about summary refs log tree commit diff
path: root/converter
diff options
context:
space:
mode:
Diffstat (limited to 'converter')
-rw-r--r--converter/Makefile4
-rw-r--r--converter/other/Makefile58
-rwxr-xr-xconverter/other/anytopnm46
-rw-r--r--converter/other/bmepsoe.c217
-rw-r--r--converter/other/bmptopnm.c114
-rw-r--r--converter/other/cameratopam/Makefile7
-rw-r--r--converter/other/cameratopam/cameratopam.c22
-rw-r--r--converter/other/dithers.h91
-rw-r--r--converter/other/fiasco/Makefile6
-rw-r--r--converter/other/fiasco/codec/Makefile6
-rw-r--r--converter/other/fiasco/input/Makefile8
-rw-r--r--converter/other/fiasco/lib/Makefile6
-rw-r--r--converter/other/fiasco/lib/misc.c32
-rw-r--r--converter/other/fiasco/output/Makefile11
-rw-r--r--converter/other/fiasco/params.c3
-rw-r--r--converter/other/fitstopnm.c889
-rw-r--r--converter/other/giftopnm.c731
-rw-r--r--converter/other/hdifftopam.c5
-rw-r--r--converter/other/infotopam.c1
-rw-r--r--converter/other/jbig/Makefile8
-rw-r--r--converter/other/jpeg2000/Makefile8
-rw-r--r--converter/other/jpeg2000/jpeg2ktopam.c1
-rw-r--r--converter/other/jpeg2000/libjasper/Makefile4
-rw-r--r--converter/other/jpeg2000/libjasper/base/Makefile4
-rw-r--r--converter/other/jpeg2000/libjasper/base/jas_stream.c71
-rw-r--r--converter/other/jpeg2000/libjasper/common.mk (renamed from converter/other/jpeg2000/libjasper/Makefile.common)7
-rw-r--r--converter/other/jpeg2000/libjasper/include/jasper/jas_types.h.orig228
-rw-r--r--converter/other/jpeg2000/libjasper/jp2/Makefile4
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/Makefile4
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_math.c128
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.c34
-rw-r--r--converter/other/jpeg2000/pamtojpeg2k.c1
-rw-r--r--converter/other/jpegdatasource.c36
-rw-r--r--converter/other/jpegdatasource.h3
-rw-r--r--converter/other/jpegtopnm.c153
-rw-r--r--converter/other/pamtodjvurle.c3
-rw-r--r--converter/other/pamtofits.c27
-rw-r--r--converter/other/pamtogif.c1977
-rw-r--r--converter/other/pamtohdiff.c1
-rw-r--r--converter/other/pamtohtmltbl.c106
-rw-r--r--converter/other/pamtompfont.c182
-rw-r--r--converter/other/pamtooctaveimg.c241
-rw-r--r--converter/other/pamtopam.c57
-rw-r--r--converter/other/pamtopfm.c1
-rw-r--r--converter/other/pamtopnm.c60
-rw-r--r--converter/other/pamtosvg/Makefile4
-rw-r--r--converter/other/pamtosvg/curve.c197
-rw-r--r--converter/other/pamtosvg/curve.h46
-rw-r--r--converter/other/pamtosvg/fit.c1870
-rw-r--r--converter/other/pamtosvg/pamtosvg.c4
-rw-r--r--converter/other/pamtosvg/pamtosvg.test6
-rw-r--r--converter/other/pamtosvg/pxl-outline.c45
-rw-r--r--converter/other/pamtosvg/spline.c10
-rw-r--r--converter/other/pamtosvg/spline.h1
-rw-r--r--converter/other/pamtosvg/vector.c282
-rw-r--r--converter/other/pamtosvg/vector.h70
-rw-r--r--converter/other/pamtotga.c3
-rw-r--r--converter/other/pamtotiff.c13
-rw-r--r--converter/other/pamtouil.c64
-rw-r--r--converter/other/pamtoxvmini.c3
-rw-r--r--converter/other/pfmtopam.c1
-rw-r--r--converter/other/pgmtopbm.c50
-rw-r--r--converter/other/pgmtoppm.c345
-rw-r--r--converter/other/pngtopam.c1281
-rw-r--r--converter/other/pngtopnm.c965
-rw-r--r--converter/other/pnmtoddif.c268
-rw-r--r--converter/other/pnmtojpeg.c726
-rw-r--r--converter/other/pnmtopalm/Makefile9
-rw-r--r--converter/other/pnmtopalm/gen_palm_colormap.c48
-rw-r--r--converter/other/pnmtopalm/palmcolor8.map458
-rw-r--r--converter/other/pnmtopalm/palmtopnm.c1
-rw-r--r--converter/other/pnmtopalm/pnmtopalm.c1
-rw-r--r--converter/other/pnmtopclxl.c5
-rw-r--r--converter/other/pnmtopng.c132
-rw-r--r--converter/other/pnmtops.c76
-rw-r--r--converter/other/pnmtorast.c139
-rw-r--r--converter/other/pnmtorle.c198
-rw-r--r--converter/other/pnmtotiffcmyk.c6
-rw-r--r--converter/other/pnmtoxwd.c4
-rw-r--r--converter/other/pstopnm.c150
-rw-r--r--converter/other/rast.h30
-rw-r--r--converter/other/rlatopam.c1
-rw-r--r--converter/other/rletopnm.c5
-rw-r--r--converter/other/svgtopam.c34
-rw-r--r--converter/other/tiff.c6
-rw-r--r--converter/other/tifftopnm.c891
-rw-r--r--converter/other/x11wd.h8
-rw-r--r--converter/other/xwdtopnm.c537
-rw-r--r--converter/pbm/Makefile8
-rw-r--r--converter/pbm/atktopbm.c2
-rw-r--r--converter/pbm/cmuwmtopbm.c181
-rw-r--r--converter/pbm/g3topbm.c147
-rw-r--r--converter/pbm/icontopbm.c12
-rw-r--r--converter/pbm/mgrtopbm.c171
-rw-r--r--converter/pbm/mrftopbm.c66
-rw-r--r--converter/pbm/pbmto4425.c2
-rw-r--r--converter/pbm/pbmtocmuwm.c167
-rw-r--r--converter/pbm/pbmtodjvurle.c166
-rw-r--r--converter/pbm/pbmtoepsi.c1
-rw-r--r--converter/pbm/pbmtoepson.c3
-rw-r--r--converter/pbm/pbmtoescp2.c1
-rw-r--r--converter/pbm/pbmtog3.c34
-rw-r--r--converter/pbm/pbmtogem.c6
-rw-r--r--converter/pbm/pbmtogo.c226
-rw-r--r--converter/pbm/pbmtoibm23xx.c1
-rw-r--r--converter/pbm/pbmtoicon.c252
-rw-r--r--converter/pbm/pbmtolj.c1
-rw-r--r--converter/pbm/pbmtoln03.c5
-rw-r--r--converter/pbm/pbmtolps.c2
-rw-r--r--converter/pbm/pbmtomgr.c209
-rw-r--r--converter/pbm/pbmtomrf.c162
-rw-r--r--converter/pbm/pbmtonokia.c686
-rw-r--r--converter/pbm/pbmtopi3.c6
-rw-r--r--converter/pbm/pbmtopk.c2
-rw-r--r--converter/pbm/pbmtoppa/Makefile4
-rw-r--r--converter/pbm/pbmtopsg3.c1
-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.c410
-rw-r--r--converter/pbm/pbmtoybm.c6
-rw-r--r--converter/pbm/pbmtozinc.c2
-rw-r--r--converter/pbm/pktopbm.c2
-rw-r--r--converter/pbm/thinkjettopbm.l1
-rw-r--r--converter/pbm/xbmtopbm.c568
-rw-r--r--converter/pgm/Makefile4
-rw-r--r--converter/pgm/asciitopgm.c2
-rw-r--r--converter/pgm/hipstopgm.c2
-rw-r--r--converter/pgm/lispmtopgm.c2
-rw-r--r--converter/pgm/pgmtofs.c6
-rw-r--r--converter/pgm/pgmtolispm.c6
-rw-r--r--converter/pgm/pgmtopgm.c4
-rw-r--r--converter/pgm/rawtopgm.c31
-rw-r--r--converter/pgm/sbigtopgm.c2
-rw-r--r--converter/ppm/411toppm.c1
-rw-r--r--converter/ppm/Makefile4
-rw-r--r--converter/ppm/eyuvtoppm.c2
-rw-r--r--converter/ppm/hpcdtoppm/Makefile6
-rw-r--r--converter/ppm/ilbmtoppm.c464
-rw-r--r--converter/ppm/mitsu.h1
-rw-r--r--converter/ppm/pcxtoppm.c1
-rw-r--r--converter/ppm/picttoppm.c1436
-rw-r--r--converter/ppm/ppmtoarbtxt.c493
-rw-r--r--converter/ppm/ppmtobmp.c512
-rw-r--r--converter/ppm/ppmtogif.c1571
-rw-r--r--converter/ppm/ppmtoilbm.c66
-rw-r--r--converter/ppm/ppmtoleaf.c259
-rw-r--r--converter/ppm/ppmtomitsu.c897
-rw-r--r--converter/ppm/ppmtomitsu.test12
-rw-r--r--converter/ppm/ppmtompeg/Makefile33
-rw-r--r--converter/ppm/ppmtompeg/bframe.c1
-rw-r--r--converter/ppm/ppmtompeg/bsearch.c1
-rw-r--r--converter/ppm/ppmtompeg/combine.c6
-rw-r--r--converter/ppm/ppmtompeg/file.c351
-rw-r--r--converter/ppm/ppmtompeg/frames.c58
-rw-r--r--converter/ppm/ppmtompeg/gethostname_win32.c404
-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/byteorder.h2
-rw-r--r--converter/ppm/ppmtompeg/headers/frame.h16
-rw-r--r--converter/ppm/ppmtompeg/headers/frames.h170
-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/param.h97
-rw-r--r--converter/ppm/ppmtompeg/headers/prototypes.h9
-rw-r--r--converter/ppm/ppmtompeg/headers/subsample.h39
-rw-r--r--converter/ppm/ppmtompeg/huff.h34
-rw-r--r--converter/ppm/ppmtompeg/iframe.c225
-rw-r--r--converter/ppm/ppmtompeg/jpeg.c28
-rw-r--r--converter/ppm/ppmtompeg/mheaders.c712
-rw-r--r--converter/ppm/ppmtompeg/mpeg.c120
-rw-r--r--converter/ppm/ppmtompeg/noparallel.c2
-rw-r--r--converter/ppm/ppmtompeg/parallel.c10
-rw-r--r--converter/ppm/ppmtompeg/param.c143
-rw-r--r--converter/ppm/ppmtompeg/pframe.c2
-rw-r--r--converter/ppm/ppmtompeg/ppmtompeg.c160
-rw-r--r--converter/ppm/ppmtompeg/psearch.c2
-rw-r--r--converter/ppm/ppmtompeg/rate.c1
-rw-r--r--converter/ppm/ppmtompeg/specifics.c45
-rw-r--r--converter/ppm/ppmtompeg/subsample.c1
-rw-r--r--converter/ppm/ppmtopcx.c1
-rw-r--r--converter/ppm/ppmtopict.c11
-rw-r--r--converter/ppm/ppmtopj.c6
-rw-r--r--converter/ppm/ppmtopjxl.c570
-rw-r--r--converter/ppm/ppmtoterm.c1
-rw-r--r--converter/ppm/ppmtowinicon.c3
-rw-r--r--converter/ppm/ppmtoxpm.c4
-rw-r--r--converter/ppm/ppmtoyuvsplit.c270
-rw-r--r--converter/ppm/rawtoppm.c418
-rw-r--r--converter/ppm/sldtoppm.c726
-rw-r--r--converter/ppm/spctoppm.c7
-rw-r--r--converter/ppm/tgatoppm.c4
-rw-r--r--converter/ppm/winicontoppm.c5
-rw-r--r--converter/ppm/ximtoppm.c4
-rw-r--r--converter/ppm/xpmtoppm.c15
-rw-r--r--converter/ppm/xvminitoppm.c10
-rw-r--r--converter/ppm/yuvsplittoppm.c2
199 files changed, 17894 insertions, 11084 deletions
diff --git a/converter/Makefile b/converter/Makefile
index 02cab3be..8c488ee2 100644
--- a/converter/Makefile
+++ b/converter/Makefile
@@ -5,7 +5,7 @@ endif
 SUBDIR = converter
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
 SUBDIRS = pbm pgm ppm other
 
@@ -14,4 +14,4 @@ all: $(SUBDIRS:%=%/all)
 SCRIPTS = 
 BINARIES =
 
-include $(SRCDIR)/Makefile.common
+include $(SRCDIR)/common.mk
diff --git a/converter/other/Makefile b/converter/other/Makefile
index a83eeb21..df084ceb 100644
--- a/converter/other/Makefile
+++ b/converter/other/Makefile
@@ -5,7 +5,7 @@ endif
 SUBDIR = converter/other
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
 ifeq ($(shell xml2-config --version),)
   XML2_LIBS=NONE
@@ -20,41 +20,40 @@ ifneq ($(BUILD_FIASCO), N)
   SUBDIRS += fiasco
 endif
 
-INCLUDES = -I$(SRCDIR)/util 
 ifneq ($(TIFFLIB),NONE)
   ifneq ($(TIFFHDR_DIR)x,x)
-    INCLUDES += -I$(TIFFHDR_DIR)
+    EXTERN_INCLUDES += -I$(TIFFHDR_DIR)
   endif
 endif
 
-ifeq ($(shell libpng-config --version),)
+ifeq ($(shell libpng$(PNGVER)-config --version),)
   ifneq ($(PNGLIB),NONE)
     HAVE_PNGLIB = Y
     ifneq ($(PNGHDR_DIR)x,x)
-      INCLUDES += -I$(PNGHDR_DIR)
+      EXTERN_INCLUDES += -I$(PNGHDR_DIR)
     endif
     ifneq ($(ZHDR_DIR)x,x)
-      INCLUDES += -I$(ZHDR_DIR)
+      EXTERN_INCLUDES += -I$(ZHDR_DIR)
     endif
   endif
 else
   HAVE_PNGLIB = Y
-  INCLUDES += $(shell libpng-config --cflags)
+  EXTERN_INCLUDES += $(shell libpng$(PNGVER)-config --cflags)
 endif
 
 ifneq ($(JPEGLIB),NONE)
   ifneq ($(JPEGHDR_DIR)x,x)
-    INCLUDES += -I$(JPEGHDR_DIR)
+    EXTERN_INCLUDES += -I$(JPEGHDR_DIR)
   endif
 endif
 ifneq ($(URTLIB),NONE)
   ifneq ($(URTHDR_DIR)x,x)
-    INCLUDES += -I$(URTHDR_DIR)
+    EXTERN_INCLUDES += -I$(URTHDR_DIR)
   endif
 endif
 ifneq ($(XML2_LIBS),NONE)
   ifneq ($(XML2_CFLAGS),NONE)
-    INCLUDES += $(XML2_CFLAGS)
+    EXTERN_INCLUDES += $(XML2_CFLAGS)
   endif
 endif
 
@@ -80,19 +79,24 @@ endif
 
 PORTBINARIES =  bmptopnm fitstopnm \
 		gemtopnm giftopnm hdifftopam infotopam \
-		pamtodjvurle pamtofits \
-		pamtohdiff pamtohtmltbl pamtopfm pamtopnm pamtouil \
+		pamtodjvurle pamtofits pamtogif \
+		pamtohdiff pamtohtmltbl pamtompfont pamtooctaveimg \
+		pamtopam pamtopfm pamtopnm pamtouil \
 		pamtoxvmini \
 		pbmtopgm pfmtopam \
 	        pgmtopbm pgmtoppm ppmtopgm pnmtoddif \
 		pnmtopclxl \
-		pnmtosgi pnmtosir pamtotga pnmtoxwd pstopnm \
+		pnmtosgi pnmtosir pamtotga pnmtoxwd \
 		rlatopam sgitopnm sirtopnm xwdtopnm zeisstopnm
 
+ifneq ($(DONT_HAVE_PROCESS_MGMT),Y)
+  PORTBINARIES += pstopnm
+endif
+
 BINARIES = $(PORTBINARIES) pnmtorast rasttopnm
 
 ifeq ($(HAVE_PNGLIB),Y)
-  BINARIES += pnmtopng pngtopnm pamrgbatopng
+  BINARIES += pnmtopng pngtopnm pngtopam pamrgbatopng
 endif
 ifneq ($(JPEGLIB),NONE)
   BINARIES += jpegtopnm pnmtojpeg
@@ -133,7 +137,7 @@ SCRIPTS = anytopnm pnmtoplainpnm
 .PHONY: all
 all:	$(BINARIES) $(SUBDIRS:%=%/all)
 
-include $(SRCDIR)/Makefile.common
+include $(SRCDIR)/common.mk
 
 ifeq ($(NEED_RUNTIME_PATH),Y)
   LIBOPTR = -runtime
@@ -148,13 +152,13 @@ tifftopnm pamtotiff pnmtotiffcmyk: %: %.o tiff.o $(NETPBMLIB) $(LIBOPT)
 	$(LD) -o $@ $@.o tiff.o \
 	  $(LIBOPTS_TIFF) $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
 
-ifeq ($(shell libpng-config --version),)
+ifeq ($(shell libpng$(PNGVER)-config --version),)
   PNGLIB_LIBOPTS = $(shell $(LIBOPT) $(LIBOPTR) $(PNGLIB) $(ZLIB))
 else
-  PNGLIB_LIBOPTS = $(shell libpng-config --ldflags)
+  PNGLIB_LIBOPTS = $(shell libpng$(PNGVER)-config --ldflags)
 endif
 
-pngtopnm: %: %.o $(NETPBMLIB) $(LIBOPT)
+pngtopnm pngtopam: %: %.o $(NETPBMLIB) $(LIBOPT)
 	$(LD) -o $@ $@.o \
 	  $(shell $(LIBOPT) $(NETPBMLIB)) \
 	  $(PNGLIB_LIBOPTS) $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
@@ -218,27 +222,29 @@ install.bin.local: $(PKGDIR)/bin
 	$(SYMLINK) pnmtoplainpnm pnmnoraw
 # backward compatibility: program used to be gemtopbm
 	cd $(PKGDIR)/bin ; \
-	$(SYMLINK) gemtopnm$(EXE) gemtopbm
+	$(SYMLINK) gemtopnm$(EXE) gemtopbm$(EXE)
 # In October 2001, pnmtojpeg replaced ppmtojpeg
+ifneq ($(JPEGLIB),NONE)
 	cd $(PKGDIR)/bin ; \
-	$(SYMLINK) pnmtojpeg$(EXE) ppmtojpeg
+	$(SYMLINK) pnmtojpeg$(EXE) ppmtojpeg$(EXE)
+endif
 # In March 2002, bmptopnm replaced bmptoppm
 	cd $(PKGDIR)/bin ; \
-	$(SYMLINK) bmptopnm$(EXE) bmptoppm
+	$(SYMLINK) bmptopnm$(EXE) bmptoppm$(EXE)
 # In May 2002, pamtouil replaced ppmtouil
 	cd $(PKGDIR)/bin ; \
-	$(SYMLINK) pamtouil$(EXE) ppmtouil
+	$(SYMLINK) pamtouil$(EXE) ppmtouil$(EXE)
 # In July 2002, pamtotga replaced ppmtotga
 	cd $(PKGDIR)/bin ; \
 	$(SYMLINK) pamtotga$(EXE) ppmtotga$(EXE)
 # In March 2005, we realized that pamtopnm obviates pnmtopnm
 	cd $(PKGDIR)/bin ; \
-	$(SYMLINK) pamtopnm$(EXE) pnmtopnm
+	$(SYMLINK) pamtopnm$(EXE) pnmtopnm$(EXE)
 # In October 2005, pamtofits replaced pnmtofits
 	cd $(PKGDIR)/bin ; \
-	$(SYMLINK) pamtofits$(EXE) pnmtofits
+	$(SYMLINK) pamtofits$(EXE) pnmtofits$(EXE)
 ifneq ($(TIFF_PREREQ_MISSING),Y)
 # In October 2005, pamtotiff replaced pnmtotiff
 	cd $(PKGDIR)/bin ; \
-	$(SYMLINK) pamtotiff$(EXE) pnmtotiff
-endif
\ No newline at end of file
+	$(SYMLINK) pamtotiff$(EXE) pnmtotiff$(EXE)
+endif
diff --git a/converter/other/anytopnm b/converter/other/anytopnm
index b2873772..06f48b4f 100755
--- a/converter/other/anytopnm
+++ b/converter/other/anytopnm
@@ -47,18 +47,39 @@ putInputIntoTempfile() {
 
 
 setMimeType() {
+#------------------------------------------------------------------------------
+# Set variable 'mimeType' to the mime type string (e.g. "application/binary")
+#
+# If we can't tell, set it to "unknown".
+#------------------------------------------------------------------------------
     # $1 is the file name
 
-    # Christos Zoulas's current 'file' (see Freshmeat) has the --mime option.
+    # Old versions of 'file' cannot tell us the mime type; they lack any option
+    # to do so.
+    #
+    # Newer ones have a --mime option for that.
+    #
+    # Still newer ones (ca 2008) have a --mime option, but it does something
+    # different - it prints the mime type plus the mime encoding.  And they
+    # have --mime-type to print just the mime type.
 
-    file --mime /dev/null >/dev/null 2>/dev/null
+    file --mime-type /dev/null >/dev/null 2>/dev/null
     if [ $? -eq 0 ]; then
-        # Now that we know the --mime option exists, use it.
-        mimeType=`file --mime "$1" | cut -d: -f2- | cut -c2-`
+        # Now that we know the --mime-type option exists, use it.
+        mimeType=`file --mime-type "$1" | cut -d: -f2- | cut -c2-`
     else
-        # file --mime failed; we don't know why, but we assume it's because it
-        # is a traditional 'file' program that doesn't have a --mime option.
-    mimeType="unknown"
+        # file --mime-type failed; we don't know why, but we assume it's
+        # because it is an older 'file' program that doesn't have a --mime-type
+        # option.
+        file --mime /dev/null >/dev/null 2>/dev/null
+        if [ $? -eq 0 ]; then
+            # Now that we know the --mime option exists, use it.
+            mimeType=`file --mime "$1" | cut -d: -f2- | cut -c2-`
+        else
+            # file --mime failed; we don't know why, but we assume it's because
+            # it is an older 'file' program that doesn't have a --mime option.
+            mimeType="unknown"
+        fi
     fi
 }
 
@@ -109,7 +130,7 @@ computeTypeFromTypeDescription () {
 
     case "$1" in
     
-        *PBM* | *PGM* | *PPM* )
+        *PBM* | *PGM* | *PPM* | *Netpbm*PAM*)
             filetype=pnm
             ;;
     
@@ -149,6 +170,10 @@ computeTypeFromTypeDescription () {
             filetype=gzip
             ;;
     
+        *XWD*X*Window*Dump* ) 
+            filetype=xwd
+            ;;
+
         *compress* )
             filetype=compress
             ;;
@@ -507,9 +532,8 @@ else
 fi
 
 tempdir="${TMPDIR-/tmp}/anytopnm.$$"
-mkdir $tempdir || { echo "Could not create temporary file. Exiting."; exit 1;}
-chmod 700 $tempdir
-
+mkdir -m 0700 $tempdir || \
+  { echo "Could not create temporary file. Exiting."; exit 1;}
 trap 'rm -rf $tempdir' 0
 
 # Take out all spaces
diff --git a/converter/other/bmepsoe.c b/converter/other/bmepsoe.c
index cdb52779..02bf39aa 100644
--- a/converter/other/bmepsoe.c
+++ b/converter/other/bmepsoe.c
@@ -209,76 +209,85 @@ static void after_flate_add(Output_Encoder *o, int b)
   
 }
 
-static void do_flate_flush(Output_Encoder *o, int final)
-{
-  Bytef *iptr, *optr, *xptr;
-  uLong  is, os, xs;
-  int err, must_continue;
-  
-  iptr = o->fl_i_buffer; optr = o->fl_o_buffer;
-  is = o->fl_i_size; os = o->fl_o_size;
-  
-  if(iptr && optr && is && os) {
-    is = o->fl_i_used;
-    if(is) {
-      (o->flate_stream).next_in = iptr;
-      (o->flate_stream).avail_in = is;
-      if(final) { 
-    must_continue = 1;
-    while(must_continue) {
-      (o->flate_stream).next_out = optr;
-      (o->flate_stream).avail_out = os;
-      must_continue = 0;
-      err = deflate(&(o->flate_stream), Z_FINISH);
-      switch(err) {
-        case Z_STREAM_END: { 
-              xptr = optr;
+
+
+static void
+do_flate_flush(Output_Encoder * const oP,
+               int              const final) {
+
+    Bytef *iptr, *optr, *xptr;
+    unsigned long is;
+    unsigned long os;
+    unsigned long xs;
+    int err;
+    int mustContinue;
+  
+    iptr = oP->fl_i_buffer; optr = oP->fl_o_buffer;
+    is = oP->fl_i_size; os = oP->fl_o_size;
+  
+    if (iptr && optr && is && os) {
+        is = oP->fl_i_used;
+        if (is || final) {
+            oP->flate_stream.next_in = iptr;
+            oP->flate_stream.avail_in = is;
+            if (final) { 
+                mustContinue = 1;
+                while (mustContinue) {
+                    oP->flate_stream.next_out = optr;
+                    oP->flate_stream.avail_out = os;
+                    mustContinue = 0;
+                    err = deflate(&oP->flate_stream, Z_FINISH);
+                    switch (err) {
+                    case Z_STREAM_END: { 
+                        xptr = optr;
           
-          xs = os - ((o->flate_stream).avail_out);
-          while(xs--) {
-        after_flate_add(o, (*(xptr++)));
-          }
-        } break;
-        case Z_OK : {
-          must_continue = 1;
-              xptr = optr;
+                        xs = os - (oP->flate_stream.avail_out);
+                        while (xs--) {
+                            after_flate_add(oP, *(xptr++));
+                        }
+                    } break;
+                    case Z_OK : {
+                        mustContinue = 1;
+                        xptr = optr;
           
-          xs = os - ((o->flate_stream).avail_out);
-          while(xs--) {
-        after_flate_add(o, (*(xptr++)));
-          }
-        } break;
-        default : { 
-        } break;
-      }
-    }
-      } else { 
-    must_continue = 1;
-    while(must_continue) {
-      must_continue = 0;
-      (o->flate_stream).avail_out = os; (o->flate_stream).next_out = optr;
-      err = deflate(&(o->flate_stream), 0);
-      switch(err) {
-        case Z_OK: {
-          if((o->flate_stream).avail_in) {
-        must_continue = 1;
-          }
+                        xs = os - (oP->flate_stream.avail_out);
+                        while (xs--) {
+                            after_flate_add(oP, *(xptr++));
+                        }
+                    } break;
+                    default : { 
+                    } break;
+                    }
+                }
+            } else { 
+                mustContinue = 1;
+                while (mustContinue) {
+                    mustContinue = 0;
+                    oP->flate_stream.avail_out = os;
+                    oP->flate_stream.next_out = optr;
+                    err = deflate(&oP->flate_stream, 0);
+                    switch (err) {
+                    case Z_OK: {
+                        if (oP->flate_stream.avail_in) {
+                            mustContinue = 1;
+                        }
           
-          xptr = optr; xs = os - ((o->flate_stream).avail_out);
-          while(xs--) {
-        after_flate_add(o, (*(xptr++)));
-          }
-        } break;
-        default : { 
-        } break;
-      }
-    }
-      }
+                        xptr = optr; xs = os - (oP->flate_stream.avail_out);
+                        while (xs--) {
+                            after_flate_add(oP, *(xptr++));
+                        }
+                    } break;
+                    default : { 
+                    } break;
+                    }
+                }
+            }
+        }
     }
-  }
-  
 }
 
+
+
 static void flate_add(Output_Encoder *o, int b)
 {
   Byte bt;
@@ -457,17 +466,20 @@ static void rl_flush(Output_Encoder *o)
   
 }
 
-static void internal_byte_add(Output_Encoder *o, int b)
-{
-  
-  if((o->mode) & OE_RL) {
-    rl_add(o,b);
-  } else {
-    after_rl_add(o,b);
-  }
+
+
+static void
+internal_byte_add(Output_Encoder * const oP,
+                  int              const b) {
   
+    if (oP->mode & OE_RL)
+        rl_add(oP, b);
+    else
+        after_rl_add(oP, b);
 }
 
+
+
 static void internal_byte_flush(Output_Encoder *o)
 {
   
@@ -479,19 +491,23 @@ static void internal_byte_flush(Output_Encoder *o)
   
 }
 
-void oe_bit_add(Output_Encoder *o, int b)
-{
-  
-  o->bit_value = 2 * o->bit_value + (b ? 1 : 0);
-  o->bit_consumed = o->bit_consumed + 1;
-  if(o->bit_consumed >= 8) {
-    o->bit_consumed = 0;
-    internal_byte_add(o, (o->bit_value));
-    o->bit_value = 0;
-  }
+
+
+void
+oe_bit_add(Output_Encoder * const oP,
+           int              const b) {
   
+    oP->bit_value = 2 * oP->bit_value + (b ? 1 : 0);
+    oP->bit_consumed = oP->bit_consumed + 1;
+    if (oP->bit_consumed >= 8) {
+        oP->bit_consumed = 0;
+        internal_byte_add(oP, oP->bit_value);
+        oP->bit_value = 0;
+    }
 }
 
+
+
 void oe_bit_flush(Output_Encoder *o)
 {
   
@@ -511,26 +527,31 @@ void oe_bit_flush(Output_Encoder *o)
   
 }
 
-void oe_byte_add(Output_Encoder *o, int b)
-{
+
+
+void
+oe_byte_add(Output_Encoder * const oP,
+            int              const b) {
   
-  if(o->bit_consumed) {
-    int testval,i;
-    testval = 128;
-    for(i = 0; i < 8; i++) {
-      if(b & testval) {
-    oe_bit_add(o,1);
-      } else {
-    oe_bit_add(o,0);
-      }
-      testval = testval / 2;
+    if (oP->bit_consumed) {
+        int testval;
+        int i;
+        testval = 128;
+        for (i = 0; i < 8; ++i) {
+            if (b & testval) {
+                oe_bit_add(oP, 1);
+            } else {
+                oe_bit_add(oP, 0);
+            }
+            testval = testval / 2;
+        }
+    } else {
+        internal_byte_add(oP, b);
     }
-  } else {
-    internal_byte_add(o,b);
-  }
-  
 }
 
+
+
 void oe_byte_flush(Output_Encoder *o)
 {
   
diff --git a/converter/other/bmptopnm.c b/converter/other/bmptopnm.c
index e1bd1403..9a405d70 100644
--- a/converter/other/bmptopnm.c
+++ b/converter/other/bmptopnm.c
@@ -17,11 +17,17 @@
  in supporting documentation.  This software is provided "as is"
  without express or implied warranty.
 
+ Note: From mid-2003 to mid-2007, this program would crash on any 16
+ bit BMP without transparency and no one reported it.  Before that, it
+ refused to even try to read a 16 bit BMP.  I conclude that essentially
+ nobody is using 16 bit BMP.
+
 *****************************************************************************/
 #include <string.h>
 #include <limits.h>
 #include <assert.h>
 
+#include "pm_c_util.h"
 #include "pnm.h"
 #include "shhopt.h"
 #include "nstring.h"
@@ -42,6 +48,10 @@ struct bitPosition {
 
        Example: if 16 bits are laid out as XRRRRRGGGGGBBBBB then the shift
        count for the R component is 10 and the mask is 0000000000011111.
+
+       A 'mask' of zero denotes absence of any bits; e.g. in the example
+       above, the mask for the transparency component is zero because there
+       is no transparency component .  'shift' is arbitrary in that case.
     */
     unsigned int shift;
         /* How many bits right you have to shift the value to get the subject
@@ -306,6 +316,36 @@ readOs2InfoHeader(FILE *                 const ifP,
 
 
 static void
+validateCompression(unsigned long const compression,
+                    enum rowOrder const rowOrder,
+                    unsigned int  const cBitCount) {
+    
+    if (compression != COMP_RGB && compression != COMP_BITFIELDS &&
+        compression != COMP_RLE4 && compression != COMP_RLE8 ) 
+        pm_error("Input has unknown encoding.  "
+                 "Compression type code = %ld.  The only ones we know "
+                 "are RGB (%u), BITFIELDS (%u), "
+                 "RLE4 (%u), and RLE8 (%u)",
+                 compression, COMP_RGB, COMP_BITFIELDS,
+                 COMP_RLE4, COMP_RLE8);
+                     
+    if ((compression == COMP_RLE4 || compression == COMP_RLE8) &&
+        rowOrder == TOPDOWN )                        
+        pm_error("Invalid BMP header.  Claims image is top-down and also "
+                 "compressed, which is an impossible combination.");
+
+    if ( (compression == COMP_RLE4 && cBitCount !=4) ||
+         (compression == COMP_RLE8 && cBitCount !=8) ) 
+        pm_error("Invalid BMP header.  " 
+                 "Compression type (%s) disagrees with "
+                 "number of bits per pixel (%u).",
+                 compression == COMP_RLE4 ? "RLE4" : "RLE8",
+                 cBitCount);
+}
+
+
+
+static void
 readWindowsBasic40ByteInfoHeader(FILE *                 const ifP,
                                  struct bmpInfoHeader * const headerP) {
 /*----------------------------------------------------------------------------
@@ -340,22 +380,9 @@ readWindowsBasic40ByteInfoHeader(FILE *                 const ifP,
         unsigned long int const compression = GetLong(ifP);
 
         headerP->bitFields = (compression == COMP_BITFIELDS);
-    
-        if (compression != COMP_RGB && compression != COMP_BITFIELDS &&
-            compression != COMP_RLE4 && compression != COMP_RLE8 ) 
-            pm_error("Input is compressed.  Unsupported encoding method.\n"
-                     "Compression type code = %ld", compression);
-                     
-        if ( (compression == COMP_RLE4 || compression == COMP_RLE8) &&
-              headerP->rowOrder == TOPDOWN )                        
-            pm_error("Invalid BMP header.  Top-down images cannot be compressed.");
 
-        if ( (compression == COMP_RLE4 && headerP->cBitCount !=4) ||
-             (compression == COMP_RLE8 && headerP->cBitCount !=8) )                        
-            pm_error("Invalid BMP header.\n" 
-                     "Compression type (%s) disagrees with number of bits per pixel (%u).",
-                      compression == COMP_RLE4 ? "RLE4" : "RLE8",
-                      headerP->cBitCount);
+        validateCompression(compression, headerP->rowOrder,
+                            headerP->cBitCount);
 
         headerP->compression = compression;             
     }
@@ -399,7 +426,7 @@ lsbZeroCount(unsigned int const mask)
    Use GCC built-in when available.
 -----------------------------------------------------------------------------*/
 
-#if ( defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 304) )
+#if HAVE_GCC_BITCOUNT 
 {
       return ( mask==0 ? sizeof(mask)*8 : __builtin_ctz(mask) );
 }
@@ -463,6 +490,10 @@ defaultPixelformat(unsigned int const bitCount) {
 
     switch (bitCount) {
     case 16:
+        /* This layout is sometimes called "RGB555".  A document from
+           Microsoft says this is the default (when the "compression"
+           field of the header says COMP_BITFIELDS).
+        */
         retval.conventionalBgr = FALSE;
         retval.red.shift = 10;
         retval.grn.shift = 5;
@@ -500,6 +531,11 @@ readV4InfoHeaderExtension(FILE *                 const ifP,
                           struct bmpInfoHeader * const headerP) {
 
     if (headerP->bitFields) {
+        /* A document from Microsoft says on Windows 95 there is no
+           transparency plane and (red, green, blue) must be either
+           (5,5,5) or (5,6,5) for 16 bit and (8,8,8) for 32 bit.
+           It calls these RGB555, RGB565, RGB888.
+        */
         headerP->pixelformat.red = bitPositionFromMask(GetLong(ifP));
         headerP->pixelformat.grn = bitPositionFromMask(GetLong(ifP));
         headerP->pixelformat.blu = bitPositionFromMask(GetLong(ifP));
@@ -655,16 +691,16 @@ extractBitFields(unsigned int       const rasterval,
         (rasterval >> pixelformat.blu.shift) & pixelformat.blu.mask;
     unsigned int const abits = 
         (rasterval >> pixelformat.trn.shift) & pixelformat.trn.mask;
-    
-    *rP = pixelformat.red.mask ?
-              (unsigned int) rbits * maxval / pixelformat.red.mask : 0;
-    *gP = pixelformat.grn.mask ?
-              (unsigned int) gbits * maxval / pixelformat.grn.mask : 0;
-    *bP = pixelformat.blu.mask ?
-              (unsigned int) bbits * maxval / pixelformat.blu.mask : 0;
-    *aP = pixelformat.trn.mask ?
-              (unsigned int) abits * maxval / pixelformat.trn.mask : 0;
-}
+
+    *rP = pixelformat.red.mask > 0 ?
+        (unsigned int) rbits * maxval / pixelformat.red.mask : 0;
+    *gP = pixelformat.grn.mask > 0 ?
+        (unsigned int) gbits * maxval / pixelformat.grn.mask : 0;
+    *bP = pixelformat.blu.mask > 0 ?
+        (unsigned int) bbits * maxval / pixelformat.blu.mask : 0;
+    *aP = pixelformat.trn.mask > 0 ?
+        (unsigned int) abits * maxval / pixelformat.trn.mask : 0;
+}        
 
 
 
@@ -1220,7 +1256,7 @@ readColorMap(FILE *               const ifP,
                    bytesRead,
                    BMPlencolormap(BMPheader.class, BMPheader.cBitCount, 
                                   BMPheader.cmapsize));
-}
+    }
 }
 
 
@@ -1259,6 +1295,25 @@ warnIfBadFileSize(struct bmpInfoHeader const BMPheader,
 
 
 
+static bool
+isValidBmpBpp(unsigned int const cBitCount) {
+
+    switch (cBitCount) {
+    case 1:
+    case 2:
+    case 4:
+    case 8:
+    case 16:
+    case 24:
+    case 32:
+        return true;
+    default:
+        return false;
+    }
+}
+
+
+
 static void
 readBmp(FILE *               const ifP, 
         unsigned char ***    const BMPrasterP, 
@@ -1316,6 +1371,11 @@ readBmp(FILE *               const ifP,
     if (fgetc(ifP) != EOF)
         pm_message("warning: some image data remains unread.");
     
+    if (!isValidBmpBpp(BMPheader.cBitCount))
+        pm_error("Invalid BMP image: 'cBitCount' field of header "
+                 "(number of bits for each pixel in raster) is %u",
+                 BMPheader.cBitCount);
+
     *colsP        = BMPheader.cols;
     *rowsP        = BMPheader.rows;
     *cBitCountP   = BMPheader.cBitCount;
diff --git a/converter/other/cameratopam/Makefile b/converter/other/cameratopam/Makefile
index b6778c67..20a95aa2 100644
--- a/converter/other/cameratopam/Makefile
+++ b/converter/other/cameratopam/Makefile
@@ -5,14 +5,15 @@ endif
 SUBDIR = converter/other/cameratopam
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
+EXTERN_INCLUDES =
 ifneq ($(JPEGLIB),NONE)
   ifneq ($(JPEGHDR_DIR)x,x)
-    INCLUDES += -I$(JPEGHDR_DIR)
+    EXTERN_INCLUDES += -I$(JPEGHDR_DIR)
     CFLAGS += -DHAVE_JPEG
   endif
 endif
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
 
 .PHONY: all
@@ -27,7 +28,7 @@ BINARIES = cameratopam
 MERGEBINARIES = 
 SCRIPTS = 
 
-include $(SRCDIR)/Makefile.common
+include $(SRCDIR)/common.mk
 
 cameratopam: $(OBJECTS) $(NETPBMLIB) $(LIBOPT)
 	$(LD) -o $@ \
diff --git a/converter/other/cameratopam/cameratopam.c b/converter/other/cameratopam/cameratopam.c
index 92773c91..b2d6da9b 100644
--- a/converter/other/cameratopam/cameratopam.c
+++ b/converter/other/cameratopam/cameratopam.c
@@ -24,18 +24,13 @@
 #include <string.h>
 
 #ifdef __CYGWIN__
-#include <io.h>
+  #include <io.h>
 #endif
-#ifdef WIN32
-  #include <winsock2.h>
-  #pragma comment(lib, "ws2_32.lib")
-  #define strcasecmp stricmp
-  typedef __int64 INT64;
-  static bool const have64BitArithmetic = true;
-#else
+#if !defined(WIN32) || defined(__CYGWIN__)
   #include <unistd.h>
 #endif
 
+#include "pm_c_util.h"
 #include "mallocvar.h"
 #include "shhopt.h"
 #include "pam.h"
@@ -48,17 +43,6 @@
 #include "foveon.h"
 #include "dng.h"
 
-#if HAVE_INT64
-   typedef int64_t INT64;
-   static bool const have64BitArithmetic = true;
-#else
-   /* We define INT64 to something that lets the code compile, but we
-      should not execute any INT64 code, because it will get the wrong
-      result.  */
-   typedef int INT64;
-   static bool const have64BitArithmetic = false;
-#endif
-
 /*
    All global variables are defined here, and all functions that
    access them are prefixed with "CLASS".  Note that a thread-safe
diff --git a/converter/other/dithers.h b/converter/other/dithers.h
deleted file mode 100644
index 1ced833d..00000000
--- a/converter/other/dithers.h
+++ /dev/null
@@ -1,91 +0,0 @@
-#ifndef DITHERS_H_INCLUDED
-#define DITHERS_H_INCLUDED
-
-/*
-** dithers.h
-**
-** Here are some dithering matrices.  They are all taken from "Digital
-** Halftoning" by Robert Ulichney, MIT Press, ISBN 0-262-21009-6.
-*/
-
-
-#if 0
-/*
-** Order-6 ordered dithering matrix.  Note that smaller ordered dithers
-** have no advantage over larger ones, so use dither8 instead.
-*/
-static int dither6[8][8] = {
-  {  1, 59, 15, 55,  2, 56, 12, 52 },
-  { 33, 17, 47, 31, 34, 18, 44, 28 },
-  {  9, 49,  5, 63, 10, 50,  6, 60 },
-  { 41, 25, 37, 21, 42, 26, 38, 22 },
-  {  3, 57, 13, 53,  0, 58, 14, 54 },
-  { 35, 19, 45, 29, 32, 16, 46, 30 },
-  { 11, 51,  7, 61,  8, 48,  4, 62 },
-  { 43, 27, 39, 23, 40, 24, 36, 20 }
-  };
-#endif
-
-/* Order-8 ordered dithering matrix. */
-static int dither8[16][16] = {
-  {   1,235, 59,219, 15,231, 55,215,  2,232, 56,216, 12,228, 52,212},
-  { 129, 65,187,123,143, 79,183,119,130, 66,184,120,140, 76,180,116},
-  {  33,193, 17,251, 47,207, 31,247, 34,194, 18,248, 44,204, 28,244},
-  { 161, 97,145, 81,175,111,159, 95,162, 98,146, 82,172,108,156, 92},
-  {   9,225, 49,209,  5,239, 63,223, 10,226, 50,210,  6,236, 60,220},
-  { 137, 73,177,113,133, 69,191,127,138, 74,178,114,134, 70,188,124},
-  {  41,201, 25,241, 37,197, 21,255, 42,202, 26,242, 38,198, 22,252},
-  { 169,105,153, 89,165,101,149, 85,170,106,154, 90,166,102,150, 86},
-  {   3,233, 57,217, 13,229, 53,213,  0,234, 58,218, 14,230, 54,214},
-  { 131, 67,185,121,141, 77,181,117,128, 64,186,122,142, 78,182,118},
-  {  35,195, 19,249, 45,205, 29,245, 32,192, 16,250, 46,206, 30,246},
-  { 163, 99,147, 83,173,109,157, 93,160, 96,144, 80,174,110,158, 94},
-  {  11,227, 51,211,  7,237, 61,221,  8,224, 48,208,  4,238, 62,222},
-  { 139, 75,179,115,135, 71,189,125,136, 72,176,112,132, 68,190,126},
-  {  43,203, 27,243, 39,199, 23,253, 40,200, 24,240, 36,196, 20,254},
-  { 171,107,155, 91,167,103,151, 87,168,104,152, 88,164,100,148, 84} 
-};
-
-/* Order-3 clustered dithering matrix. */
-static int cluster3[6][6] = {
-  {  9,11,10, 8, 6, 7},
-  { 12,17,16, 5, 0, 1},
-  { 13,14,15, 4, 3, 2},
-  {  8, 6, 7, 9,11,10},
-  {  5, 0, 1,12,17,16},
-  {  4, 3, 2,13,14,15}
-};
-
-/* Order-4 clustered dithering matrix. */
-static int cluster4[8][8] = {
-  { 18,20,19,16,13,11,12,15},
-  { 27,28,29,22, 4, 3, 2, 9},
-  { 26,31,30,21, 5, 0, 1,10},
-  { 23,25,24,17, 8, 6, 7,14},
-  { 13,11,12,15,18,20,19,16},
-  {  4, 3, 2, 9,27,28,29,22},
-  {  5, 0, 1,10,26,31,30,21},
-  {  8, 6, 7,14,23,25,24,17}
-};
-
-/* Order-8 clustered dithering matrix. */
-static int cluster8[16][16] = {
-   { 64, 69, 77, 87, 86, 76, 68, 67, 63, 58, 50, 40, 41, 51, 59, 60},
-   { 70, 94,100,109,108, 99, 93, 75, 57, 33, 27, 18, 19, 28, 34, 52},
-   { 78,101,114,116,115,112, 98, 83, 49, 26, 13, 11, 12, 15, 29, 44},
-   { 88,110,123,124,125,118,107, 85, 39, 17,  4,  3,  2,  9, 20, 42},
-   { 89,111,122,127,126,117,106, 84, 38, 16,  5,  0,  1, 10, 21, 43},
-   { 79,102,119,121,120,113, 97, 82, 48, 25,  8,  6,  7, 14, 30, 45},
-   { 71, 95,103,104,105, 96, 92, 74, 56, 32, 24, 23, 22, 31, 35, 53},
-   { 65, 72, 80, 90, 91, 81, 73, 66, 62, 55, 47, 37, 36, 46, 54, 61},
-   { 63, 58, 50, 40, 41, 51, 59, 60, 64, 69, 77, 87, 86, 76, 68, 67},
-   { 57, 33, 27, 18, 19, 28, 34, 52, 70, 94,100,109,108, 99, 93, 75},
-   { 49, 26, 13, 11, 12, 15, 29, 44, 78,101,114,116,115,112, 98, 83},
-   { 39, 17,  4,  3,  2,  9, 20, 42, 88,110,123,124,125,118,107, 85},
-   { 38, 16,  5,  0,  1, 10, 21, 43, 89,111,122,127,126,117,106, 84},
-   { 48, 25,  8,  6,  7, 14, 30, 45, 79,102,119,121,120,113, 97, 82},
-   { 56, 32, 24, 23, 22, 31, 35, 53, 71, 95,103,104,105, 96, 92, 74},
-   { 62, 55, 47, 37, 36, 46, 54, 61, 65, 72, 80, 90, 91, 81, 73, 66}
-};
-
-#endif
diff --git a/converter/other/fiasco/Makefile b/converter/other/fiasco/Makefile
index 9f7310bd..16221d77 100644
--- a/converter/other/fiasco/Makefile
+++ b/converter/other/fiasco/Makefile
@@ -5,9 +5,9 @@ endif
 SUBDIR = converter/other/fiasco
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
-INCLUDES = \
+COMP_INCLUDES = \
 	-I$(SRCDIR)/$(SUBDIR)/codec -I$(SRCDIR)/$(SUBDIR)/input \
 	-I$(SRCDIR)/$(SUBDIR)/output -I$(SRCDIR)/$(SUBDIR)/lib \
 
@@ -32,7 +32,7 @@ MERGE_OBJECTS = $(BINARIES:%=%.o2) $(COMMON_OBJECTS)  $(FIASCOLIBS)
 
 SUBDIRS = codec input output lib
 
-include $(SRCDIR)/Makefile.common
+include $(SRCDIR)/common.mk
 
 $(BINARIES):%:%.o $(COMMON_OBJECTS) $(FIASCOLIBS) $(NETPBMLIB) \
    $(LIBOPT)
diff --git a/converter/other/fiasco/codec/Makefile b/converter/other/fiasco/codec/Makefile
index 9a9d502a..e3b2a112 100644
--- a/converter/other/fiasco/codec/Makefile
+++ b/converter/other/fiasco/codec/Makefile
@@ -6,9 +6,9 @@ FIASCOSUBDIR = converter/other/fiasco
 SUBDIR = $(FIASCOSUBDIR)/codec
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
-INCLUDES = -I$(SRCDIR)/$(FIASCOSUBDIR) -I$(SRCDIR)/$(FIASCOSUBDIR)/lib \
+COMP_INCLUDES = -I$(SRCDIR)/$(FIASCOSUBDIR) -I$(SRCDIR)/$(FIASCOSUBDIR)/lib \
 	 -I$(SRCDIR)/$(FIASCOSUBDIR)/input -I$(SRCDIR)/$(FIASCOSUBDIR)/output 
 
 OBJECTS =  approx.o bintree.o coder.o coeff.o \
@@ -19,7 +19,7 @@ MERGE_OBJECTS = $(OBJECTS)
 
 all: libfiasco_codec.a
 
-include $(SRCDIR)/Makefile.common
+include $(SRCDIR)/common.mk
 
 libfiasco_codec.a: $(OBJECTS)
 	$(AR) -rc $@ $(OBJECTS)
diff --git a/converter/other/fiasco/input/Makefile b/converter/other/fiasco/input/Makefile
index c01af772..2f8749f6 100644
--- a/converter/other/fiasco/input/Makefile
+++ b/converter/other/fiasco/input/Makefile
@@ -7,18 +7,18 @@ SUBDIR = $(FIASCOSUBDIR)/input
 BUILDDIR = ../../../..
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
 OBJECTS =  basis.o matrices.o mc.o nd.o read.o tree.o weights.o
 
 MERGE_OBJECTS = $(OBJECTS)
 
-INCLUDES = -I$(SRCDIR)/$(FIASCOSUBDIR) -I$(SRCDIR)/$(FIASCOSUBDIR)/lib \
-	   -I$(SRCDIR)/$(FIASCOSUBDIR)/codec
+COMP_INCLUDES = -I$(SRCDIR)/$(FIASCOSUBDIR) -I$(SRCDIR)/$(FIASCOSUBDIR)/lib \
+	        -I$(SRCDIR)/$(FIASCOSUBDIR)/codec
 
 all: libfiasco_input.a
 
-include $(SRCDIR)/Makefile.common
+include $(SRCDIR)/common.mk
 
 libfiasco_input.a: $(OBJECTS)
 	$(AR) -rc $@ $(OBJECTS)
diff --git a/converter/other/fiasco/lib/Makefile b/converter/other/fiasco/lib/Makefile
index 99d7c1d7..801fd24e 100644
--- a/converter/other/fiasco/lib/Makefile
+++ b/converter/other/fiasco/lib/Makefile
@@ -6,7 +6,7 @@ FIASCOSUBDIR = converter/other/fiasco
 SUBDIR = $(FIASCOSUBDIR)/lib
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
 OBJECTS = \
   arith.o \
@@ -21,11 +21,11 @@ OBJECTS = \
 
 MERGE_OBJECTS = $(OBJECTS)
 
-INCLUDES = -I$(SRCDIR)/$(FIASCOSUBDIR)
+COMP_INCLUDES = -I$(SRCDIR)/$(FIASCOSUBDIR)
 
 all: libfiasco_lib.a
 
-include $(SRCDIR)/Makefile.common
+include $(SRCDIR)/common.mk
 
 libfiasco_lib.a: $(OBJECTS)
 	$(AR) -rc $@ $(OBJECTS)
diff --git a/converter/other/fiasco/lib/misc.c b/converter/other/fiasco/lib/misc.c
index 02a1314f..12b94e7a 100644
--- a/converter/other/fiasco/lib/misc.c
+++ b/converter/other/fiasco/lib/misc.c
@@ -432,38 +432,6 @@ Log2 (double x)
    return log (x) / 0.69314718;
 }
 
-#ifndef HAVE_STRCASECMP
-bool_t
-strcaseeq (const char *s1, const char *s2)
-/*
- *  Compare strings 's1' and 's2', ignoring  the  case of the characters.
- *
- *  Return value:
- *	TRUE if strings match, else FALSE
- */
-{
-   bool_t  matched;
-   char	  *ls1, *ls2, *ptr;
-
-   assert (s1 && s2);
-   
-   ls1 = strdup (s1);
-   ls2 = strdup (s2);
-   
-   for (ptr = ls1; *ptr; ptr++)
-      *ptr = tolower (*ptr);
-   for (ptr = ls2; *ptr; ptr++)
-      *ptr = tolower (*ptr);
-
-   matched = streq (ls1, ls2) ? YES : NO;
-
-   Free (ls1);
-   Free (ls2);
-   
-   return matched;
-}
-#endif /* not HAVE_STRCASECMP */
-
 real_t
 variance (const word_t *pixels, unsigned x0, unsigned y0,
 	  unsigned width, unsigned height, unsigned cols)
diff --git a/converter/other/fiasco/output/Makefile b/converter/other/fiasco/output/Makefile
index 3bdc4635..26b6d924 100644
--- a/converter/other/fiasco/output/Makefile
+++ b/converter/other/fiasco/output/Makefile
@@ -6,19 +6,20 @@ FIASCOSUBDIR = converter/other/fiasco
 SUBDIR = $(FIASCOSUBDIR)/output
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
 OBJECTS =  matrices.o mc.o nd.o tree.o weights.o write.o
 
 MERGE_OBJECTS = $(OBJECTS)
 
-INCLUDES = -I$(SRCDIR)/$(FIASCOSUBDIR) \
-	   -I$(SRCDIR)/$(FIASCOSUBDIR)/lib \
-	   -I$(SRCDIR)/$(FIASCOSUBDIR)/codec 
+COMP_INCLUDES = \
+  -I$(SRCDIR)/$(FIASCOSUBDIR) \
+  -I$(SRCDIR)/$(FIASCOSUBDIR)/lib \
+  -I$(SRCDIR)/$(FIASCOSUBDIR)/codec 
 
 all: libfiasco_output.a
 
-include $(SRCDIR)/Makefile.common
+include $(SRCDIR)/common.mk
 
 libfiasco_output.a: $(OBJECTS)
 	$(AR) -rc $@ $(OBJECTS)
diff --git a/converter/other/fiasco/params.c b/converter/other/fiasco/params.c
index 3d0a0252..7a302b82 100644
--- a/converter/other/fiasco/params.c
+++ b/converter/other/fiasco/params.c
@@ -15,7 +15,8 @@
  *  $State: Exp $
  */
 
-#define _BSD_SOURCE 1   /* Make sure strdup() is in string.h */
+#define _BSD_SOURCE 1
+    /* Make sure strdup() is in string.h and strcaseeq() is in nstring.h */
 #define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
 
 #include "config.h"
diff --git a/converter/other/fitstopnm.c b/converter/other/fitstopnm.c
index b4240d63..73564c4b 100644
--- a/converter/other/fitstopnm.c
+++ b/converter/other/fitstopnm.c
@@ -1,4 +1,4 @@
- /* fitstopnm.c - read a FITS file and produce a portable anymap
+ /* fitstopnm.c - read a FITS file and produce a PNM.
  **
  ** Copyright (C) 1989 by Jef Poskanzer.
  **
@@ -30,16 +30,118 @@
  ** disabled min max scanning when reading from stdin.
  */
 
+/*
+  The official specification of FITS format (which is for more than
+  just visual images) is at
+  ftp://legacy.gsfc.nasa.gov/fits_info/fits_office/fits_standard.pdf
+*/
+
 #include <string.h>
+#include <float.h>
 
+#include "pm_config.h"
 #include "pm_c_util.h"
+#include "mallocvar.h"
+#include "floatcode.h"
+#include "shhopt.h"
 #include "pnm.h"
 
-/* Do what you have to, to get a sensible value here.  This may not be so */
-/* portable as the rest of the program.  We want to use MAXFLOAT and */
-/* MAXDOUBLE, so you could define them manually if you have to. */
-/* #include <values.h> */
-#include <float.h>
+
+
+struct cmdlineInfo {
+    const char * inputFileName;
+    unsigned int image;  /* zero if unspecified */
+    float max;
+    unsigned int maxSpec;
+    float min;
+    unsigned int minSpec;
+    unsigned int scanmax;
+    unsigned int printmax;
+    unsigned int noraw;
+        /* This is for backward compatibility only.  Use the common option
+           -plain now.  (pnm_init() processes -plain).
+        */
+    unsigned int verbose;
+    unsigned int omaxval;
+    unsigned int omaxvalSpec;
+};
+
+
+
+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 imageSpec;
+    unsigned int option_def_index;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "image",    OPT_UINT,
+            &cmdlineP->image,   &imageSpec,                            0);
+    OPTENT3(0, "min",      OPT_FLOAT,
+            &cmdlineP->min,     &cmdlineP->minSpec,                    0);
+    OPTENT3(0, "max",      OPT_FLOAT,
+            &cmdlineP->max,     &cmdlineP->maxSpec,                    0);
+    OPTENT3(0, "scanmax",  OPT_FLAG,
+            NULL,               &cmdlineP->scanmax,                    0);
+    OPTENT3(0, "printmax", OPT_FLAG,
+            NULL,               &cmdlineP->printmax,                   0);
+    OPTENT3(0, "noraw",    OPT_FLAG,
+            NULL,               &cmdlineP->noraw,                      0);
+    OPTENT3(0, "verbose",  OPT_FLAG,
+            NULL,               &cmdlineP->verbose,                    0);
+    OPTENT3(0, "omaxval",  OPT_UINT,
+            &cmdlineP->omaxval, &cmdlineP->omaxvalSpec,                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 */
+
+    /* Set some defaults the lazy way (using multiple setting of variables) */
+
+    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (imageSpec) {
+        if (cmdlineP->image == 0)
+            pm_error("You may not specify zero for the image number.  "
+                     "Images are numbered starting at 1.");
+    } else
+        cmdlineP->image = 0;
+
+    if (cmdlineP->maxSpec && cmdlineP->minSpec) {
+        if (cmdlineP->max <= cmdlineP->min)
+            pm_error("-max must be greater than -min.  You specified "
+                     "-max=%f, -min=%f", cmdlineP->max, cmdlineP->min);
+    }
+
+    if (argc-1 < 1)
+        cmdlineP->inputFileName = "-";
+    else {
+        cmdlineP->inputFileName = argv[1];
+        
+        if (argc-1 > 1)
+            pm_error("Too many arguments (%u).  The only non-option argument "
+                     "is the input file name.", argc-1);
+    }
+}
+
+
 
 struct FITS_Header {
   int simple;       /* basic format or not */
@@ -54,10 +156,262 @@ struct FITS_Header {
   double bscale;
 };
 
-static void read_fits_header ARGS(( FILE* fp, struct FITS_Header* hP ));
-static void read_card ARGS(( FILE* fp, char* buf ));
-static void read_val ARGS(( FILE* fp, int bitpix, double* vp ));
-     
+
+/* This code deals properly with integers, no matter what the byte order
+   or integer size of the host machine.  We handle sign extension manually to
+   prevent problems with signed/unsigned characters.  We read floating point
+   values properly only when the host architecture conforms to IEEE-754.  If
+   you need to tweak this code for other machines, you might want to get a
+   copy of the FITS documentation from nssdca.gsfc.nasa.gov
+*/
+
+static void
+readFitsChar(FILE *   const ifP,
+             double * const vP) {
+
+    /* 8 bit FITS integers are unsigned */
+
+    int const ich = getc(ifP);
+
+    if (ich == EOF)
+        pm_error("EOF / read error");
+    else
+        *vP = ich;
+}
+
+
+
+static void
+readFitsShort(FILE *   const ifP,
+              double * const vP) {
+
+    int ich;
+    int ival;
+    unsigned char c[8];
+
+    ich = getc(ifP);
+
+    if (ich == EOF)
+        pm_error("EOF / read error");
+
+    c[0] = ich;
+
+    ich = getc(ifP);
+
+    if (ich == EOF)
+        pm_error("EOF / read error");
+
+    c[1] = ich;
+
+    if (c[0] & 0x80)
+        ival = ~0xFFFF | c[0] << 8 | c[1];
+    else
+        ival = c[0] << 8 | c[1];
+
+    *vP = ival;
+}
+
+
+
+static void
+readFitsLong(FILE *   const ifP,
+             double * const vP) {
+
+    unsigned int i;
+    long int lval;
+    unsigned char c[4];
+
+    for (i = 0; i < 4; ++i) {
+        int const ich = getc(ifP);
+        if (ich == EOF)
+            pm_error("EOF / read error");
+        c[i] = ich;
+    }
+
+    if (c[0] & 0x80)
+        lval = ~0xFFFFFFFF | c[0] << 24 | c[1] << 16 | c[2] << 8 | c[3];
+    else
+        lval = c[0] << 24 | c[1] << 16 | c[2] << 8 | c[3] << 0;
+
+    *vP = lval;
+}
+
+
+
+static void
+readFitsFloat(FILE *   const ifP,
+              double * const vP) {
+
+    unsigned int i;
+    pm_bigendFloat bigend;
+
+    for (i = 0; i < 4; ++i) {
+        int const ich = getc(ifP);
+        if (ich == EOF)
+            pm_error("EOF / read error");
+        bigend.bytes[i] = ich;
+    }
+
+    *vP = pm_floatFromBigendFloat(bigend);
+}
+
+
+
+static void
+readFitsDouble(FILE *   const ifP,
+               double * const vP) {
+
+    unsigned int i;
+    pm_bigendDouble bigend;
+
+    for (i = 0; i < 8; ++i) {
+        int const ich = getc(ifP);
+        if (ich == EOF)
+            pm_error("EOF / read error");
+        bigend.bytes[i] = ich;
+    }
+
+    *vP = pm_doubleFromBigendDouble(bigend);
+}
+
+
+
+static void
+readVal(FILE *   const ifP,
+        int      const bitpix,
+        double * const vP) {
+
+    switch (bitpix) {
+    case 8:
+        readFitsChar(ifP, vP);
+        break;
+
+    case 16:
+        readFitsShort(ifP, vP);
+        break;
+      
+    case 32:
+        readFitsLong(ifP, vP);
+        break;
+      
+    case -32:
+        readFitsFloat(ifP, vP);
+        break;
+      
+    case -64:
+        readFitsDouble(ifP, vP);
+        break;
+      
+    default:
+        pm_error("Strange bitpix value %d in readVal()", bitpix);
+    }
+}
+
+
+
+static void
+readCard(FILE * const ifP,
+         char * const buf) {
+
+    size_t bytesRead;
+
+    bytesRead = fread(buf, 1, 80, ifP);
+    if (bytesRead == 0)
+        pm_error("error reading header");
+}
+
+
+
+static void
+readFitsHeader(FILE *               const ifP,
+               struct FITS_Header * const hP) {
+
+    int seenEnd;
+  
+    seenEnd = 0;
+    /* Set defaults */
+    hP->simple  = 0;
+    hP->bzer    = 0.0;
+    hP->bscale  = 1.0;
+    hP->datamin = - DBL_MAX;
+    hP->datamax = DBL_MAX;
+  
+    while (!seenEnd) {
+        unsigned int i;
+        for (i = 0; i < 36; ++i) {
+            char buf[80];
+            char c;
+
+            readCard(ifP, buf);
+    
+            if (sscanf(buf, "SIMPLE = %c", &c) == 1) {
+                if (c == 'T' || c == 't')
+                    hP->simple = 1;
+            } else if (sscanf(buf, "BITPIX = %d", &(hP->bitpix)) == 1);
+            else if (sscanf(buf, "NAXIS = %d", &(hP->naxis)) == 1);
+            else if (sscanf(buf, "NAXIS1 = %d", &(hP->naxis1)) == 1);
+            else if (sscanf(buf, "NAXIS2 = %d", &(hP->naxis2)) == 1);
+            else if (sscanf(buf, "NAXIS3 = %d", &(hP->naxis3)) == 1);
+            else if (sscanf(buf, "DATAMIN = %lf", &(hP->datamin)) == 1);
+            else if (sscanf(buf, "DATAMAX = %lf", &(hP->datamax)) == 1);
+            else if (sscanf(buf, "BZERO = %lf", &(hP->bzer)) == 1);
+            else if (sscanf(buf, "BSCALE = %lf", &(hP->bscale)) == 1);
+            else if (strncmp(buf, "END ", 4 ) == 0) seenEnd = 1;
+        }
+    }
+}
+
+
+
+static void
+interpretPlanes(struct FITS_Header const fitsHeader,
+                unsigned int       const imageRequest,
+                bool               const verbose,
+                unsigned int *     const imageCountP,
+                bool *             const multiplaneP,
+                unsigned int *     const desiredImageP) {
+
+    if (fitsHeader.naxis == 2) {
+        *imageCountP   = 1;
+        *multiplaneP   = FALSE;
+        *desiredImageP = 1;
+    } else {
+        if (imageRequest) {
+            if (imageRequest > fitsHeader.naxis3)
+                pm_error("Only %u plane%s in this file.  "
+                         "You requested image %u", 
+                         fitsHeader.naxis3, fitsHeader.naxis3 > 1 ? "s" : "",
+                         imageRequest);
+            else {
+                *imageCountP   = fitsHeader.naxis3;
+                *multiplaneP   = FALSE;
+                *desiredImageP = imageRequest;
+            }
+        } else {
+            if (fitsHeader.naxis3 == 3) {
+                *imageCountP   = 1;
+                *multiplaneP   = TRUE;
+                *desiredImageP = 1;
+            } else if (fitsHeader.naxis3 > 1)
+                pm_error("This FITS file contains multiple (%u) images.  "
+                         "You must specify which one you want with a "
+                         "-image option.", fitsHeader.naxis3);
+            else {
+                *imageCountP   = fitsHeader.naxis3;
+                *multiplaneP   = FALSE;
+                *desiredImageP = 1;
+            }
+        }
+    }
+    if (verbose) {
+        
+        pm_message("FITS stream is %smultiplane", *multiplaneP ? "" : "not ");
+        pm_message("We will take image %u (1 is first) of %u "
+                   "in the FITS stream",
+                   *desiredImageP, *imageCountP);
+    }
+}
+
 
 
 static void
@@ -100,7 +454,7 @@ scanImageForMinMax(FILE *       const ifP,
             unsigned int col;
             for (col = 0; col < cols; ++col) {
                 double val;
-                read_val(ifP, bitpix, &val);
+                readVal(ifP, bitpix, &val);
                 if (image == imagenum || multiplane ) {
                     dmax = MAX(dmax, val);
                     dmin = MIN(dmin, val);
@@ -170,344 +524,233 @@ computeMinMax(FILE *             const ifP,
 
 
 
-int
-main(int argc, char * argv[]) {
-
-    FILE* ifp;
-    int argn, imagenum, image, row;
-    register int col;
-    xelval maxval;
-    double val, frmin, frmax, scale, t;
-    double datamin, datamax;
-    int rows, cols, images, format;
-    struct FITS_Header h;
-    xel** pnmarray;
-    xelval tx, txv[4];
-    const char* fits_name;
-    const char* const usage = "[-image N] [-scanmax] [-printmax] [-min f] [-max f] [FITSfile]";
-
-    int doscan = 0;
-    int forceplain = 0;
-    int forcemin = 0;
-    int forcemax = 0;
-    int printmax = 0;
-    bool multiplane;
-  
-    pnm_init( &argc, argv );
-  
-    argn = 1;
-    imagenum = 0;
-  
-    while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
-    {
-        if ( pm_keymatch( argv[argn], "-image", 2 ) )
-        {
-            ++argn;
-            if ( argn == argc || sscanf( argv[argn], "%d", &imagenum ) != 1 )
-                pm_usage( usage );
-        }
-        else if ( pm_keymatch( argv[argn], "-max", 3 ) )
-        {
-            ++argn;
-            forcemax = 1;
-            if ( argn == argc || sscanf( argv[argn], "%lf", &frmax ) != 1 )
-                pm_usage( usage );
-        }
-        else if ( pm_keymatch( argv[argn], "-min", 3 ) )
-        {
-            ++argn;
-            forcemin = 1;
-            if ( argn == argc || sscanf( argv[argn], "%lf", &frmin ) != 1 )
-                pm_usage( usage );
-        }
-        else if ( pm_keymatch( argv[argn], "-scanmax", 2 ) )
-            doscan = 1;
-        else if ( pm_keymatch( argv[argn], "-noraw", 2 ) )
-            /* This is for backward compatibility only.  Use the common option
-               -plain now.  (pnm_init() processes -plain).
+static xelval
+determineMaxval(struct cmdlineInfo const cmdline,
+                struct FITS_Header const fitsHeader,
+                double             const datamax,
+                double             const datamin) {
+
+    xelval retval;
+                
+    if (cmdline.omaxvalSpec)
+        retval = cmdline.omaxval;
+    else {
+        if (fitsHeader.bitpix < 0) {
+            /* samples are floating point, which means the resolution
+               could be anything.  So we just pick a convenient maxval
+               of 255.  Before Netpbm 10.20 (January 2004), we did
+               maxval = max - min for floating point as well as
+               integer samples.
             */
-            forceplain = 1;
-        else if ( pm_keymatch( argv[argn], "-printmax", 2 ) )
-            printmax = 1;
-        else
-            pm_usage( usage );
-        ++argn;
-    }
-  
-    if ( argn < argc )
-    {
-        fits_name = argv[argn];
-        ++argn;
+            retval = 255;
+            if (cmdline.verbose)
+                pm_message("FITS image has floating point samples.  "
+                           "Using maxval = %u.", (unsigned int)retval);
+        } else {
+            retval = MAX(1, MIN(PNM_OVERALLMAXVAL, datamax - datamin));
+            if (cmdline.verbose)
+                pm_message("FITS image has samples in the range %d-%d.  "
+                           "Using maxval %u.",
+                           (int)(datamin+0.5), (int)(datamax+0.5),
+                           (unsigned int)retval);
+        }
     }
-    else
-        fits_name = "-";
-
-    if ( argn != argc )
-        pm_usage( usage );
-
-    ifp = pm_openr_seekable(fits_name);
-  
-    read_fits_header( ifp, &h );
-  
-    if ( ! h.simple )
-        pm_error( "FITS file is not in simple format, can't read" );
-    if ( h.naxis != 2 && h.naxis != 3 )
-        pm_message( "Warning: FITS file has %d axes", h.naxis );
-    cols = h.naxis1;
-    rows = h.naxis2;
-    if ( h.naxis == 2 )
-        images = imagenum = 1;
-    else
-        images = h.naxis3;
-    if ( imagenum > images )
-        pm_error( "only %d plane%s in this file", 
-                  images, images > 1 ? "s" : "" );
-    if ( images != 3 && images > 1 && imagenum == 0 )
-        pm_error( "need to specify a plane using the -imagenum flag" );
-
-    multiplane = ( images == 3 && imagenum == 0 );
+    return retval;
+}
 
-    computeMinMax(ifp, images, cols, rows, h, imagenum, multiplane,
-                  forcemin, forcemax, frmin, frmax,
-                  &datamin, &datamax);
 
-    if (h.bitpix < 0) {
-        /* samples are floating point, which means the resolution could be
-           anything.  So we just pick a convenient maxval of 255.  We should
-           have a program option to choose the maxval.  Before Netpbm 10.20
-           (January 2004), we did maxval = max - min for floating point as
-           well as integer samples.
-        */
-        maxval = 255;
-    } else
-        maxval = MAX(1, MIN(PNM_OVERALLMAXVAL, datamax - datamin));
 
-    if ( datamax - datamin == 0 )
-        scale = 1.0;
-    else
-        scale = maxval / ( datamax - datamin );
-
-    /* If printmax option is true, just print and exit. */
-    /* For use in shellscripts.  Ex:                    */
-    /* eval `fitstopnm -printmax $filename | \          */
-    /*   awk '{min = $1; max = $2}\                     */
-    /*         END {print "min=" min; " max=" max}'`    */
-    if (printmax) {
-        printf( "%f %f\n", datamin, datamax);
-        pm_close( ifp );
-        pm_close( stdout );
-        exit( 0 );
-    }
+static void
+convertPgmRaster(FILE *             const ifP,
+                 unsigned int       const cols,
+                 unsigned int       const rows,
+                 xelval             const maxval,
+                 unsigned int       const desiredImage,
+                 unsigned int       const imageCount,
+                 struct FITS_Header const fitsHdr,
+                 double             const scale,
+                 double             const datamin,
+                 xel **             const xels) {
+        
+    /* Note: the FITS specification does not give the association between
+       file position and image position (i.e. is the first pixel in the
+       file the top left, bottom left, etc.).  We use the common sense,
+       popular order of row major, top to bottom, left to right.  This
+       has been the case and accepted since 1989, but in 2008, we discovered
+       that Gimp and ImageMagick do bottom to top.
+    */
+    unsigned int image;
 
-    if (multiplane)
-        format = PPM_FORMAT;
-    else
-        format = PGM_FORMAT;
+    pm_message("Writing PPM file "
+               "(Probably not what you want - consider an -image option)");
 
-    pnmarray = pnm_allocarray( cols, rows );
-
-    switch( PNM_FORMAT_TYPE( format ))
-    {
-    case PGM_TYPE:
-        pm_message( "writing PGM file" );
-        for ( image = 1; image <= imagenum; ++image )
-        {
-            if ( image != imagenum )
-                pm_message( "skipping image plane %d of %d", image, images );
-            else if ( images > 1 )
-                pm_message( "reading image plane %d of %d", image, images );
-            for ( row = 0; row < rows; ++row)
-                for ( col = 0; col < cols; ++col )
+    for (image = 1; image <= desiredImage; ++image) {
+        unsigned int row;
+        if (image != desiredImage)
+            pm_message("skipping image plane %u of %u", image, imageCount);
+        else if (imageCount > 1)
+            pm_message("reading image plane %u of %u", image, imageCount);
+        for (row = 0; row < rows; ++row) {
+            unsigned int col;
+            for (col = 0; col < cols; ++col) {
+                double val;
+                readVal(ifP, fitsHdr.bitpix, &val);
                 {
-                    read_val (ifp, h.bitpix, &val);
-                    t = scale * ( val * h.bscale + h.bzer - datamin );
-                    tx = MAX( 0, MIN( t, maxval ) );
-                    if ( image == imagenum )
-                        PNM_ASSIGN1( pnmarray[row][col], tx );
+                    double const t = scale *
+                        (val * fitsHdr.bscale + fitsHdr.bzer - datamin);
+                    xelval const tx = MAX(0, MIN(t, maxval));
+                    if (image == desiredImage)
+                        PNM_ASSIGN1(xels[row][col], tx);
                 }
+            }
         }
-        break;
-    case PPM_TYPE:
-        pm_message( "writing PPM file" );
-        for ( image = 1; image <= images; image++ )
-        {
-            pm_message( "reading image plane %d of %d", image, images );
-            for ( row = 0; row < rows; row++ )
-                for ( col = 0; col < cols; col++ )
+    } 
+}
+
+
+
+static void
+convertPpmRaster(FILE *             const ifP,
+                 unsigned int       const cols,
+                 unsigned int       const rows,
+                 xelval             const maxval,
+                 struct FITS_Header const fitsHdr,
+                 double             const scale,
+                 double             const datamin,
+                 xel **             const xels) {
+/*----------------------------------------------------------------------------
+   Read the FITS raster from file *ifP into xels[][].  Image dimensions
+   are 'cols' by 'rows'.  The FITS raster is 3 planes composing one
+   image: a red plane followed by a green plane followed by a blue plane.
+-----------------------------------------------------------------------------*/
+    unsigned int plane;
+
+    pm_message("writing PPM file");
+
+    for (plane = 0; plane < 3; ++plane) {
+        unsigned int row;
+        pm_message("reading image plane %u (%s)",
+                   plane, plane == 0 ? "red" : plane == 1 ? "green" : "blue");
+        for (row = 0; row < rows; ++row) {
+            unsigned int col;
+            for (col = 0; col < cols; ++col) {
+                double val;
+                readVal(ifP, fitsHdr.bitpix, &val);
                 {
-                    read_val (ifp, h.bitpix, &val);
-                    txv[1] = PPM_GETR( pnmarray[row][col] );
-                    txv[2] = PPM_GETG( pnmarray[row][col] );
-                    txv[3] = PPM_GETB( pnmarray[row][col] );
-                    t = scale * ( val * h.bscale + h.bzer - datamin );
-                    txv[image] = MAX( 0, MIN( t, maxval ));
-                    PPM_ASSIGN( pnmarray[row][col], txv[1], txv[2], txv[3] );
+                    double const t = scale *
+                        (val * fitsHdr.bscale + fitsHdr.bzer - datamin);
+                    xelval const sample = MAX(0, MIN(t, maxval));
+
+                    switch (plane) {
+                    case 0: PPM_PUTR(xels[row][col], sample); break;
+                    case 1: PPM_PUTG(xels[row][col], sample); break;
+                    case 2: PPM_PUTB(xels[row][col], sample); break;
+                    }
                 }
+            }
         }
-        break;
-    default:
-        pm_error( "can't happen" );
-        break;
     }
-
-    pnm_writepnm( stdout, pnmarray, cols, rows, maxval, format, forceplain );
-    pnm_freearray( pnmarray, rows );
-
-    pm_close( ifp );
-    pm_close( stdout );
-  
-    exit( 0 );
 }
 
 
+
 static void
-swapbytes(void *       const p,
-          unsigned int const nbytes) {
-#if BYTE_ORDER == LITTLE_ENDIAN
-    unsigned char * const c = p;
-    unsigned int i;
-    for (i = 0; i < nbytes/2; ++i) {
-        unsigned char const orig = c[i];
-        c[i] = c[nbytes-(i+1)];
-        c[nbytes-(i+1)] = orig;
+convertRaster(FILE *             const ifP,
+              unsigned int       const cols,
+              unsigned int       const rows,
+              xelval             const maxval,
+              bool               const forceplain,
+              bool               const multiplane,
+              unsigned int       const desiredImage,
+              unsigned int       const imageCount,
+              struct FITS_Header const fitsHdr,
+              double             const scale,
+              double             const datamin) {
+
+    xel ** xels;
+    int format;
+
+    xels = pnm_allocarray(cols, rows);
+
+    if (multiplane) {
+        format = PPM_FORMAT;
+        convertPpmRaster(ifP, cols, rows, maxval, fitsHdr, scale, datamin,
+                         xels);
+    } else {
+        format = PGM_FORMAT;
+        convertPgmRaster(ifP, cols, rows, maxval,
+                         desiredImage, imageCount, fitsHdr, scale, datamin,
+                         xels);
     }
-#endif
+    pnm_writepnm(stdout, xels, cols, rows, maxval, format, forceplain);
+    pnm_freearray(xels, rows);
 }
 
 
-/*
- ** This code will deal properly with integers, no matter what the byte order
- ** or integer size of the host machine.  Sign extension is handled manually
- ** to prevent problems with signed/unsigned characters.  Floating point
- ** values will only be read properly when the host architecture is IEEE-754
- ** conformant.  If you need to tweak this code for other machines, you might
- ** want to snag a copy of the FITS documentation from nssdca.gsfc.nasa.gov
- */
 
-static void
-read_val (fp, bitpix, vp)
-    FILE *fp;
-    int bitpix;
-    double *vp;
+int
+main(int argc, char * argv[]) {
 
-{
-    int i, ich, ival;
-    long int lval;
-    unsigned char c[8];
-  
-    switch ( bitpix )
-    {
-        /* 8 bit FITS integers are unsigned */
-    case 8:
-        ich = getc( fp );
-        if ( ich == EOF )
-            pm_error( "EOF / read error" );
-        *vp = ich;
-        break;
-      
-    case 16:
-        ich = getc( fp );
-        if ( ich == EOF )
-            pm_error( "EOF / read error" );
-        c[0] = ich;
-        ich = getc( fp );
-        if ( ich == EOF )
-            pm_error( "EOF / read error" );
-        c[1] = ich;
-        if (c[0] & 0x80)
-            ival = ~0xFFFF | c[0]<<8 | c[1];
-        else
-            ival = c[0]<<8 | c[1];
-        *vp = ival;
-        break;
-      
-    case 32:
-        for (i=0; i<4; i++) {
-            ich = getc( fp );
-            if ( ich == EOF )
-                pm_error( "EOF / read error" );
-            c[i] = ich;
-        }
-        if (c[0] & 0x80)
-            lval = ~0xFFFFFFFF |
-                c[0]<<24 | c[1]<<16 | c[2]<<8 | c[3];
-        else
-            lval = c[0]<<24 | c[1]<<16 | c[2]<<8 | c[3];
-        *vp = lval;
-        break;
-      
-    case -32:
-        for (i=0; i<4; i++) {
-            ich = getc( fp );
-            if ( ich == EOF )
-                pm_error( "EOF / read error" );
-            c[i] = ich;
-        }
-        swapbytes(c, 4);
-        *vp = *( (float *) c);
-        break;
-      
-    case -64:
-        for (i=0; i<8; i++) {
-            ich = getc( fp );
-            if ( ich == EOF )
-                pm_error( "EOF / read error" );
-            c[i] = ich;
-        }
-        swapbytes(c, 8);
-        *vp = *( (double *) c);
-        break;
-      
-    default:
-        pm_error( "Strange bitpix in read_value" );
-    }
-}
+    struct cmdlineInfo cmdline;
+    FILE * ifP;
+    unsigned int cols, rows;
+    xelval maxval;
+    double scale;
+    double datamin, datamax;
+    struct FITS_Header fitsHeader;
 
-static void
-read_fits_header( fp, hP )
-    FILE* fp;
-    struct FITS_Header* hP;
-{
-    char buf[80];
-    int seen_end;
-    int i;
-    char c;
+    unsigned int imageCount;
+    unsigned int desiredImage;
+        /* Plane number (starting at one) of plane that contains the image
+           we want.
+        */
+    bool multiplane;
+        /* This is a one-image multiplane stream; 'desiredImage'
+           is undefined
+        */
   
-    seen_end = 0;
-    hP->simple = 0;
-    hP->bzer = 0.0;
-    hP->bscale = 1.0;
-    hP->datamin = - DBL_MAX;
-    hP->datamax = DBL_MAX;
+    pnm_init( &argc, argv );
   
-    while ( ! seen_end )
-        for ( i = 0; i < 36; ++i )
-        {
-            read_card( fp, buf );
-    
-            if ( sscanf( buf, "SIMPLE = %c", &c ) == 1 )
-            {
-                if ( c == 'T' || c == 't' )
-                    hP->simple = 1;
-            }
-            else if ( sscanf( buf, "BITPIX = %d", &(hP->bitpix) ) == 1 );
-            else if ( sscanf( buf, "NAXIS = %d", &(hP->naxis) ) == 1 );
-            else if ( sscanf( buf, "NAXIS1 = %d", &(hP->naxis1) ) == 1 );
-            else if ( sscanf( buf, "NAXIS2 = %d", &(hP->naxis2) ) == 1 );
-            else if ( sscanf( buf, "NAXIS3 = %d", &(hP->naxis3) ) == 1 );
-            else if ( sscanf( buf, "DATAMIN = %lf", &(hP->datamin) ) == 1 );
-            else if ( sscanf( buf, "DATAMAX = %lf", &(hP->datamax) ) == 1 );
-            else if ( sscanf( buf, "BZERO = %lf", &(hP->bzer) ) == 1 );
-            else if ( sscanf( buf, "BSCALE = %lf", &(hP->bscale) ) == 1 );
-            else if ( strncmp( buf, "END ", 4 ) == 0 ) seen_end = 1;
-        }
-}
+    parseCommandLine(argc, argv, &cmdline);
 
-static void
-read_card( fp, buf )
-    FILE* fp;
-    char* buf;
-{
-    if ( fread( buf, 1, 80, fp ) == 0 )
-        pm_error( "error reading header" );
+    ifP = pm_openr(cmdline.inputFileName);
+
+    readFitsHeader(ifP, &fitsHeader);
+  
+    if (!fitsHeader.simple)
+        pm_error("FITS file is not in simple format, can't read");
+
+    if (fitsHeader.naxis != 2 && fitsHeader.naxis != 3)
+        pm_message("Warning: FITS file has %u axes", fitsHeader.naxis);
+
+    cols = fitsHeader.naxis1;
+    rows = fitsHeader.naxis2;
+
+    interpretPlanes(fitsHeader, cmdline.image, cmdline.verbose,
+                    &imageCount, &multiplane, &desiredImage);
+
+    computeMinMax(ifP, imageCount, cols, rows, fitsHeader,
+                  desiredImage, multiplane,
+                  cmdline.minSpec, cmdline.maxSpec,
+                  cmdline.min, cmdline.max,
+                  &datamin, &datamax);
+
+    maxval = determineMaxval(cmdline, fitsHeader, datamax, datamin);
+
+    if (datamax - datamin == 0)
+        scale = 1.0;
+    else
+        scale = maxval / (datamax - datamin);
+
+    if (cmdline.printmax)
+        printf("%f %f\n", datamin, datamax);
+    else
+        convertRaster(ifP, cols, rows, maxval, cmdline.noraw,
+                      multiplane, desiredImage, imageCount,
+                      fitsHeader, scale, datamin);
+
+    pm_close(ifP);
+    pm_close(stdout);
+
+    return 0;
 }
diff --git a/converter/other/giftopnm.c b/converter/other/giftopnm.c
index 7337960c..4b8b0487 100644
--- a/converter/other/giftopnm.c
+++ b/converter/other/giftopnm.c
@@ -23,10 +23,11 @@
 #include <string.h>
 #include <assert.h>
 
-#include "pnm.h"
-#include "shhopt.h"
+#include "pm_c_util.h"
 #include "mallocvar.h"
 #include "nstring.h"
+#include "shhopt.h"
+#include "pnm.h"
 
 #define GIFMAXVAL 255
 #define MAXCOLORMAPSIZE 256
@@ -41,6 +42,13 @@
 #define LOCALCOLORMAP  0x80
 #define BitSet(byte, bit)      (((byte) & (bit)) == (bit))
 
+#if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN)
+  /* make sure (BYTE_ORDER == LITTLE_ENDIAN) is FALSE */ 
+  #define BYTE_ORDER    0
+  #define LITTLE_ENDIAN 1
+#endif
+
+
 static __inline__ bool
 ReadOK(FILE *          const fileP,
        unsigned char * const buffer,
@@ -54,6 +62,33 @@ ReadOK(FILE *          const fileP,
 }
 
 
+
+static void
+readFile(FILE *          const ifP,
+         unsigned char * const buffer,
+         size_t          const len,
+         const char **   const errorP) {
+
+    size_t bytesRead;
+
+    bytesRead = fread(buffer, len, 1, ifP);
+
+    if (bytesRead == len)
+        *errorP = NULL;
+    else {
+        if (ferror(ifP))
+            asprintfN(errorP, "Error reading file.  errno=%d (%s)",
+                      errno, strerror(errno));
+        else if (feof(ifP))
+            asprintfN(errorP, "End of file encountered");
+        else
+            asprintfN(errorP, "Short read -- %u bytes of %u",
+                              (unsigned)bytesRead, (unsigned)len);
+    }
+}
+
+
+
 #define LM_to_uint(a,b)                        (((b)<<8)|(a))
 
 static int const maxnum_lzwCode = (1<<MAX_LZW_BITS);
@@ -72,6 +107,7 @@ struct cmdlineInfo {
         */
     const char * alpha_filename;
     unsigned int quitearly;
+    unsigned int repair;
 };
 
 
@@ -101,8 +137,10 @@ parseCommandLine(int argc, char ** argv,
             &cmdlineP->verbose,         0);
     OPTENT3(0, "comments",    OPT_FLAG, NULL,
             &cmdlineP->comments,        0);
-    OPTENT3(0, "quitearly",    OPT_FLAG, NULL,
+    OPTENT3(0, "quitearly",   OPT_FLAG, NULL,
             &cmdlineP->quitearly,       0);
+    OPTENT3(0, "repair",      OPT_FLAG, NULL,
+            &cmdlineP->repair,          0);
     OPTENT3(0, "image",       OPT_STRING, &image,
             &imageSpec,                 0);
     OPTENT3(0, "alphaout",    OPT_STRING, &cmdlineP->alpha_filename, 
@@ -232,13 +270,15 @@ readColorMap(FILE *ifP, const int colormapsize,
 
 static bool zeroDataBlock = FALSE;
     /* the most recently read DataBlock was an EOD marker, i.e. had
-       zero length */
+       zero length
+    */
 
 static void
 getDataBlock(FILE *          const ifP, 
              unsigned char * const buf, 
              bool *          const eofP,
-             unsigned int *  const lengthP) {
+             unsigned int *  const lengthP,
+             const char **   const errorP) {
 /*----------------------------------------------------------------------------
    Read a DataBlock from file 'ifP', return it at 'buf'.
 
@@ -258,10 +298,11 @@ getDataBlock(FILE *          const ifP,
     unsigned char count;
     bool successfulRead;
     
-    long const pos=ftell(ifP);
+    long const pos = ftell(ifP);
     successfulRead = ReadOK(ifP, &count, 1);
     if (!successfulRead) {
         pm_message("EOF or error in reading DataBlock size from file" );
+        *errorP = NULL;
         *eofP = TRUE;
         *lengthP = 0;
     } else {
@@ -270,17 +311,21 @@ getDataBlock(FILE *          const ifP,
         *eofP = FALSE;
         *lengthP = count;
 
-        if (count == 0) 
+        if (count == 0) {
+            *errorP = NULL;
             zeroDataBlock = TRUE;
-        else {
+        } else {
             bool successfulRead;
 
             zeroDataBlock = FALSE;
             successfulRead = ReadOK(ifP, buf, count); 
-            
-            if (!successfulRead) 
-                pm_error("EOF or error reading data portion of %d byte "
-                         "DataBlock from file", count);
+
+            if (successfulRead) 
+                *errorP = NULL;
+            else
+                asprintfN(errorP,
+                          "EOF or error reading data portion of %u byte "
+                          "DataBlock from file", count);
         }
     }
 }
@@ -303,14 +348,15 @@ readThroughEod(FILE * const ifP) {
     while (!eod) {
         bool eof;
         unsigned int count;
+        const char * error;
 
-        getDataBlock(ifP, buf, &eof, &count);
-        if (eof)
+        getDataBlock(ifP, buf, &eof, &count, &error);
+        if (error || eof)
             pm_message("EOF encountered before EOD marker.  The GIF "
                        "file is malformed, but we are proceeding "
                        "anyway as if an EOD marker were at the end "
                        "of the file.");
-        if (eof || count == 0)
+        if (error || eof || count == 0)
             eod = TRUE;
     }
 }
@@ -334,7 +380,11 @@ doCommentExtension(FILE * const ifP) {
     done = FALSE;
     while (!done) {
         bool eof;
-        getDataBlock(ifP, (unsigned char*) buf, &eof, &blocklen); 
+        const char * error;
+        getDataBlock(ifP, (unsigned char*) buf, &eof, &blocklen, &error); 
+        if (error)
+            pm_error("Error reading a data block in a comment extension.  %s",
+                     error);
         if (blocklen == 0 || eof)
             done = TRUE;
         else {
@@ -355,8 +405,11 @@ doGraphicControlExtension(FILE *         const ifP,
     bool eof;
     unsigned int length;
     static unsigned char buf[256];
+    const char * error;
 
-    getDataBlock(ifP, buf, &eof, &length);
+    getDataBlock(ifP, buf, &eof, &length, &error);
+    if (error)
+        pm_error("Error reading 1st data block of Graphic Control Extension");
     if (eof)
         pm_error("EOF/error encountered reading "
                  "1st DataBlock of Graphic Control Extension.");
@@ -451,28 +504,16 @@ struct getCodeState {
         */
     bool streamExhausted;
         /* The last time we read from the input stream, we got an EOD marker
-           or EOF
+           or EOF or an error that prevents further reading of the stream.
         */
 };
 
 
 
 static void
-initGetCode(struct getCodeState * const getCodeStateP) {
-    
-    /* Fake a previous data block */
-    getCodeStateP->buf[0] = 0;
-    getCodeStateP->buf[1] = 0;
-    getCodeStateP->bufCount = 2;
-    getCodeStateP->curbit = getCodeStateP->bufCount * 8;
-    getCodeStateP->streamExhausted = FALSE;
-}
-
-
-
-static void
-getAnotherBlock(FILE * const ifP, 
-                struct getCodeState * const gsP) {
+getAnotherBlock(FILE *                const ifP, 
+                struct getCodeState * const gsP,
+                const char **         const errorP) {
 
     unsigned int count;
     unsigned int assumed_count;
@@ -490,98 +531,145 @@ getAnotherBlock(FILE * const ifP,
     gsP->bufCount = 2;
         
     /* Add the next block to the buffer */
-    getDataBlock(ifP, &gsP->buf[gsP->bufCount], &eof, &count);
-    if (eof) {
-        pm_message("EOF encountered in image "
-                   "before EOD marker.  The GIF "
-                   "file is malformed, but we are proceeding "
-                   "anyway as if an EOD marker were at the end "
-                   "of the file.");
-        assumed_count = 0;
-    } else
-        assumed_count = count;
-
-    gsP->streamExhausted = (assumed_count == 0);
+    getDataBlock(ifP, &gsP->buf[gsP->bufCount], &eof, &count, errorP);
+    if (*errorP)
+        gsP->streamExhausted = TRUE;
+    else {
+        if (eof) {
+            pm_message("EOF encountered in image "
+                       "before EOD marker.  The GIF "
+                       "file is malformed, but we are proceeding "
+                       "anyway as if an EOD marker were at the end "
+                       "of the file.");
+            assumed_count = 0;
+        } else
+            assumed_count = count;
 
-    gsP->bufCount += assumed_count;
+        gsP->streamExhausted = (assumed_count == 0);
+        
+        gsP->bufCount += assumed_count;
+    }
 }
 
 
 
+static struct getCodeState getCodeState;
+
 static void
-doGetCode(FILE *                const ifP, 
-          int                   const codeSize,
-          struct getCodeState * const gsP,
-          int *                 const retvalP) {
+getCode_init(struct getCodeState * const getCodeStateP) {
+    
+    /* Fake a previous data block */
+    getCodeStateP->buf[0] = 0;
+    getCodeStateP->buf[1] = 0;
+    getCodeStateP->bufCount = 2;
+    getCodeStateP->curbit = getCodeStateP->bufCount * 8;
+    getCodeStateP->streamExhausted = FALSE;
+}
 
-    while (gsP->curbit + codeSize > gsP->bufCount * 8 &&
-           !gsP->streamExhausted) 
-        /* Not enough left in buffer to satisfy request.  Get the next
-           data block into the buffer.
 
-           Note that a data block may be as small as one byte, so we may need
-           to do this multiple times to get the full code.  (This probably
-           never happens in practice).
-        */
-        getAnotherBlock(ifP, gsP);
 
-    if ((gsP->curbit+codeSize) > gsP->bufCount*8) {
-        /* If the buffer still doesn't have enough bits in it, that means
-           there were no data blocks left to read.
+static unsigned int
+bitsOfLeBuffer(const unsigned char * const buf,
+               unsigned int          const start,
+               unsigned int          const len) {
+/*----------------------------------------------------------------------------
+   Return a string of 'len' bits (up to 16) starting at bit 'start' of buffer
+   buf[].
+
+   In the buffer, the bits are numbered Intel-style, with the first bit of a
+   byte being the least significant bit.  So bit 3 is the "16" bit of the
+   first byte of buf[].
+
+   We return the string as an integer such that its pure binary encoding with
+   the bits numbered Intel-style is the string.  E.g. the string 0,1,1 
+   yields six.
+-----------------------------------------------------------------------------*/
+    uint32_t codeBlock;
+        /* The 3 whole bytes of the buffer that contain the requested
+           bit string
         */
-        *retvalP = -1;  /* EOF */
-
-        {
-            int const bitsUnused = gsP->bufCount*8 - gsP->curbit;
-            if (bitsUnused > 0)
-                pm_message("Stream ends with a partial code "
-                           "(%d bits left in file; "
-                           "expected a %d bit code).  Ignoring.",
-                           bitsUnused, codeSize);
-        }
-    } else {
-        int i, j;
-        int code;
-        unsigned char * const buf = gsP->buf;
-
-        code = 0;  /* initial value */
-        for (i = gsP->curbit, j = 0; j < codeSize; ++i, ++j)
-            code |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
-        gsP->curbit += codeSize;
-        *retvalP = code;
-    }
+
+    assert(len <= 16);
+
+    if (BYTE_ORDER == LITTLE_ENDIAN)
+        /* Fast path */
+        codeBlock = *(uint32_t *) & buf[start/8];
+    else
+        /* logic works for little endian too */
+        codeBlock =
+            (buf[start/8+0] <<  0) |
+            (buf[start/8+1] <<  8) |
+            (buf[start/8+2] << 16);
+            
+    return (unsigned int) 
+        (codeBlock >> (start % 8)) & ((1 << len) - 1);
 }
 
 
 
-static int
-getCode(FILE * const ifP, 
-        int    const codeSize, 
-        bool   const init)
-{
+static void
+getCode_get(struct getCodeState * const gsP,
+            FILE *                const ifP, 
+            int                   const codeSize,
+            bool *                const eofP,
+            unsigned int *        const codeP,
+            const char **         const errorP) {
 /*----------------------------------------------------------------------------
-   If 'init', initialize the code getter.
+  Read and return the next lzw code from the file *ifP.
+
+  'codeSize' is the number of bits in the code we are to get.
 
-   Otherwise, read and return the next lzw code from the file *ifP.
+  Return *eofP == TRUE iff we hit the end of the stream.  That means a legal
+  end of stream, marked by an EOD marker, not just end of file.  An end of
+  file in the middle of the GIF stream is an error.
 
-   'codeSize' is the number of bits in the code we are to get.
+  If there are bits left in the stream, but not 'codeSize' of them, we
+  call that a success with *eofP == TRUE.
 
-   Return -1 instead of a code if we encounter the end of the file.
+  Return the code read (assuming *eofP == FALSE and *errorP == NULL)
+  as *codeP.
 -----------------------------------------------------------------------------*/
-    static struct getCodeState getCodeState;
 
-    int retval;
+    *errorP = NULL;
+
+    while (gsP->curbit + codeSize > gsP->bufCount * 8 &&
+           !gsP->streamExhausted && !*errorP) 
+        /* Not enough left in buffer to satisfy request.  Get the next
+           data block into the buffer.
+
+           Note that a data block may be as small as one byte, so we may need
+           to do this multiple times to get the full code.  (This probably
+           never happens in practice).
+        */
+        getAnotherBlock(ifP, gsP, errorP);
 
-    if (init) {
-        initGetCode(&getCodeState);
-        retval = 0;
-    } else 
-        doGetCode(ifP, codeSize, &getCodeState, &retval);
+    if (!*errorP) {
+        if (gsP->curbit + codeSize > gsP->bufCount * 8) {
+            /* The buffer still doesn't have enough bits in it; that means
+               there were no data blocks left to read.
+            */
+            *eofP = TRUE;
+
+            {
+                int const bitsUnused = gsP->bufCount * 8 - gsP->curbit;
+                if (bitsUnused > 0)
+                    pm_message("Stream ends with a partial code "
+                               "(%d bits left in file; "
+                               "expected a %d bit code).  Ignoring.",
+                               bitsUnused, codeSize);
+            }
+        } else {
+            *codeP = bitsOfLeBuffer(gsP->buf, gsP->curbit, codeSize);
 
-    return retval;
+            gsP->curbit += codeSize;
+            *eofP = FALSE;
+        }
+    }
 }
 
 
+
+
 struct stack {
     /* Stack grows from low addresses to high addresses */
     int * stack;  /* malloc'ed array */
@@ -638,6 +726,7 @@ termStack(struct stack * const stackP) {
     stackP->stack = NULL;
 }
 
+    
 
 /*----------------------------------------------------------------------------
    Some notes on LZW.
@@ -657,7 +746,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.
 
@@ -694,7 +783,7 @@ struct decompressor {
         */
     int      next_tableSlot;
         /* Index in the code translation table of the next free entry */
-    int      firstcode;
+    unsigned int firstcode;
         /* This is always a true data element code */
     int      prevcode;
         /* The code just before, in the image, the one we're processing now */
@@ -759,7 +848,7 @@ lzwInit(struct decompressor * const decompP,
     }
     resetDecompressor(decompP);
 
-    getCode(decompP->ifP, 0, TRUE);
+    getCode_init(&getCodeState);
     
     decompP->fresh = TRUE;
     
@@ -779,7 +868,7 @@ lzwTerm(struct decompressor * const decompP) {
 static void
 expandCodeOntoStack(struct decompressor * const decompP,
                     int                   const incode,
-                    bool *                const errorP) {
+                    const char **         const errorP) {
 /*----------------------------------------------------------------------------
    'incode' is an LZW string code.  It represents a string of true data
    elements, as defined by the string translation table in *decompP.
@@ -790,12 +879,13 @@ expandCodeOntoStack(struct decompressor * const decompP,
    Also add to the translation table where appropriate.
 
    Iff the translation table contains a cycle (which means the LZW stream
-   from which it was built is invalid), return *errorP == TRUE.
+   from which it was built is invalid), fail (return text explanation
+   as *errorP).
 -----------------------------------------------------------------------------*/
     int code;
-    bool error;
+    const char * error;
 
-    error = FALSE;
+    error = NULL; /* Initial value */
 
     if (incode < decompP->next_tableSlot) 
         code = incode;
@@ -810,15 +900,15 @@ 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;
 
         while (code > decompP->max_dataVal && !error) {
             if (stringCount > maxnum_lzwCode) {
-                pm_message("Error in GIF image: contains LZW string loop");
-                error = TRUE;
+                asprintfN(&error,
+                          "Error in GIF image: contains LZW string loop");
             } else {
                 ++stringCount;
                 pushStack(&decompP->stack, decompP->table[1][code]);
@@ -847,78 +937,106 @@ expandCodeOntoStack(struct decompressor * const decompP,
         }
     }
 
-    decompP->prevcode = incode;
     *errorP = error;
+
+    decompP->prevcode = incode;
 }
 
 
 
-static int
-lzwReadByte(struct decompressor * const decompP) {
+static void
+lzwReadByteFresh(struct getCodeState * const getCodeStateP,
+                 struct decompressor * const decompP,
+                 bool *                const endOfImageP,
+                 unsigned int *        const dataReadP,
+                 const char **         const errorP) {
+                     
+    /* Read off all initial clear codes, read the first non-clear code,
+       and return it.  There are no strings in the table yet, so the next
+       code must be a direct true data code.
+    */
+    bool eof;
+    do {
+        getCode_get(getCodeStateP, decompP->ifP, decompP->codeSize,
+                    &eof, &decompP->firstcode, errorP);
+        decompP->prevcode = decompP->firstcode;
+    } while (decompP->firstcode == decompP->clear_code && !*errorP && !eof);
+
+    if (!*errorP) {
+        if (eof)
+            *endOfImageP = TRUE;
+        else if (decompP->firstcode == decompP->end_code) {
+            if (!zeroDataBlock)
+                readThroughEod(decompP->ifP);
+            *endOfImageP = TRUE;
+        } else {
+            *endOfImageP = FALSE;
+            *dataReadP = decompP->firstcode;
+        }
+    }
+}
+
+
+
+static void
+lzwReadByte(struct decompressor * const decompP,
+            unsigned int *        const dataReadP,
+            bool *                const endOfImageP,
+            const char **         const errorP) {
 /*----------------------------------------------------------------------------
   Return the next data element of the decompressed image.  In the context
   of a GIF, a data element is the color table index of one pixel.
 
-  We read and return the next byte of the decompressed image, or:
+  We read and return the next byte of the decompressed image.
 
-    Return -1 if we hit EOF prematurely (i.e. before an "end" code.  We
-    forgive the case that the "end" code is followed by EOF instead of
-    an EOD marker (zero length DataBlock)).
+  If we can't, because the stream is too corrupted to make sense out of
+  it or the stream ends, we fail (return text description of why as
+  *errorP).
 
-    Return -2 if there are no more bytes in the image.  In that case,
-    make sure the file is positioned immediately after the image (i.e.
-    after the EOD marker that marks the end of the image or EOF).
+  We forgive the case that the "end" code is the end of the stream --
+  not followed by an EOD marker (zero length DataBlock).
 
-    Return -3 if we encounter errors in the LZW stream.
+  Iff we can't read a byte because we've hit the end of the image,
+  we return *endOfImageP = true.
 -----------------------------------------------------------------------------*/
-    int retval;
-
-    if (!stackIsEmpty(&decompP->stack))
-        retval = popStack(&decompP->stack);
-    else if (decompP->fresh) {
+    if (!stackIsEmpty(&decompP->stack)) {
+        *errorP = NULL;
+        *endOfImageP = FALSE;
+        *dataReadP = popStack(&decompP->stack);
+    } else if (decompP->fresh) {
         decompP->fresh = FALSE;
-        /* Read off all initial clear codes, read the first non-clear code,
-           and return it.  There are no strings in the table yet, so the next
-           code must be a direct true data code.
-        */
-        do {
-            decompP->firstcode =
-                getCode(decompP->ifP, decompP->codeSize, FALSE);
-            decompP->prevcode = decompP->firstcode;
-        } while (decompP->firstcode == decompP->clear_code);
-        if (decompP->firstcode == decompP->end_code) {
-            if (!zeroDataBlock)
-                readThroughEod(decompP->ifP);
-            retval = -2;
-        } else
-            retval = decompP->firstcode;
+
+        lzwReadByteFresh(&getCodeState, decompP, endOfImageP, dataReadP,
+                         errorP);
     } else {
-        int code;
-        code = getCode(decompP->ifP, decompP->codeSize, FALSE);
-        if (code == -1)
-            retval = -1;
-        else {
-            assert(code >= 0);  /* -1 is only possible error return */
-            if (code == decompP->clear_code) {
-                resetDecompressor(decompP);
-                retval = lzwReadByte(decompP);
-            } else {
-                if (code == decompP->end_code) {
-                    if (!zeroDataBlock)
-                        readThroughEod(decompP->ifP);
-                    retval = -2;
+        unsigned int code;
+        bool eof;
+        getCode_get(&getCodeState, decompP->ifP, decompP->codeSize,
+                    &eof, &code, errorP);
+        if (!*errorP) {
+            if (eof)
+                asprintfN(errorP,
+                          "Premature end of file; no proper GIF closing");
+            else {
+                if (code == decompP->clear_code) {
+                    resetDecompressor(decompP);
+                    lzwReadByte(decompP, dataReadP, endOfImageP, errorP);
                 } else {
-                    bool error;
-                    expandCodeOntoStack(decompP, code, &error);
-                    if (error)
-                        retval = -3;
-                    else
-                        retval = popStack(&decompP->stack);
+                    if (code == decompP->end_code) {
+                        if (!zeroDataBlock)
+                            readThroughEod(decompP->ifP);
+                        *endOfImageP = TRUE;
+                        *errorP = NULL;
+                    } else {
+                        *endOfImageP = FALSE;
+                        expandCodeOntoStack(decompP, code, errorP);
+                        if (!*errorP)
+                            *dataReadP = popStack(&decompP->stack);
+                    }
                 }
             }
         }
     }
-    return retval;
 }
 
 
@@ -1027,6 +1145,124 @@ addPixelToRaster(unsigned int       const cmapIndex,
 
 
 static void
+verifyPixelRead(bool          const endOfImage,
+                const char *  const readError,
+                unsigned int  const cols,
+                unsigned int  const rows,
+                unsigned int  const failedRowNum,
+                const char ** const errorP) {
+
+    if (readError)
+        *errorP = strdup(readError);
+    else {
+        if (endOfImage)
+            asprintfN(errorP,
+                      "Error in GIF image: Not enough raster data to fill "
+                      "%u x %u dimensions.  Ran out of raster data in "
+                      "row %u.  The image has proper ending sequence, so "
+                      "this is not just a truncated file.",
+                      cols, rows, failedRowNum);
+        else
+            *errorP = NULL;
+    }
+}
+
+
+
+static void
+readRaster(struct decompressor * const decompP,
+           xel **                const xels, 
+           unsigned int          const cols,
+           unsigned int          const rows,
+           gifColorMap                 cmap, 
+           unsigned int          const cmapSize,
+           bool                  const interlace,
+           int                   const transparentIndex,
+           bit **                const alphabits,
+           bool                  const tolerateBadInput) {
+                   
+    struct pnmBuffer pnmBuffer;
+    enum pass pass;
+    bool fillingMissingPixels;
+
+    pass = MULT8PLUS0;
+    pnmBuffer.xels = xels;
+    pnmBuffer.col  = 0;
+    pnmBuffer.row  = 0;
+    fillingMissingPixels = false;  /* initial value */
+
+    while (pnmBuffer.row < rows) {
+        unsigned int colorIndex;
+
+        if (fillingMissingPixels)
+            colorIndex = 0;
+        else {
+            const char * error;
+
+            const char * readError;
+            unsigned int readColorIndex;
+            bool endOfImage;
+
+            lzwReadByte(decompP, &readColorIndex, &endOfImage, &readError);
+
+            verifyPixelRead(endOfImage, readError, cols, rows, pnmBuffer.row,
+                            &error);
+
+            if (readError)
+                strfree(readError);
+
+            if (error) {
+                if (tolerateBadInput) {
+                    pm_message("WARNING: %s.  "
+                               "Filling bottom %u rows with arbitrary color",
+                               error, rows - pnmBuffer.row);
+                    fillingMissingPixels = true;
+                } else
+                    pm_error("Unable to read input image.  %s.  Use the "
+                             "-repair option to try to salvage some of "
+                             "the image",
+                             error);
+
+                colorIndex = 0;
+            } else
+                colorIndex = readColorIndex;
+        }
+        addPixelToRaster(colorIndex, &pnmBuffer, cols, rows, cmap, cmapSize,
+                         interlace, transparentIndex, alphabits, &pass);
+    }
+}
+
+
+
+static void
+skipExtraneousData(struct decompressor * const decompP) {
+
+    unsigned int byteRead;
+    bool endOfImage;
+    const char * error;
+
+    lzwReadByte(decompP, &byteRead, &endOfImage, &error);
+
+    if (error)
+        strfree(error);
+    else if (!endOfImage) {
+        pm_message("Extraneous data at end of image.  "
+                   "Skipped to end of image");
+
+        while (!endOfImage && !error)
+            lzwReadByte(decompP, &byteRead, &endOfImage, &error);
+
+        if (error) {
+            pm_message("Error encountered skipping to end of image: %s",
+                       error);
+            strfree(error);
+        }
+    }
+}
+
+
+
+static void
 readImageData(FILE *       const ifP, 
               xel **       const xels, 
               unsigned int const cols,
@@ -1035,20 +1271,13 @@ readImageData(FILE *       const ifP,
               unsigned int const cmapSize,
               bool         const interlace,
               int          const transparentIndex,
-              bit **       const alphabits) {
+              bit **       const alphabits,
+              bool         const tolerateBadInput) {
 
     unsigned char lzwMinCodeSize;      
-    enum pass pass;
     struct decompressor decomp;
-    struct pnmBuffer pnmBuffer;
     bool gotMinCodeSize;
 
-    pass = MULT8PLUS0;
-
-    pnmBuffer.xels = xels;
-    pnmBuffer.col  = 0;
-    pnmBuffer.row  = 0;
-
     gotMinCodeSize =  ReadOK(ifP, &lzwMinCodeSize, 1);
     if (!gotMinCodeSize)
         pm_error("GIF stream ends (or read error) "
@@ -1062,29 +1291,10 @@ readImageData(FILE *       const ifP,
 
     lzwInit(&decomp, ifP, lzwMinCodeSize);
 
-    while (pnmBuffer.row < rows) {
-        int const rc = lzwReadByte(&decomp);
+    readRaster(&decomp, xels, cols, rows, cmap, cmapSize, interlace,
+               transparentIndex, alphabits, tolerateBadInput);
 
-        switch (rc) {
-        case -3:
-            pm_error("Error in GIF input stream");
-            break;
-        case -2:
-            pm_error("Error in GIF image: Not enough raster data to fill "
-                     "%u x %u dimensions.  Ran out of raster data in "
-                     "row %u", cols, rows, pnmBuffer.row);
-            break;
-        case -1:
-            pm_error("Premature end of file; no proper GIF closing");
-            break;
-        default:
-            addPixelToRaster(rc, &pnmBuffer, cols, rows, cmap, cmapSize,
-                             interlace, transparentIndex, alphabits, &pass);
-        }
-    }
-    if (lzwReadByte(&decomp) >= 0)
-        pm_message("Extraneous data at end of image.  "
-                   "Skipped to end of image");
+    skipExtraneousData(&decomp);
 
     lzwTerm(&decomp);
 }
@@ -1092,33 +1302,36 @@ readImageData(FILE *       const ifP,
 
 
 static void
-writePnm(FILE *outfile, xel ** const xels, 
-         const int cols, const int rows,
-         const int hasGray, const int hasColor) {
+writePnm(FILE * const outfileP,
+         xel ** const xels, 
+         int    const cols,
+         int    const rows,
+         int    const hasGray,
+         int    const hasColor) {
 /*----------------------------------------------------------------------------
-   Write a PNM image to the current position of file 'outfile' with
+   Write a PNM image to the current position of file *outfileP with
    dimensions 'cols' x 'rows' and raster 'xels'.
    
    Make it PBM, PGM, or PBM according to 'hasGray' and 'hasColor'.
 -----------------------------------------------------------------------------*/
     int format;
-    const char *format_name;
+    const char * formatName;
            
     if (hasColor) {
         format = PPM_FORMAT;
-        format_name = "PPM";
+        formatName = "PPM";
     } else if (hasGray) {
         format = PGM_FORMAT;
-        format_name = "PGM";
+        formatName = "PGM";
     } else {
         format = PBM_FORMAT;
-        format_name = "PBM";
+        formatName = "PBM";
     }
     if (verbose) 
-        pm_message("writing a %s file", format_name);
+        pm_message("writing a %s file", formatName);
     
-    if (outfile) 
-        pnm_writepnm(outfile, xels, cols, rows,
+    if (outfileP) 
+        pnm_writepnm(outfileP, xels, cols, rows,
                      (xelval) GIFMAXVAL, format, FALSE);
 }
 
@@ -1172,7 +1385,7 @@ readGifHeader(FILE * const gifFile, struct gifScreen * const gifScreenP) {
     if (verbose)
         pm_message("GIF format version is '%s'", version);
     
-    if ((!STREQ(version, "87a")) && (!STREQ(version, "89a")))
+    if ((!streq(version, "87a")) && (!streq(version, "89a")))
         pm_error("bad version number, not '87a' or '89a'" );
     
     if (! ReadOK(gifFile,buf,7))
@@ -1223,7 +1436,8 @@ readGifHeader(FILE * const gifFile, struct gifScreen * const gifScreenP) {
 static void
 readExtensions(FILE*          const ifP, 
                struct gif89 * const gif89P,
-               bool *         const eodP) {
+               bool *         const eodP,
+               const char **  const errorP) {
 /*----------------------------------------------------------------------------
    Read extension blocks from the GIF stream to which the file *ifP is
    positioned.  Read up through the image separator that begins the
@@ -1232,33 +1446,50 @@ readExtensions(FILE*          const ifP,
    If we encounter EOD (end of GIF stream) before we find an image 
    separator, we return *eodP == TRUE.  Else *eodP == FALSE.
 
-   If we hit end of file before an EOD marker, we abort the program with
-   an error message.
+   If we hit end of file before an EOD marker, we fail.
 -----------------------------------------------------------------------------*/
     bool imageStart;
     bool eod;
 
+    *errorP = NULL;  /* initial value */
+
     eod = FALSE;
     imageStart = FALSE;
 
     /* Read the image descriptor */
-    while (!imageStart && !eod) {
+    while (!imageStart && !eod && !*errorP) {
         unsigned char c;
+        const char * error;
 
-        if (! ReadOK(ifP,&c,1))
-            pm_error("EOF / read error on image data" );
+        readFile(ifP, &c, 1, &error);
 
-        if (c == ';') {         /* GIF terminator */
-            eod = TRUE;
-        } else if (c == '!') {         /* Extension */
-            if (! ReadOK(ifP,&c,1))
-                pm_error("EOF / "
-                         "read error on extension function code");
-            doExtension(ifP, c, gif89P);
-        } else if (c == ',') 
-            imageStart = TRUE;
-        else 
-            pm_message("bogus character 0x%02x, ignoring", (int) c );
+        if (error) {
+            asprintfN(errorP, "File read error where start of image "
+                      "descriptor or end of GIF expected.  %s",
+                      error);
+            strfree(error);
+        } else {
+            if (c == ';') {         /* GIF terminator */
+                eod = TRUE;
+            } else if (c == '!') {         /* Extension */
+                unsigned char functionCode;
+                const char * error;
+
+                readFile(ifP, &functionCode, 1, &error);
+
+                if (error) {
+                    asprintfN(errorP, "Failed to read function code "
+                              "of GIF extension (immediately after the '!' "
+                              "extension delimiter) from input.  %s", error);
+                    strfree(error);
+                } else {
+                    doExtension(ifP, functionCode, gif89P);
+                }
+            } else if (c == ',') 
+                imageStart = TRUE;
+            else 
+                pm_message("bogus character 0x%02x, ignoring", (int)c);
+        }
     }
     *eodP = eod;
 }
@@ -1272,9 +1503,9 @@ reportImageInfo(unsigned int const cols,
                 unsigned int const localColorMapSize,
                 bool         const interlaced) {
 
-
     pm_message("reading %u by %u%s GIF image",
                cols, rows, interlaced ? " interlaced" : "" );
+
     if (useGlobalColormap)
         pm_message("  Uses global colormap");
     else
@@ -1289,7 +1520,8 @@ convertImage(FILE *           const ifP,
              FILE *           const imageout_file, 
              FILE *           const alphafile, 
              struct gifScreen       gifScreen,
-             struct gif89     const gif89) {
+             struct gif89     const gif89,
+             bool             const tolerateBadInput) {
 /*----------------------------------------------------------------------------
    Read a single GIF image from the current position of file 'ifP'.
 
@@ -1340,7 +1572,8 @@ convertImage(FILE *           const ifP,
                      &hasGray, &hasColor);
         transparencyMessage(gif89.transparent, localColorMap);
         readImageData(ifP, xels, cols, rows, localColorMap, localColorMapSize,
-                      interlaced, gif89.transparent, alphabits);
+                      interlaced, gif89.transparent, alphabits,
+                      tolerateBadInput);
         if (!skipIt) {
             writePnm(imageout_file, xels, cols, rows,
                      hasGray, hasColor);
@@ -1349,7 +1582,8 @@ convertImage(FILE *           const ifP,
         transparencyMessage(gif89.transparent, gifScreen.ColorMap);
         readImageData(ifP, xels, cols, rows, 
                       gifScreen.ColorMap, gifScreen.ColorMapSize,
-                      interlaced, gif89.transparent, alphabits);
+                      interlaced, gif89.transparent, alphabits,
+                      tolerateBadInput);
         if (!skipIt) {
             writePnm(imageout_file, xels, cols, rows,
                      gifScreen.hasGray, gifScreen.hasColor);
@@ -1367,12 +1601,33 @@ convertImage(FILE *           const ifP,
 
 
 static void
+disposeOfReadExtensionsError(const char * const error,
+                             bool         const tolerateBadInput,
+                             unsigned int const imageSeq,
+                             bool *       const eodP) {
+    if (error) {
+        if (tolerateBadInput)
+            pm_message("Error accessing Image %u of stream; no further "
+                       "images can be accessed.  %s",
+                       imageSeq, error);
+        else
+            pm_error("Error accessing Image %u of stream.  %s",
+                     imageSeq, error);
+        strfree(error);
+        *eodP = TRUE;
+    }
+}
+
+
+
+static void
 convertImages(FILE * const ifP, 
               bool   const allImages,
               int    const requestedImageSeq, 
               bool   const drainStream,
               FILE * const imageout_file, 
-              FILE * const alphafile) {
+              FILE * const alphafile,
+              bool   const tolerateBadInput) {
 /*----------------------------------------------------------------------------
    Read a GIF stream from file 'ifP' and write one or more images from
    it as PNM images to file 'imageout_file'.  If the images have transparency
@@ -1407,20 +1662,25 @@ convertImages(FILE * const ifP,
          !eod && (imageSeq <= requestedImageSeq || allImages || drainStream);
          ++imageSeq) {
 
-        readExtensions(ifP, &gif89, &eod);
+        const char * error;
+
+        readExtensions(ifP, &gif89, &eod, &error);
+
+        disposeOfReadExtensionsError(error, tolerateBadInput, imageSeq, &eod);
 
         if (eod) {
             /* GIF stream ends before image with sequence imageSeq */
             if (!allImages && (imageSeq <= requestedImageSeq))
                 pm_error("You requested Image %d, but "
                          "only %d image%s found in GIF stream",
-                         requestedImageSeq+1,
-                         imageSeq, imageSeq>1?"s":"" );
+                         requestedImageSeq + 1,
+                         imageSeq, imageSeq > 1 ? "s" : "");
         } else {
             if (verbose)
                 pm_message("Reading Image Sequence %d", imageSeq);
             convertImage(ifP, !allImages && (imageSeq != requestedImageSeq), 
-                         imageout_file, alphafile, gifScreen, gif89);
+                         imageout_file, alphafile, gifScreen, gif89,
+                         tolerateBadInput);
         }
     }
 }
@@ -1447,19 +1707,20 @@ main(int argc, char **argv) {
     else
         alpha_file = pm_openw(cmdline.alpha_filename);
 
-    if (alpha_file && STREQ(cmdline.alpha_filename, "-"))
+    if (alpha_file && streq(cmdline.alpha_filename, "-"))
         imageout_file = NULL;
     else
         imageout_file = stdout;
 
     convertImages(ifP, cmdline.all_images, cmdline.image_no, 
-                  !cmdline.quitearly, imageout_file, alpha_file);
+                  !cmdline.quitearly, imageout_file, alpha_file,
+                  cmdline.repair);
 
     pm_close(ifP);
     if (imageout_file != NULL) 
-        pm_close( imageout_file );
+        pm_close(imageout_file);
     if (alpha_file != NULL)
-        pm_close( alpha_file );
+        pm_close(alpha_file);
 
     return 0;
 }
diff --git a/converter/other/hdifftopam.c b/converter/other/hdifftopam.c
index 444d6068..7bfeed9b 100644
--- a/converter/other/hdifftopam.c
+++ b/converter/other/hdifftopam.c
@@ -9,6 +9,7 @@
 #include <string.h>
 #include <stdio.h>
 
+#include "pm_c_util.h"
 #include "pam.h"
 #include "shhopt.h"
 #include "nstring.h"
@@ -96,7 +97,7 @@ main(int argc, char *argv[]) {
     tuple * outrow;
     tuple * prevrow;
 
-    pnm_init( &argc, argv );
+    pnm_init(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
@@ -106,7 +107,7 @@ main(int argc, char *argv[]) {
 
     if (diffpam.format != PAM_FORMAT) 
         pm_error("Input must be a PAM file, not PNM");
-    else if (!STREQ(diffpam.tuple_type, "hdiff")) 
+    else if (!streq(diffpam.tuple_type, "hdiff")) 
         pm_error("Input tuple type is '%s'.  Must be 'hdiff'",
                  diffpam.tuple_type);
 
diff --git a/converter/other/infotopam.c b/converter/other/infotopam.c
index 4f29eb07..21fa8ee2 100644
--- a/converter/other/infotopam.c
+++ b/converter/other/infotopam.c
@@ -65,6 +65,7 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
+#include "pm_c_util.h"
 #include "pam.h"
 #include "shhopt.h"
 #include "mallocvar.h"
diff --git a/converter/other/jbig/Makefile b/converter/other/jbig/Makefile
index 1b9d7535..b5f4e14a 100644
--- a/converter/other/jbig/Makefile
+++ b/converter/other/jbig/Makefile
@@ -5,13 +5,13 @@ endif
 SUBDIR = converter/other/jbig
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
 LIBJBIG_OBJECTS = jbig.o jbig_tab.o
 
-INCLUDES =
+EXTERN_INCLUDES =
 ifneq ($(JBIGHDR_DIR),NONE)
-  INCLUDES += -I$(JBIGHDR_DIR)
+  EXTERN_INCLUDES += -I$(JBIGHDR_DIR)
 endif
 
 ifneq ($(JBIGHDR_DIR),NONE)
@@ -33,7 +33,7 @@ MERGE_OBJECTS = $(BINARIES:%=%.o2) $(LIBJBIG_OBJECTS)
 
 all: $(BINARIES)
 
-include $(SRCDIR)/Makefile.common
+include $(SRCDIR)/common.mk
 
 $(BINARIES): %: %.o $(JBIGLIB_DEP) $(NETPBMLIB) $(LIBOPT)
 	$(LD) -o $@ $< \
diff --git a/converter/other/jpeg2000/Makefile b/converter/other/jpeg2000/Makefile
index bf3f5e4a..f4fee87f 100644
--- a/converter/other/jpeg2000/Makefile
+++ b/converter/other/jpeg2000/Makefile
@@ -7,11 +7,11 @@ VPATH=.:$(SRCDIR)/$(SUBDIR)
 
 SUBDIRS = libjasper
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
-INCLUDES =
+EXTERN_INCLUDES =
 ifneq ($(JASPERHDR_DIR),NONE)
-  INCLUDES += -I$(JASPERHDR_DIR)
+  EXTERN_INCLUDES += -I$(JASPERHDR_DIR)
 endif
 
 
@@ -55,7 +55,7 @@ MERGEBINARIES = $(BINARIES)
 .PHONY: all
 all: $(BINARIES)
 
-include $(SRCDIR)/Makefile.common
+include $(SRCDIR)/common.mk
 
 LIBOPTS = $(shell $(LIBOPT) $(NETPBMLIB) $(JASPERLIB_USE))
 
diff --git a/converter/other/jpeg2000/jpeg2ktopam.c b/converter/other/jpeg2000/jpeg2ktopam.c
index e11e9fb4..e6db7658 100644
--- a/converter/other/jpeg2000/jpeg2ktopam.c
+++ b/converter/other/jpeg2000/jpeg2ktopam.c
@@ -13,6 +13,7 @@
 #define _XOPEN_SOURCE 600
 #include <string.h>
 
+#include "pm_c_util.h"
 #include "pam.h"
 #include "shhopt.h"
 #include "nstring.h"
diff --git a/converter/other/jpeg2000/libjasper/Makefile b/converter/other/jpeg2000/libjasper/Makefile
index 965f15ad..ddbd148a 100644
--- a/converter/other/jpeg2000/libjasper/Makefile
+++ b/converter/other/jpeg2000/libjasper/Makefile
@@ -5,7 +5,7 @@ endif
 SUBDIR = converter/other/jpeg2000/libjasper
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
 SUBDIRS = base jp2 jpc
 LIB_OBJECTS =
@@ -17,7 +17,7 @@ JASPERSRCDIR = $(SRCDIR)/$(SUBDIR)
 
 all: libjasper.a
 
-include $(SRCDIR)/$(SUBDIR)/Makefile.common
+include $(SRCDIR)/$(SUBDIR)/common.mk
 
 # We cheat a bit here -- the real dependencies are all the .o files listed
 # in the part list, but since we don't know what those are, we just do a
diff --git a/converter/other/jpeg2000/libjasper/base/Makefile b/converter/other/jpeg2000/libjasper/base/Makefile
index 0ee65b5e..ad84f043 100644
--- a/converter/other/jpeg2000/libjasper/base/Makefile
+++ b/converter/other/jpeg2000/libjasper/base/Makefile
@@ -7,7 +7,7 @@ VPATH=.:$(SRCDIR)/$(SUBDIR)
 
 JASPERSRCDIR=$(SRCDIR)/$(SUBDIR)/..
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
 LIB_OBJECTS = jas_debug.o jas_getopt.o jas_image.o jas_init.o \
 	      jas_malloc.o jas_seq.o jas_stream.o jas_string.o \
@@ -17,5 +17,5 @@ MERGE_OBJECTS =
 
 all: partlist $(LIB_OBJECTS)
 
-include $(JASPERSRCDIR)/Makefile.common
+include $(JASPERSRCDIR)/common.mk
 
diff --git a/converter/other/jpeg2000/libjasper/base/jas_stream.c b/converter/other/jpeg2000/libjasper/base/jas_stream.c
index f450aabf..4c84e6c2 100644
--- a/converter/other/jpeg2000/libjasper/base/jas_stream.c
+++ b/converter/other/jpeg2000/libjasper/base/jas_stream.c
@@ -130,6 +130,8 @@
 #include <io.h>
 #endif
 
+#include "pm.h"
+
 #include "jasper/jas_types.h"
 #include "jasper/jas_stream.h"
 #include "jasper/jas_malloc.h"
@@ -380,51 +382,6 @@ jas_stream_t *jas_stream_freopen(const char *path, const char *mode, FILE *fp)
 }
 
 
-static int
-tmpfilex(void) {
-/*----------------------------------------------------------------------------
-   This is a copy of pm_tmpfile() without the libnetpbm dependencies
-   and returning a file descriptor instead of stream.
------------------------------------------------------------------------------*/
-    const char libname[] = "jasper";
-
-    int fd;
-    char buf[FILENAME_MAX];
-    const char * tbuf;
-    unsigned int fnamelen;
-
-    fnamelen = strlen(libname) + 10; /* "/" + "_XXXXXX\0" */
-
-    tbuf = getenv("TMPDIR");
-
-    if ((tbuf != NULL) && (strlen(tbuf) > FILENAME_MAX - fnamelen))
-        /* length of TMPDIR value too big for buf */
-        tbuf = NULL;
-
-    buf[FILENAME_MAX - fnamelen -1] = 0;
-
-    if ((tbuf == NULL) || (strlen(tbuf) == 0))
-        /* environment variable not suitable to construct file name.
-           Use default.
-        */
-        strncpy(buf, TMPDIR, sizeof(buf) - fnamelen);
-    else
-        strncpy(buf, tbuf, sizeof(buf) - fnamelen);
-
-    if (buf[strlen(buf) - 1] != '/')
-        strcat (buf, "/");
-    
-    strcat(buf, libname);
-    strcat(buf, "_XXXXXX");
-
-    fd = mkstemp(buf);
-
-    if (fd >= 0)
-        unlink(buf);
-
-    return fd;
-}
-
 jas_stream_t *jas_stream_tmpfile()
 {
 	jas_stream_t *stream;
@@ -444,13 +401,23 @@ jas_stream_t *jas_stream_tmpfile()
 		return 0;
 	}
 	stream->obj_ = obj;
-    
-    /* This is a Netpbm enhancement.  Original Jasper library uses
-       tmpnam(), which is unsafe.
-    */
-    if ((*obj = tmpfilex()) < 0) {
-		jas_stream_destroy(stream);
-		return 0;
+
+    {
+        /* This is a Netpbm enhancement.  Original Jasper library uses
+           tmpnam(), which is unsafe.
+        */
+        jmp_buf jmpbuf;
+        int rc;
+        
+        rc = setjmp(jmpbuf);
+        if (rc == 0) {
+            pm_setjmpbuf(&jmpbuf);
+            *obj = pm_tmpfile_fd();
+        } else {
+            /* pm_tmpfile_fd() threw an error */
+            jas_stream_destroy(stream);
+            return 0;
+        }
     }
 	/* Use full buffering. */
 	jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
diff --git a/converter/other/jpeg2000/libjasper/Makefile.common b/converter/other/jpeg2000/libjasper/common.mk
index 525e9c2d..687a9f3f 100644
--- a/converter/other/jpeg2000/libjasper/Makefile.common
+++ b/converter/other/jpeg2000/libjasper/common.mk
@@ -1,4 +1,3 @@
-# -*-makefile-*-    <-- an Emacs control
 # This is common rules for the libjasper subdirectories.
 #
 # Set the following variables before including this:
@@ -19,14 +18,14 @@ $(SUBDIRS:%=%/partlist): %/partlist: $(CURDIR)/%
 	$(MAKE) -C $(dir $@) -f $(SRCDIR)/$(SUBDIR)/$(dir $@)Makefile \
 	    SRCDIR=$(SRCDIR) BUILDDIR=$(BUILDDIR) $(notdir $@) 
 
-INCLUDES = -I$(JASPERSRCDIR)/include -Iimportinc
+include $(SRCDIR)/common.mk
 
-include $(SRCDIR)/Makefile.common
+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 $(INCLUDES) $(DEFS) $(CFLAGS) $(CADD) $<
+	$(CC) -c $(INCLUDES) $(DEFS) $(CPPFLAGS) $(CFLAGS) $(CADD) $<
 
 $(LIB_OBJECTS): importinc
 
diff --git a/converter/other/jpeg2000/libjasper/include/jasper/jas_types.h.orig b/converter/other/jpeg2000/libjasper/include/jasper/jas_types.h.orig
new file mode 100644
index 00000000..10c1152d
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/include/jasper/jas_types.h.orig
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 1999-2000 Image Power, Inc. and the University of
+ *   British Columbia.
+ * Copyright (c) 2001-2002 Michael David Adams.
+ * All rights reserved.
+ */
+
+/* __START_OF_JASPER_LICENSE__
+ * 
+ * JasPer Software License
+ * 
+ * IMAGE POWER JPEG-2000 PUBLIC LICENSE
+ * ************************************
+ * 
+ * GRANT:
+ * 
+ * Permission is hereby granted, free of charge, to any person (the "User")
+ * obtaining a copy of this software and associated documentation, to deal
+ * in the JasPer Software without restriction, including without limitation
+ * the right to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the JasPer Software (in source and binary forms),
+ * and to permit persons to whom the JasPer Software is furnished to do so,
+ * provided further that the License Conditions below are met.
+ * 
+ * License Conditions
+ * ******************
+ * 
+ * A.  Redistributions of source code must retain the above copyright notice,
+ * and this list of conditions, and the following disclaimer.
+ * 
+ * B.  Redistributions in binary form must reproduce the above copyright
+ * notice, and this list of conditions, and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution.
+ * 
+ * C.  Neither the name of Image Power, Inc. nor any other contributor
+ * (including, but not limited to, the University of British Columbia and
+ * Michael David Adams) may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * 
+ * D.  User agrees that it shall not commence any action against Image Power,
+ * Inc., the University of British Columbia, Michael David Adams, or any
+ * other contributors (collectively "Licensors") for infringement of any
+ * intellectual property rights ("IPR") held by the User in respect of any
+ * technology that User owns or has a right to license or sublicense and
+ * which is an element required in order to claim compliance with ISO/IEC
+ * 15444-1 (i.e., JPEG-2000 Part 1).  "IPR" means all intellectual property
+ * rights worldwide arising under statutory or common law, and whether
+ * or not perfected, including, without limitation, all (i) patents and
+ * patent applications owned or licensable by User; (ii) rights associated
+ * with works of authorship including copyrights, copyright applications,
+ * copyright registrations, mask work rights, mask work applications,
+ * mask work registrations; (iii) rights relating to the protection of
+ * trade secrets and confidential information; (iv) any right analogous
+ * to those set forth in subsections (i), (ii), or (iii) and any other
+ * proprietary rights relating to intangible property (other than trademark,
+ * trade dress, or service mark rights); and (v) divisions, continuations,
+ * renewals, reissues and extensions of the foregoing (as and to the extent
+ * applicable) now existing, hereafter filed, issued or acquired.
+ * 
+ * E.  If User commences an infringement action against any Licensor(s) then
+ * such Licensor(s) shall have the right to terminate User's license and
+ * all sublicenses that have been granted hereunder by User to other parties.
+ * 
+ * F.  This software is for use only in hardware or software products that
+ * are compliant with ISO/IEC 15444-1 (i.e., JPEG-2000 Part 1).  No license
+ * or right to this Software is granted for products that do not comply
+ * with ISO/IEC 15444-1.  The JPEG-2000 Part 1 standard can be purchased
+ * from the ISO.
+ * 
+ * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.
+ * NO USE OF THE JASPER SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER
+ * THIS DISCLAIMER.  THE JASPER SOFTWARE IS PROVIDED BY THE LICENSORS AND
+ * CONTRIBUTORS UNDER THIS LICENSE ON AN ``AS-IS'' BASIS, WITHOUT WARRANTY
+ * OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION,
+ * WARRANTIES THAT THE JASPER SOFTWARE IS FREE OF DEFECTS, IS MERCHANTABLE,
+ * IS FIT FOR A PARTICULAR PURPOSE OR IS NON-INFRINGING.  THOSE INTENDING
+ * TO USE THE JASPER SOFTWARE OR MODIFICATIONS THEREOF FOR USE IN HARDWARE
+ * OR SOFTWARE PRODUCTS ARE ADVISED THAT THEIR USE MAY INFRINGE EXISTING
+ * PATENTS, COPYRIGHTS, TRADEMARKS, OR OTHER INTELLECTUAL PROPERTY RIGHTS.
+ * THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE JASPER SOFTWARE
+ * IS WITH THE USER.  SHOULD ANY PART OF THE JASPER SOFTWARE PROVE DEFECTIVE
+ * IN ANY RESPECT, THE USER (AND NOT THE INITIAL DEVELOPERS, THE UNIVERSITY
+ * OF BRITISH COLUMBIA, IMAGE POWER, INC., MICHAEL DAVID ADAMS, OR ANY
+ * OTHER CONTRIBUTOR) SHALL ASSUME THE COST OF ANY NECESSARY SERVICING,
+ * REPAIR OR CORRECTION.  UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY,
+ * WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL THE
+ * INITIAL DEVELOPER, THE UNIVERSITY OF BRITISH COLUMBIA, IMAGE POWER, INC.,
+ * MICHAEL DAVID ADAMS, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF THE
+ * JASPER SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO
+ * THE USER OR ANY OTHER PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
+ * CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION,
+ * DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR
+ * MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF
+ * SUCH PARTY HAD BEEN INFORMED, OR OUGHT TO HAVE KNOWN, OF THE POSSIBILITY
+ * OF SUCH DAMAGES.  THE JASPER SOFTWARE AND UNDERLYING TECHNOLOGY ARE NOT
+ * FAULT-TOLERANT AND ARE NOT DESIGNED, MANUFACTURED OR INTENDED FOR USE OR
+ * RESALE AS ON-LINE CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING
+ * FAIL-SAFE PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES,
+ * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT
+ * LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
+ * JASPER SOFTWARE OR UNDERLYING TECHNOLOGY OR PRODUCT COULD LEAD DIRECTLY
+ * TO DEATH, PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE
+ * ("HIGH RISK ACTIVITIES").  LICENSOR SPECIFICALLY DISCLAIMS ANY EXPRESS
+ * OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES.  USER WILL NOT
+ * KNOWINGLY USE, DISTRIBUTE OR RESELL THE JASPER SOFTWARE OR UNDERLYING
+ * TECHNOLOGY OR PRODUCTS FOR HIGH RISK ACTIVITIES AND WILL ENSURE THAT ITS
+ * CUSTOMERS AND END-USERS OF ITS PRODUCTS ARE PROVIDED WITH A COPY OF THE
+ * NOTICE SPECIFIED IN THIS SECTION.
+ * 
+ * __END_OF_JASPER_LICENSE__
+ */
+
+/*
+ * Primitive Types
+ *
+ * $Id$
+ */
+
+#ifndef JAS_TYPES_H
+#define JAS_TYPES_H
+
+#if defined(HAVE_STDLIB_H)
+#include <stdlib.h>
+#endif
+#if defined(HAVE_STDDEF_H)
+#include <stddef.h>
+#endif
+#if defined(HAVE_SYS_TYPES_H)
+#include <sys/types.h>
+#endif
+
+#if defined(HAVE_STDBOOL_H)
+/*
+ * The C language implementation does correctly provide the standard header
+ * file "stdbool.h".
+ */
+#include <stdbool.h>
+#else
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The C language implementation does not provide the standard header file
+ * "stdbool.h" as required by ISO/IEC 9899:1999.  Try to compensate for this
+ * braindamage below.
+ */
+#if !defined(bool)
+#define	bool	int
+#endif
+#if !defined(true)
+#define true	1
+#endif
+#if !defined(false)
+#define	false	0
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+/* pm_config.h defines the FAST integer types if possible (typically by
+   including <inttypes.h>.  If not, the following try to take care
+   of it.
+*/
+/**********/
+#if !defined(INT_FAST8_MAX)
+typedef signed char int_fast8_t;
+#define INT_FAST8_MIN	(-127)
+#define INT_FAST8_MAX	128
+#endif
+/**********/
+#if !defined(UINT_FAST8_MAX)
+typedef unsigned char uint_fast8_t;
+#define UINT_FAST8_MAX	255
+#endif
+/**********/
+#if !defined(INT_FAST16_MAX)
+typedef short int_fast16_t;
+#define INT_FAST16_MIN	SHRT_MIN
+#define INT_FAST16_MAX	SHRT_MAX
+#endif
+/**********/
+#if !defined(UINT_FAST16_MAX)
+typedef unsigned short uint_fast16_t;
+#define UINT_FAST16_MAX	USHRT_MAX
+#endif
+/**********/
+#if !defined(INT_FAST32_MAX)
+typedef int int_fast32_t;
+#define INT_FAST32_MIN	INT_MIN
+#define INT_FAST32_MAX	INT_MAX
+#endif
+/**********/
+#if !defined(UINT_FAST32_MAX)
+typedef unsigned int uint_fast32_t;
+#define UINT_FAST32_MAX	UINT_MAX
+#endif
+/**********/
+#if !defined(INT_FAST64_MAX)
+typedef int int_fast64_t;
+#define INT_FAST64_MIN	LLONG_MIN
+#define INT_FAST64_MAX	LLONG_MAX
+#endif
+/**********/
+#if !defined(UINT_FAST64_MAX)
+typedef unsigned int uint_fast64_t;
+#define UINT_FAST64_MAX	ULLONG_MAX
+#endif
+/**********/
+#endif
+
+/* The below macro is intended to be used for type casts.  By using this
+  macro, type casts can be easily located in the source code with
+  tools like "grep". */
+#define	JAS_CAST(t, e) \
+	((t) (e))
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jp2/Makefile b/converter/other/jpeg2000/libjasper/jp2/Makefile
index 254b7f56..65838cc2 100644
--- a/converter/other/jpeg2000/libjasper/jp2/Makefile
+++ b/converter/other/jpeg2000/libjasper/jp2/Makefile
@@ -7,7 +7,7 @@ VPATH=.:$(SRCDIR)/$(SUBDIR)
 
 JASPERSRCDIR=$(SRCDIR)/$(SUBDIR)/..
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
 LIB_OBJECTS = jp2_cod.o jp2_dec.o jp2_enc.o
 
@@ -15,5 +15,5 @@ MERGE_OBJECTS =
 
 all: partlist $(LIB_OBJECTS)
 
-include $(JASPERSRCDIR)/Makefile.common
+include $(JASPERSRCDIR)/common.mk
 
diff --git a/converter/other/jpeg2000/libjasper/jpc/Makefile b/converter/other/jpeg2000/libjasper/jpc/Makefile
index e176bd48..ffc4c64f 100644
--- a/converter/other/jpeg2000/libjasper/jpc/Makefile
+++ b/converter/other/jpeg2000/libjasper/jpc/Makefile
@@ -7,7 +7,7 @@ VPATH=.:$(SRCDIR)/$(SUBDIR)
 
 JASPERSRCDIR=$(SRCDIR)/$(SUBDIR)/..
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
 LIB_OBJECTS = jpc_bs.o jpc_cs.o jpc_dec.o jpc_enc.o \
 	jpc_math.o jpc_mct.o jpc_mqcod.o jpc_mqdec.o jpc_mqenc.o \
@@ -18,5 +18,5 @@ MERGE_OBJECTS =
 
 all: partlist $(LIB_OBJECTS)
 
-include $(JASPERSRCDIR)/Makefile.common
+include $(JASPERSRCDIR)/common.mk
 
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_math.c b/converter/other/jpeg2000/libjasper/jpc/jpc_math.c
index d860847d..72e3ac37 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_math.c
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_math.c
@@ -1,3 +1,72 @@
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "jpc_math.h"
+
+
+
+/* Calculate the integer quantity floor(log2(x)), where x is a positive
+  integer. */
+int
+jpc_floorlog2(int const arg) {
+
+	int y;
+    int x;
+
+	assert(arg > 0);
+
+	y = 0;
+    x = arg;
+	while (x > 1) {
+		x >>= 1;
+		++y;
+	}
+	return y;
+}
+
+
+
+/*
+  jpc_floorlog2() and jpc_firstone() do the same thing.
+  The only difference is how input 0 is handled.
+
+n                  : 0 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 
+ceil(log2(n))      : x 0  1  2  2  3  3  3  3  4  4  4  4  4  4  4  4  5  5  5 
+floor(log2(n))     : x 0  1  1  2  2  2  2  3  3  3  3  3  3  3  3  4  4  4  4 
+31-__builtin_clz(n): x 0  1  1  2  2  2  2  3  3  3  3  3  3  3  3  4  4  4  4 
+jpc_floorlog2(n)   : x 0  1  1  2  2  2  2  3  3  3  3  3  3  3  3  4  4  4  4 
+jpc_firstone(n)    :-1 0  1  1  2  2  2  2  3  3  3  3  3  3  3  3  4  4  4  4 
+
+*/
+
+
+
+int
+jpc_firstone(int const arg) {
+/*---------------------------------------------------------------------------- 
+  Calculate the bit position of the first leading one in a nonnegative
+  integer.
+-----------------------------------------------------------------------------*/
+	int n;
+    int x;
+
+	assert(arg >= 0);
+
+	n = -1;
+    x = arg;
+	while (x > 0) {
+		x >>= 1;
+		++n;
+	}
+	return n;
+}
+
+
+
 /*
  * Copyright (c) 1999-2000 Image Power, Inc. and the University of
  *   British Columbia.
@@ -109,62 +178,3 @@
  * 
  * __END_OF_JASPER_LICENSE__
  */
-
-/*
- * Math Library
- *
- * $Id$
- */
-
-/******************************************************************************\
-* Includes
-\******************************************************************************/
-
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-#include <stdlib.h>
-#include <stdarg.h>
-
-#include "jpc_math.h"
-
-/******************************************************************************\
-* Miscellaneous Functions
-\******************************************************************************/
-
-/* Calculate the integer quantity floor(log2(x)), where x is a positive
-  integer. */
-int jpc_floorlog2(int x)
-{
-	int y;
-
-	/* The argument must be positive. */
-	assert(x > 0);
-
-	y = 0;
-	while (x > 1) {
-		x >>= 1;
-		++y;
-	}
-	return y;
-}
-
-/* Calculate the bit position of the first leading one in a nonnegative
-  integer. */
-/* This function is the basically the same as ceillog2(x), except that the
-  allowable range for x is slightly different. */
-int jpc_firstone(int x)
-{
-	int n;
-
-	/* The argument must be nonnegative. */
-	assert(x >= 0);
-
-	n = -1;
-	while (x > 0) {
-		x >>= 1;
-		++n;
-	}
-	return n;
-}
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.c b/converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.c
index 1ed0dd90..1d41d5c5 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.c
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.c
@@ -205,16 +205,6 @@ static void jpc_qmfb1d_split(jpc_fix_t *startptr, int startind, int endind,
 	llen = lendind - lstartind;
 	hlen = hendind - hstartind;
 
-#if defined(WIN32)
-	/* Get a buffer. */
-	if (bufsize > QMFB_SPLITBUFSIZE) {
-		if (!(buf = jas_malloc(bufsize * sizeof(jpc_fix_t)))) {
-			/* We have no choice but to commit suicide in this case. */
-			abort();
-		}
-	}
-#endif
-
 	if (hstartind < lstartind) {
 		/* The first sample in the input signal is to appear
 		  in the highpass subband signal. */
@@ -294,13 +284,6 @@ static void jpc_qmfb1d_split(jpc_fix_t *startptr, int startind, int endind,
 			hptr -= step;
 		}
 	}
-
-#if defined(WIN32)
-	/* If the split buffer was allocated on the heap, free this memory. */
-	if (buf != splitbuf) {
-		jas_free(buf);
-	}
-#endif
 }
 
 static void jpc_qmfb1d_join(jpc_fix_t *startptr, int startind, int endind,
@@ -320,16 +303,6 @@ static void jpc_qmfb1d_join(jpc_fix_t *startptr, int startind, int endind,
 	register int n;
 	int state;
 
-#if defined(WIN32)
-	/* Allocate memory for the join buffer from the heap. */
-	if (bufsize > QMFB_JOINBUFSIZE) {
-		if (!(buf = jas_malloc(bufsize * sizeof(jpc_fix_t)))) {
-			/* We have no choice but to commit suicide. */
-			abort();
-		}
-	}
-#endif
-
 	twostep = step << 1;
 	llen = lendind - lstartind;
 	hlen = hendind - hstartind;
@@ -414,13 +387,6 @@ static void jpc_qmfb1d_join(jpc_fix_t *startptr, int startind, int endind,
 			state ^= 1;
 		}
 	}
-
-#if defined(WIN32)
-	/* If the join buffer was allocated on the heap, free this memory. */
-	if (buf != joinbuf) {
-		jas_free(buf);
-	}
-#endif
 }
 
 /******************************************************************************\
diff --git a/converter/other/jpeg2000/pamtojpeg2k.c b/converter/other/jpeg2000/pamtojpeg2k.c
index 851d2bf9..70774725 100644
--- a/converter/other/jpeg2000/pamtojpeg2k.c
+++ b/converter/other/jpeg2000/pamtojpeg2k.c
@@ -13,6 +13,7 @@
 #define _XOPEN_SOURCE 600
 #include <string.h>
 
+#include "pm_c_util.h"
 #include "pam.h"
 #include "shhopt.h"
 #include "nstring.h"
diff --git a/converter/other/jpegdatasource.c b/converter/other/jpegdatasource.c
index 5c1070e4..1f53c2a4 100644
--- a/converter/other/jpegdatasource.c
+++ b/converter/other/jpegdatasource.c
@@ -45,6 +45,11 @@ struct sourceManager {
     */
     struct jpeg_source_mgr jpegSourceMgr;
     FILE * ifP;
+    bool prematureEof;
+        /* We have been asked for data and were unable to comply because
+           the file had no more to give (so we supplied EOI markers
+           instead).
+        */
     JOCTET * currentBuffer;
     JOCTET * nextBuffer;
     unsigned int bytesInNextBuffer;
@@ -66,6 +71,10 @@ dsInitSource(j_decompress_ptr const cinfoP) {
 
 
 
+static const JOCTET jfifEoiMarker[] = {0xff, JPEG_EOI};
+    /* An EOI (end of image) marker */
+
+
 static boolean
 dsFillInputBuffer(j_decompress_ptr const cinfoP) {
 /*----------------------------------------------------------------------------
@@ -74,9 +83,19 @@ dsFillInputBuffer(j_decompress_ptr const cinfoP) {
 -----------------------------------------------------------------------------*/
     struct sourceManager * const srcP = (struct sourceManager *) cinfoP->src;
 
-    if (srcP->bytesInNextBuffer == 0) 
-        pm_error("End-of-file encountered in the middle of JPEG image.");
-    else {
+    if (srcP->bytesInNextBuffer == 0) {
+        /* The decompressor expects more bytes, but there aren't any, so
+           the file is corrupted -- probably truncated.  We want the
+           decompressor to decompress whatever it's read so far, so we
+           synthesize an EOI marker here, but we also set error state
+           in the source manager.  The decompressor will recognize the
+           truncation and pad out the image with gray.
+        */
+        srcP->prematureEof = TRUE;
+        
+        srcP->jpegSourceMgr.next_input_byte = jfifEoiMarker;
+        srcP->jpegSourceMgr.bytes_in_buffer = sizeof(jfifEoiMarker);
+    } else {
         /* Rotate the buffers */
         srcP->jpegSourceMgr.next_input_byte = srcP->nextBuffer;
         srcP->jpegSourceMgr.bytes_in_buffer = srcP->bytesInNextBuffer;
@@ -87,7 +106,7 @@ dsFillInputBuffer(j_decompress_ptr const cinfoP) {
             srcP->currentBuffer = tmp;
         }
 
-        /* Fill the new 'next' buffer */
+        /* Fill the new "next" buffer */
         srcP->bytesInNextBuffer = 
             fread(srcP->nextBuffer, 1, BUFFER_SIZE, srcP->ifP);
     }
@@ -139,6 +158,14 @@ dsDataLeft(struct sourceManager * const srcP) {
 
 
 
+bool
+dsPrematureEof(struct sourceManager * const srcP) {
+
+    return srcP->prematureEof;
+}
+
+
+
 struct sourceManager * 
 dsCreateSource(const char * const fileName) {
 
@@ -156,6 +183,7 @@ dsCreateSource(const char * const fileName) {
     srcP->jpegSourceMgr.resync_to_restart = jpeg_resync_to_restart;
     srcP->jpegSourceMgr.term_source = dsTermSource;
     
+    srcP->prematureEof = FALSE;
     srcP->currentBuffer = srcP->buffer1;
     srcP->nextBuffer = srcP->buffer2;
     srcP->jpegSourceMgr.bytes_in_buffer = 
diff --git a/converter/other/jpegdatasource.h b/converter/other/jpegdatasource.h
index 07f17389..58648fe4 100644
--- a/converter/other/jpegdatasource.h
+++ b/converter/other/jpegdatasource.h
@@ -12,6 +12,9 @@ dsDestroySource(struct sourceManager * const srcP);
 bool
 dsDataLeft(struct sourceManager * const srcP);
 
+bool
+dsPrematureEof(struct sourceManager * const srcP);
+
 struct jpeg_source_mgr *
 dsJpegSourceMgr(struct sourceManager * const srcP);
 
diff --git a/converter/other/jpegtopnm.c b/converter/other/jpegtopnm.c
index 60ae7e42..07a7dfb0 100644
--- a/converter/other/jpegtopnm.c
+++ b/converter/other/jpegtopnm.c
@@ -61,6 +61,8 @@
    itself, but doesn't.
 */
 #include <jpeglib.h>
+
+#include "pm_c_util.h"
 #include "pnm.h"
 #include "shhopt.h"
 #include "mallocvar.h"
@@ -109,6 +111,7 @@ struct cmdlineInfo {
     unsigned int comments;
     unsigned int dumpexif;
     unsigned int multiple;
+    unsigned int repair;
 };
 
 
@@ -116,9 +119,9 @@ static bool displayComments;
     /* User wants comments from the JPEG to be displayed */
 
 static void 
-interpret_maxmemory (bool         const maxmemorySpec,
-                     const char * const maxmemory, 
-                     long int *   const max_memory_to_use_p) { 
+interpret_maxmemory(bool         const maxmemorySpec,
+                    const char * const maxmemory, 
+                    long int *   const max_memory_to_use_p) { 
 /*----------------------------------------------------------------------------
    Interpret the "maxmemory" command line option.
 -----------------------------------------------------------------------------*/
@@ -157,8 +160,9 @@ interpret_adobe(const int adobe, const int notadobe,
 
 
 static void
-parse_command_line(const int argc, char ** argv,
-                   struct cmdlineInfo *cmdlineP) {
+parseCommandLine(int                  const argc,
+                 char **              const argv,
+                 struct cmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that many of the strings that this function returns in the
    *cmdlineP structure are actually in the supplied argv array.  And
@@ -173,10 +177,10 @@ parse_command_line(const int argc, char ** argv,
          */
     optStruct3 opt;
 
-    int i;  /* local loop variable */
+    unsigned int i;  /* local loop variable */
 
-    char *maxmemory;
-    char *dctval;
+    const char * maxmemory;
+    const char * dctval;
     unsigned int adobe, notadobe;
 
     unsigned int tracelevelSpec, exifSpec, dctvalSpec, maxmemorySpec;
@@ -206,6 +210,7 @@ parse_command_line(const int argc, char ** argv,
             &exifSpec, 0);
     OPTENT3(0, "dumpexif",    OPT_FLAG,   NULL, &cmdlineP->dumpexif,      0);
     OPTENT3(0, "multiple",    OPT_FLAG,   NULL, &cmdlineP->multiple,      0);
+    OPTENT3(0, "repair",      OPT_FLAG,   NULL, &cmdlineP->repair,        0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
@@ -213,7 +218,8 @@ parse_command_line(const int argc, char ** argv,
 
     /* Make private copy of arguments for optParseOptions to corrupt */
     argc_parse = argc;
-    for (i=0; i < argc; i++) argv_parse[i] = argv[i];
+    for (i=0; i < argc; ++i)
+        argv_parse[i] = argv[i];
 
     optParseOptions3( &argc_parse, argv_parse, opt, sizeof(opt), 0);
         /* Uses and sets argc_parse, argv_parse, 
@@ -236,11 +242,11 @@ parse_command_line(const int argc, char ** argv,
     if (!dctvalSpec)
         cmdlineP->dct_method = JDCT_DEFAULT;
     else {
-        if (STREQ(dctval, "int"))
+        if (streq(dctval, "int"))
             cmdlineP->dct_method = JDCT_ISLOW;
-        else if (STREQ(dctval, "fast"))
+        else if (streq(dctval, "fast"))
             cmdlineP->dct_method = JDCT_IFAST;
-        else if (STREQ(dctval, "float"))
+        else if (streq(dctval, "float"))
             cmdlineP->dct_method = JDCT_FLOAT;
         else pm_error("Invalid value for the --dct option: '%s'.", dctval);
     }
@@ -458,32 +464,34 @@ read_rgb(JSAMPLE *ptr, const enum colorspace color_space,
    copy_pixel_row().  But it would be impractical to allocate and free
    the storage with every call to copy_pixel_row().
 */
-static xel *pnmbuffer;      /* Output buffer.  Input to pnm_writepnmrow() */
+static xel * pnmbuffer;      /* Output buffer.  Input to pnm_writepnmrow() */
 
 static void
-copy_pixel_row(const JSAMPROW jpegbuffer, const int width, 
-               const unsigned int samples_per_pixel, 
-               const enum colorspace color_space,
-               const unsigned int maxval,
-               FILE * const output_file, const int output_type) {
-  JSAMPLE *ptr;
-  unsigned int output_cursor;     /* Cursor into output buffer 'pnmbuffer' */
-
-  ptr = jpegbuffer;  /* Start at beginning of input row */
-
-  for (output_cursor = 0; output_cursor < width; output_cursor++) {
-      xel current_pixel;
-      if (samples_per_pixel >= 3) {
-          const rgb_type * const rgb_p = read_rgb(ptr, color_space, maxval);
-          PPM_ASSIGN(current_pixel, rgb_p->r, rgb_p->g, rgb_p->b);
-      } else {
-          PNM_ASSIGN1(current_pixel, GETJSAMPLE(*ptr));
-      }
-      ptr += samples_per_pixel;  /* move to next pixel of input */
-      pnmbuffer[output_cursor] = current_pixel;
-  }
-  pnm_writepnmrow(output_file, pnmbuffer, width,
-                  maxval, output_type, FALSE);
+copyPixelRow(JSAMPROW        const jpegbuffer,
+             unsigned int    const width, 
+             unsigned int    const samplesPerPixel, 
+             enum colorspace const colorSpace,
+             FILE *          const ofP,
+             int             const format,
+             xelval          const maxval) {
+
+    JSAMPLE * ptr;
+    unsigned int outputCursor;     /* Cursor into output buffer 'pnmbuffer' */
+
+    ptr = &jpegbuffer[0];  /* Start at beginning of input row */
+    
+    for (outputCursor = 0; outputCursor < width; ++outputCursor) {
+        xel currentPixel;
+        if (samplesPerPixel >= 3) {
+            const rgb_type * const rgb_p = read_rgb(ptr, colorSpace, maxval);
+            PPM_ASSIGN(currentPixel, rgb_p->r, rgb_p->g, rgb_p->b);
+        } else {
+            PNM_ASSIGN1(currentPixel, GETJSAMPLE(*ptr));
+        }
+        ptr += samplesPerPixel;  /* move to next pixel of input */
+        pnmbuffer[outputCursor] = currentPixel;
+    }
+    pnm_writepnmrow(ofP, pnmbuffer, width, maxval, format, FALSE);
 }
 
 
@@ -796,17 +804,42 @@ computeColorSpace(struct jpeg_decompress_struct * const cinfoP,
 
 
 static void
+convertRaster(struct jpeg_decompress_struct * const cinfoP,
+              enum colorspace                 const color_space,
+              FILE *                          const ofP,
+              xelval                          const format,
+              unsigned int                    const maxval) {
+              
+    JSAMPROW jpegbuffer;  /* Input buffer.  Filled by jpeg_scanlines() */
+
+    jpegbuffer = ((*cinfoP->mem->alloc_sarray)
+                  ((j_common_ptr) cinfoP, JPOOL_IMAGE,
+                   cinfoP->output_width * cinfoP->output_components, 
+                   (JDIMENSION) 1)
+        )[0];
+
+    while (cinfoP->output_scanline < cinfoP->output_height) {
+        jpeg_read_scanlines(cinfoP, &jpegbuffer, 1);
+        if (ofP)
+            copyPixelRow(jpegbuffer, cinfoP->output_width, 
+                         cinfoP->out_color_components,
+                         color_space, ofP, format, maxval);
+    }
+}
+
+
+
+static void
 convertImage(FILE *                          const ofP, 
              struct cmdlineInfo              const cmdline,
              struct jpeg_decompress_struct * const cinfoP) {
 
-    int output_type;
+    int format;
         /* The type of output file, PGM or PPM.  Value is either PPM_TYPE
            or PGM_TYPE, which conveniently also pass as format values
            PPM_FORMAT and PGM_FORMAT.
         */
-    JSAMPROW jpegbuffer;  /* Input buffer.  Filled by jpeg_scanlines() */
-    unsigned int maxval;  
+    xelval maxval;  
         /* The maximum value of a sample (color component), both in the input
            and the output.
         */
@@ -817,43 +850,30 @@ convertImage(FILE *                          const ofP,
                    cmdline.dct_method, 
                    cmdline.max_memory_to_use, cmdline.nosmooth);
                    
-    set_color_spaces(cinfoP->jpeg_color_space, &output_type, 
+    set_color_spaces(cinfoP->jpeg_color_space, &format,
                      &cinfoP->out_color_space);
 
-    maxval = (1 << cinfoP->data_precision) - 1;
+    maxval = pm_bitstomaxval(cinfoP->data_precision);
 
     if (cmdline.verbose) 
-        tellDetails(*cinfoP, maxval, output_type);
+        tellDetails(*cinfoP, maxval, format);
 
     /* Calculate output image dimensions so we can allocate space */
     jpeg_calc_output_dimensions(cinfoP);
 
-    jpegbuffer = ((*cinfoP->mem->alloc_sarray)
-                  ((j_common_ptr) cinfoP, JPOOL_IMAGE,
-                   cinfoP->output_width * cinfoP->output_components, 
-                   (JDIMENSION) 1)
-        )[0];
-
     /* Start decompressor */
     jpeg_start_decompress(cinfoP);
 
     if (ofP)
         /* Write pnm output header */
         pnm_writepnminit(ofP, cinfoP->output_width, cinfoP->output_height,
-                         maxval, output_type, FALSE);
+                         maxval, format, FALSE);
 
     pnmbuffer = pnm_allocrow(cinfoP->output_width);
     
     color_space = computeColorSpace(cinfoP, cmdline.inklevel);
-
-    /* Process data */
-    while (cinfoP->output_scanline < cinfoP->output_height) {
-        jpeg_read_scanlines(cinfoP, &jpegbuffer, 1);
-        if (ofP)
-            copy_pixel_row(jpegbuffer, cinfoP->output_width, 
-                           cinfoP->out_color_components,
-                           color_space, maxval, ofP, output_type);
-    }
+    
+    convertRaster(cinfoP, color_space, ofP, format, maxval);
 
     if (cmdline.comments)
         print_comments(*cinfoP);
@@ -905,17 +925,25 @@ convertImages(FILE *                          const ofP,
             convertImage(ofP, cmdline, cinfoP);
         }
     } else {
-        if (dsDataLeft(sourceManagerP))
+        if (dsDataLeft(sourceManagerP)) {
             convertImage(ofP, cmdline, cinfoP);
-        else
+        } else
             pm_error("Input stream is empty");
     }
+    if (dsPrematureEof(sourceManagerP)) {
+        if (cmdline.repair)
+            pm_message("Premature EOF on input; repaired by padding end "
+                       "of image.");
+        else
+            pm_error("Premature EOF on input.  Use -repair to salvage.");
+    }
 }
 
 
 
 int
 main(int argc, char **argv) {
+
     FILE * ofP;
     struct cmdlineInfo cmdline;
     struct jpeg_decompress_struct cinfo;
@@ -924,9 +952,9 @@ main(int argc, char **argv) {
 
     pnm_init(&argc, argv);
 
-    parse_command_line(argc, argv, &cmdline);
+    parseCommandLine(argc, argv, &cmdline);
 
-    if (cmdline.exif_filespec && STREQ(cmdline.exif_filespec, "-"))
+    if (cmdline.exif_filespec && streq(cmdline.exif_filespec, "-"))
         /* He's got exif going to stdout, so there can be no image output */
         ofP = NULL;
     else
@@ -967,4 +995,3 @@ main(int argc, char **argv) {
   
     exit(jerr.num_warnings > 0 ? EXIT_WARNING : EXIT_SUCCESS);
 }
-
diff --git a/converter/other/pamtodjvurle.c b/converter/other/pamtodjvurle.c
index ae35e81d..2d26eeb0 100644
--- a/converter/other/pamtodjvurle.c
+++ b/converter/other/pamtodjvurle.c
@@ -16,6 +16,7 @@
 #include <stdio.h>
 #include <assert.h>
 
+#include "pm_c_util.h"
 #include "pam.h"
 #include "pammap.h"
 #include "shhopt.h"
@@ -179,7 +180,7 @@ writeRleRun(FILE *       const ofP,
   
   'transcolor' is a 3-deep tuple with the same maxval as the image.
 -----------------------------------------------------------------------------*/
-    uint32n rlevalue;         /* RLE-encoded color/valuex */
+    uint32_t rlevalue;         /* RLE-encoded color/valuex */
     int index;
 
     if (count > 0) {
diff --git a/converter/other/pamtofits.c b/converter/other/pamtofits.c
index ec271ff3..7a1c70de 100644
--- a/converter/other/pamtofits.c
+++ b/converter/other/pamtofits.c
@@ -20,10 +20,17 @@
 ** in the FITS header, but do not cause the data to be rescaled.
 */
 
+/*
+  The official specification of FITS format (which is for more than
+  just visual images) is at
+  ftp://legacy.gsfc.nasa.gov/fits_info/fits_office/fits_standard.pdf
+*/
+
 #include <assert.h>
 #include <string.h>
 #include <stdio.h>
 
+#include "pm_c_util.h"
 #include "mallocvar.h"
 #include "shhopt.h"
 #include "nstring.h"
@@ -39,10 +46,9 @@ struct cmdlineInfo {
 
 
 static void 
-parseCommandLine(int argc, 
-                 char ** argv, 
-                 struct cmdlineInfo  * const cmdlineP) {
-/* --------------------------------------------------------------------------
+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.  
 
@@ -52,8 +58,8 @@ parseCommandLine(int argc,
    Note that the strings we return are stored in the storage that
    was passed to us as the argv array.  We also trash *argv.
 --------------------------------------------------------------------------*/
-    optEntry *option_def;
-    /* Instructions to optParseOptions3 on how to parse our options. */
+    optEntry * option_def;
+        /* Instructions to optParseOptions3 on how to parse our options. */
     optStruct3 opt;
 
     unsigned int minSpec;
@@ -98,7 +104,6 @@ parseCommandLine(int argc,
 
 
 
-
 static void
 writeHeaderCard(const char * const s) {
 /*----------------------------------------------------------------------------
@@ -203,6 +208,14 @@ writeRaster(struct pam * const pamP,
             unsigned int const bitpix,
             int          const offset) {
 
+    /* Note: the FITS specification does not give the association between
+       file position and image position (i.e. is the first pixel in the
+       file the top left, bottom left, etc.).  We use the common sense,
+       popular order of row major, top to bottom, left to right.  This
+       has been the case and accepted since 1989, but in 2008, we discovered
+       that Gimp and ImageMagick do bottom to top.
+    */
+
     unsigned int plane;
 
     for (plane = 0; plane < pamP->depth; ++plane) {
diff --git a/converter/other/pamtogif.c b/converter/other/pamtogif.c
new file mode 100644
index 00000000..0c8c0f9e
--- /dev/null
+++ b/converter/other/pamtogif.c
@@ -0,0 +1,1977 @@
+/*=============================================================================
+                              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 "pm_c_util.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.
+    */
+
+
+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.
+        */
+    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.
+
+           Meaningful only if 'haveTransparent' is true.
+        */
+    tuplehash tuplehash;
+        /* A hash table to translate color to GIF 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 */
+    float aspect;               /* -aspect option value (the ratio).  */
+    unsigned int verbose;
+};
+
+
+
+
+
+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;
+
+    unsigned int aspectSpec;
+
+    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,   "aspect",      OPT_FLOAT, 
+            &cmdlineP->aspect,         &aspectSpec, 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];
+        
+    if (aspectSpec) { 
+        if (cmdlineP->aspect < 0.25  || cmdlineP->aspect > 4.21875)
+            pm_error("Invalid -aspect value: %f.  "
+                     "GIF allows only the range 0.25-4.0 .",
+                     cmdlineP->aspect);
+        else if (cmdlineP->aspect > 4.0)
+            pm_message("Warning: "
+                       "You specified an aspect ratio over 4.0: %f.  "
+                       "This will result in an invalid GIF.",
+                       cmdlineP->aspect);
+    } else
+        cmdlineP->aspect = 1.0;
+}
+
+
+
+/*
+ * 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 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.
+-----------------------------------------------------------------------------*/
+    int colorIndex;
+
+    if (alphaPlane && tuple[alphaPlane] < alphaThreshold &&
+        cmapP->haveTransparent)
+        colorIndex = cmapP->transparent;
+    else {
+        int found;
+
+        pnm_lookuptuple(pamP, cmapP->tuplehash, tuple,
+                        &found, &colorIndex);
+        
+        if (!found)
+            colorIndex = closestColor(tuple, pamP, cmapP);
+    }
+    assert(colorIndex >= 0);
+    return (unsigned int) 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
+
+/*
+ *
+ * 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 {
+    stringCode 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 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 &= (1 << codeBufferP->curBits) - 1;
+
+    if (codeBufferP->curBits > 0)
+        codeBufferP->curAccum |= ((unsigned 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 hsize;
+        /* The number of slots in the hash table.  This variable to
+           enhance overall performance by reducing memory use when
+           encoding smaller gifs. 
+         */
+        
+    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 unsigned int
+nSignificantBits( unsigned int const arg ){
+
+#if HAVE_GCC_BITCOUNT
+
+    return (arg == 0) ? 0 : 8 * sizeof(unsigned int) - __builtin_clz(arg);
+
+#else
+
+    unsigned int i = 0;
+    while (arg >> i != 0)
+        ++i;
+
+    return i;
+#endif
+}
+
+
+
+static lzwCompressor *
+lzw_create(FILE *       const ofP,
+           unsigned int const initBits,
+           bool         const lzw,
+           unsigned int const pixelCount) {
+
+    unsigned int const hsizeTable[] = {257, 521, 1031, 2053, 4099, 5003};
+    /* If the image has 4096 or fewer pixels we use prime numbers slightly
+       above powers of two between 8 and 12.  In this case the hash table
+       never fills up; clear code is never emitted.
+    
+       Above that we use a table with 4096 slots plus 20% extra.
+       When this is not enough the clear code is emitted.
+       Due to the extra 20% the table itself never fills up.
+       
+       lzw.hsize and lzw.hshift stay constant through the image.
+
+       Variable hsize is a performance enhancement based on the fact that
+       the encoder never needs more codes than the number of pixels in
+       the image.  Typically, the ratio of pixels to codes is around
+       10:1 to 20:1.
+   
+       Logic works with fixed values lzw.hsize=5003 and t=13.
+    */
+
+    lzwCompressor * lzwP;
+       
+    MALLOCVAR_NOFAIL(lzwP);
+
+    /* Constants */
+    lzwP->lzw = lzw;
+
+    lzwP->clearCode     = 1 << (initBits - 1);
+    lzwP->eofCode       = lzwP->clearCode + 1;
+    lzwP->initCodeLimit = 1 << initBits;
+
+    if (lzw) {
+        unsigned int const t =
+            MIN(13, MAX(8, nSignificantBits(pixelCount +lzwP->eofCode - 2)));
+            /* Index into hsizeTable */
+    
+        lzwP->hsize = hsizeTable[t-8];
+
+        lzwP->hshift = (t == 13 ? 12 : t) - nSignificantBits(MAXCMAPSIZE-1);
+
+        MALLOCARRAY(lzwP->hashTable, lzwP->hsize);
+        
+        if (lzwP->hashTable == NULL)
+            pm_error("Couldn't get memory for %u-entry hash table.",
+                     lzwP->hsize);
+    } else {
+        /* No LZW compression.  We don't need a stringcode hash table */  
+        lzwP->hashTable = NULL;
+        lzwP->hsize     = 0;
+    }
+
+    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 < lzwP->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;
+    
+    return hash;
+}
+
+    
+
+static void
+lookupInHash(lzwCompressor *  const lzwP,
+             unsigned int     const gifPixel,
+             stringCode       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 : lzwP->hsize - i;
+
+    while (lzwP->hashTable[i].fcode != fcode &&
+           lzwP->hashTable[i].fcode >= 0) {
+        i -= disp;
+        if (i < 0)
+            i += lzwP->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 {
+        stringCode const fcode =
+            ((stringCode) 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 known 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, pamP->height * pamP->width);
+
+    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[i];
+
+            assert(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[],
+               float               const aspect) {
+
+    unsigned int const resolution = bitsPerPixel;
+
+    unsigned char b;
+
+    /* Write the Magic header */
+    if (cmapP->haveTransparent || comment || aspect != 1.0 )
+        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);
+
+    {
+        int const aspectValue = aspect == 1.0 ? 0 : ROUND(aspect * 64) - 15;
+        assert(0 <= aspectValue && aspectValue <= 255); 
+        fputc(aspectValue, 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[],
+          float         const aspect,
+          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);
+
+    if (pamP->width > 65535)
+        pm_error("Image width %u too large for GIF format.  (Max 65535)",
+                 pamP->width);
+     
+    if (pamP->height > 65535)
+        pm_error("Image height %u too large for GIF format.  (Max 65535)",
+                 pamP->height);
+
+    writeGifHeader(ofP, pamP->width, pamP->height, background,
+                   bitsPerPixel, cmapP, comment, aspect);
+
+    /* 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->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 colorindex;
+        
+        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,
+                        &colorindex);
+        
+        if (found) {
+            cmapP->haveTransparent = TRUE;
+            cmapP->transparent = colorindex;
+        } else if (!exact) {
+            cmapP->haveTransparent = TRUE;
+            cmapP->transparent = 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
+sortOrderColor(tuple const tuple) {
+
+    return ((tuple[PAM_RED_PLANE] * MAXCMAPSIZE) +
+            tuple[PAM_GRN_PLANE]) * MAXCMAPSIZE +
+           tuple[PAM_BLU_PLANE];
+}
+
+
+
+#ifndef LITERAL_FN_DEF_MATCH
+static qsort_comparison_fn sortCompareColor;
+#endif
+
+static int
+sortCompareColor(const void * const entry1P,
+                 const void * const entry2P) {
+
+    struct tupleint * const * const tupleint1PP = entry1P;
+    struct tupleint * const * const tupleint2PP = entry2P;
+
+    return (sortOrderColor((*tupleint1PP)->tuple) 
+            - sortOrderColor((*tupleint2PP)->tuple));
+}
+
+
+
+#ifndef LITERAL_FN_DEF_MATCH
+static qsort_comparison_fn sortCompareGray;
+#endif
+
+static int
+sortCompareGray(const void * const entry1P,
+                const void * const entry2P){
+
+    struct tupleint * const * const tupleint1PP = entry1P;
+    struct tupleint * const * const tupleint2PP = entry2P;
+
+    return ((*tupleint1PP)->tuple[0] - (*tupleint2PP)->tuple[0]);
+}
+
+
+
+static void
+sortTupletable(struct pam * const mapPamP,
+               unsigned int const colors,
+               tupletable   const tuplefreq) {
+/*----------------------------------------------------------------------------
+   Sort the colormap *cmapP.
+
+   Sort the colormap by red intensity, then by green intensity,
+   then by blue intensity.
+-----------------------------------------------------------------------------*/
+
+    pm_message("sorting colormap");
+
+    if (mapPamP->depth < 3)
+        qsort(tuplefreq, colors, sizeof(tuplefreq[0]), sortCompareGray);
+    else
+        qsort(tuplefreq, colors, sizeof(tuplefreq[0]), sortCompareColor); 
+
+}
+
+
+
+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 ...");
+    
+    *tupletableP = 
+        pnm_computetuplefreqtable(mapPamP, colors, maxcolors, &colorCount);
+
+    *colorCountP = colorCount;
+
+    pnm_freepamarray(colors, mapPamP); 
+}
+
+
+
+static void
+readAndValidateColormapFromFile(char           const filename[],
+                                unsigned int   const maxcolors,
+                                tupletable *   const tuplefreqP, 
+                                struct pam *   const mapPamP,
+                                unsigned int * const colorCountP,
+                                unsigned int   const nInputComp,
+                                sample         const inputMaxval) {
+/*----------------------------------------------------------------------------
+   Read the colormap from a separate colormap file named filename[],
+   and make sure it's consistent with an image with 'nInputComp'
+   color components (e.g. 3 for RGB) and a maxval of 'inputMaxval'.
+-----------------------------------------------------------------------------*/
+    colormapFromFile(filename, maxcolors, tuplefreqP, mapPamP, colorCountP);
+
+    if (mapPamP->depth != nInputComp)
+        pm_error("Depth of map file (%u) does not match number of "
+                 "color components in input file (%u)",
+                 mapPamP->depth, nInputComp);
+    if (mapPamP->maxval != inputMaxval)
+        pm_error("Maxval of map file (%lu) does not match maxval of "
+                 "input file (%lu)", mapPamP->maxval, inputMaxval);
+}
+
+
+
+static void
+computeColormapBw(struct pam *   const pamP,
+                  struct pam *   const mapPamP,
+                  unsigned int * const colorCountP,
+                  tupletable   * const tuplefreqP) {
+/*----------------------------------------------------------------------------
+  Shortcut for black and white (e.g. PBM).  We know that there are
+  only two colors.  Users who know that only one color is present in
+  the image should specify -sort at the command line.  Example:
+
+   $ pbmmake -w 600 400 | pamtogif -sort > canvas.gif
+-----------------------------------------------------------------------------*/
+    tupletable const colormap = pnm_alloctupletable(pamP, 2);
+    
+    *mapPamP = *pamP;
+    mapPamP->depth = 1;
+
+    colormap[0]->value = 1;
+    colormap[0]->tuple[0] = PAM_BLACK;
+    colormap[1]->value = 1;
+    colormap[1]->tuple[0] = PAM_BW_WHITE;
+    
+    *tuplefreqP  = colormap;
+    *colorCountP = 2;
+}
+  
+    
+
+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,
+                         bool           const sort) {
+/*----------------------------------------------------------------------------
+   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.
+
+   'sort' means to sort the colormap by red intensity, then by green
+   intensity, then by blue intensity, as opposed to arbitrary order.
+-----------------------------------------------------------------------------*/
+    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)
+        readAndValidateColormapFromFile(mapfile, maxcolors, &tuplefreq,
+                                        mapPamP, &colorCount,
+                                        nInputComp, pamP->maxval);
+    else if (nInputComp == 1 && pamP->maxval == 1 && !sort &&
+             pamP->height * pamP->width > 1)
+        computeColormapBw(pamP, mapPamP, &colorCount, &tuplefreq);
+    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);
+
+    if (sort)
+        sortTupletable(mapPamP, colorCount, tuplefreq);
+
+    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, cmdline.sort);
+    
+    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);
+    }
+
+    bitsPerPixel = cmap.cmapSize == 1 ? 1 : nSignificantBits(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.aspect, !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.
+  
+  2007.01  Changed sort routine to qsort.  (afu)
+  2007.03  Implemented variable hash table size, PBM color table
+           shortcut and "-aspect" command line option.   (afu)
+
+ 
+  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/pamtohdiff.c b/converter/other/pamtohdiff.c
index 0e1ff00f..2d5f6a61 100644
--- a/converter/other/pamtohdiff.c
+++ b/converter/other/pamtohdiff.c
@@ -16,6 +16,7 @@
 #include <string.h>
 #include <stdio.h>
 
+#include "pm_c_util.h"
 #include "pam.h"
 #include "shhopt.h"
 
diff --git a/converter/other/pamtohtmltbl.c b/converter/other/pamtohtmltbl.c
index 0afbfea0..5335ff9f 100644
--- a/converter/other/pamtohtmltbl.c
+++ b/converter/other/pamtohtmltbl.c
@@ -2,16 +2,17 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "pam.h"
-#include "shhopt.h"
+#include "pm_c_util.h"
 #include "mallocvar.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 *inputFilespec;  /* '-' if stdin */
-    const char *transparent;  /* NULL if none */
+    const char * inputFileName;  /* '-' if stdin */
+    const char * transparent;  /* NULL if none */
     unsigned int verbose;
 };
 
@@ -19,8 +20,8 @@ struct cmdlineInfo {
 
 
 static void
-parseCommandLine ( int argc, char ** argv,
-                   struct cmdlineInfo *cmdlineP ) {
+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.  
@@ -31,7 +32,7 @@ parseCommandLine ( int argc, char ** argv,
    Note that the strings we return are stored in the storage that
    was passed to us as the argv array.  We also trash *argv.
 -----------------------------------------------------------------------------*/
-    optEntry *option_def = malloc(100*sizeof(optEntry));
+    optEntry * option_def;
         /* Instructions to optParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
@@ -40,6 +41,8 @@ parseCommandLine ( int argc, char ** argv,
 
     unsigned int transparentSpec;
 
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
     option_def_index = 0;   /* incremented by OPTENT3 */
     OPTENT3(0, "verbose",     OPT_FLAG,   NULL,                  
             &cmdlineP->verbose,       0 );
@@ -58,9 +61,9 @@ parseCommandLine ( int argc, char ** argv,
         cmdlineP->transparent = NULL;
 
     if (argc-1 < 1)
-        cmdlineP->inputFilespec = "-";
+        cmdlineP->inputFileName = "-";
     else if (argc-1 == 1)
-        cmdlineP->inputFilespec = argv[1];
+        cmdlineP->inputFileName = argv[1];
     else
         pm_error("Too many arguments.  Program takes at most one argument: "
                  "input file name");
@@ -135,31 +138,30 @@ findSameColorRectangle(struct pam *   const pamP,
     mx=0; my=0;
     cnx = pamP->width - col; cny = pamP->height - row;
 
-    for (i=0; (!mx)||(!my); i++) {
+    for (i = 0; !mx || !my; ++i) {
         int j;
-        /*fprintf(stderr,"\n[%d]",i);*/
-        for (j=0; j<=i; j++) {
+        for (j = 0; j <= i; ++j) {
             if (!my) {
-                if (i>=cny) 
-                    my=cny;
-                else
-                    if (((!mx) || (j<mx)) && (j < cnx)) {
-                        /*fprintf(stderr,"%d/%d ",j,i);*/
+                if (i >= cny) 
+                    my = cny;
+                else {
+                    if ((!mx || j < mx) && (j < cnx)) {
                         if (!pnm_tupleequal(pamP, tuples[row+i][col+j],
                                             rectangleColor)) 
                             my = i;
                     }
+                }
             }
             if (!mx) {
-                if (i>=cnx) 
-                    mx=cnx;
-                else
-                    if (((!my) || (j<my)) && (j < cny)) {
-                        /*fprintf(stderr,"%d/%d ",i,j);*/
+                if (i >= cnx) 
+                    mx = cnx;
+                else {
+                    if ((!my || (j < my)) && (j < cny)) {
                         if (!pnm_tupleequal(pamP, tuples[row+j][col+i],
                                             rectangleColor)) 
                             mx = i;
                     }
+                }
             }
         }
     }
@@ -170,7 +172,8 @@ findSameColorRectangle(struct pam *   const pamP,
 
 
 static bool **
-allocOutputtedArray(unsigned int const width, unsigned int const height) {
+allocOutputtedArray(unsigned int const width,
+                    unsigned int const height) {
 
     bool ** outputted;
     unsigned int row;
@@ -180,15 +183,9 @@ allocOutputtedArray(unsigned int const width, unsigned int const height) {
         pm_error("Unable to allocate space for 'outputted' array");
 
     for (row = 0; row < height; ++row) {
-        unsigned int col;
-
         MALLOCARRAY(outputted[row], width);
         if (outputted[row] == NULL)
             pm_error("Unable to allocate space for 'outputted' array");
-
-        for (col = 0; col < width ; ++col)
-          outputted[row][col] = FALSE;
-
     }
     return outputted;
 }
@@ -196,7 +193,8 @@ allocOutputtedArray(unsigned int const width, unsigned int const height) {
 
 
 static void
-freeOutputtedArray(bool ** const outputted, unsigned int const height) {
+freeOutputtedArray(bool **       const outputted,
+                   unsigned int const height) {
 
     unsigned int row;
 
@@ -206,13 +204,40 @@ freeOutputtedArray(bool ** const outputted, unsigned int const height) {
 
 
 
+                       
 static void
-markOutputted(bool ** const outputted,
+markNotOutputted(bool **      const outputted,
+                 unsigned int const upperLeftCol,
+                 unsigned int const upperLeftRow,
+                 unsigned int const width,
+                 unsigned int const height) {
+/*----------------------------------------------------------------------------
+   Mark every pixel in the specified rectangle as not having been output
+   yet.
+-----------------------------------------------------------------------------*/
+    unsigned int const lowerRightCol = upperLeftCol + width;
+    unsigned int const lowerRightRow = upperLeftRow + height;
+    unsigned int row;
+    
+    for (row = upperLeftRow; row < lowerRightRow; ++row) {
+        unsigned int col;
+        for (col = upperLeftCol; col < lowerRightCol; ++col) 
+            outputted[row][col] = FALSE;
+    }
+}
+
+
+
+static void
+markOutputted(bool **      const outputted,
               unsigned int const upperLeftCol,
               unsigned int const upperLeftRow,
               unsigned int const width,
               unsigned int const height) {
-
+/*----------------------------------------------------------------------------
+   Mark every pixel in the specified rectangle as having been output
+   already.
+-----------------------------------------------------------------------------*/
     unsigned int const lowerRightCol = upperLeftCol + width;
     unsigned int const lowerRightRow = upperLeftRow + height;
     unsigned int row;
@@ -232,16 +257,19 @@ main(int argc, char **argv) {
     FILE * ifP;
     struct pam inpam;
     tuple ** tuples;
-    int row;
+    unsigned int row;
     unsigned int rectWidth, rectHeight;
     bool ** outputted;
+        /* Two dimensional array.  outputted[ROW][COL] means the pixel
+           at row ROW, column COL has already been outputted.
+        */
     tuple transparentColor;
 
     pnm_init(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
-    ifP = pm_openr(cmdline.inputFilespec);
+    ifP = pm_openr(cmdline.inputFileName);
 
     tuples = pnm_readpam(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
 
@@ -259,8 +287,12 @@ main(int argc, char **argv) {
 
     printf("<TABLE WIDTH=%d HEIGHT=%d BORDER=0 CELLSPACING=0 CELLPADDING=0>\n",
            inpam.width, inpam.height);
+
+    markNotOutputted(outputted, 0, 0, inpam.width, inpam.height);
+        /* No pixel has been outputted yet */
+
     for (row = 0; row < inpam.height; ++row) {
-        int col;
+        unsigned int col;
         printf("<TR>\n");
         pripix(&inpam, tuples[row][0], 1, 1, transparentColor); 
         markOutputted(outputted, 0, row, 1, 1);
@@ -270,7 +302,7 @@ main(int argc, char **argv) {
                 findSameColorRectangle(&inpam, tuples, row, col, 
                                        &rectWidth, &rectHeight);
                 if (cmdline.verbose)
-                    pm_message("[%d/%d] [%d/%d]",
+                    pm_message("[%u/%u] [%u/%u]",
                                col, row, rectWidth, rectHeight);
                 pripix(&inpam, tuples[row][col], rectWidth, rectHeight, 
                        transparentColor);
@@ -286,5 +318,5 @@ main(int argc, char **argv) {
     pnm_freepamarray(tuples, &inpam);
     freeOutputtedArray(outputted, inpam.height);
 
-    exit(0);
+    return 0;
 }
diff --git a/converter/other/pamtompfont.c b/converter/other/pamtompfont.c
new file mode 100644
index 00000000..ba170fef
--- /dev/null
+++ b/converter/other/pamtompfont.c
@@ -0,0 +1,182 @@
+/*----------------------------------------------------------------------------
+                               pamtompfont
+------------------------------------------------------------------------------
+  Part of the Netpbm package.
+
+  Convert a PAM image to an Mplayer bitmap font.
+
+  It is obvious that this format was designed to be an image format and
+  adopted by Mplayer for it's fonts (before Mplayer got the ability to
+  use Freetype to read standard font formats such as TrueType).  But
+  I have no idea what the format was originally.
+
+  In the Mplayer font subset of the format, the image is always grayscale
+  (one byte per pixel) with no palette.
+
+  By Bryan Henderson, San Jose CA 2008.05.18
+
+  Contributed to the public domain by its author.
+-----------------------------------------------------------------------------*/
+
+#include <string.h>
+#include <assert.h>
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "shhopt.h"
+#include "pm.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;
+};
+
+
+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;
+        /* Instructions to OptParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+
+    OPTENTINIT;
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
+
+    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (argc-1 == 0) 
+        cmdlineP->inputFilename = "-";
+    else if (argc-1 != 1)
+        pm_error("Program takes zero or one argument (filename).  You "
+                 "specified %d", argc-1);
+    else
+        cmdlineP->inputFilename = argv[1];
+}
+
+
+
+static void
+validateInput(struct pam * const inpamP) {
+
+    /* The image format does provide for RGB images, but Mplayer doesn't
+       understand that format (and doesn't even recognize it as something
+       it doesn't understand)
+    */
+
+    if (inpamP->depth != 1)
+        pm_error("Input must have depth 1.  This image's depth is %u",
+                 inpamP->depth);
+}
+
+
+
+static void
+writeMpFontHeader(FILE *       const ofP,
+                  struct pam * const inpamP) {
+/*----------------------------------------------------------------------------
+   Write the 32 byte header.
+-----------------------------------------------------------------------------*/
+    fwrite("mhwanh", 1, 6, ofP);  /* Signature */
+
+    fputc(0, ofP);  /* pad */
+    fputc(0, ofP);  /* pad */
+
+    /* Write the old 16 bit width field.  Zero means use the 32 bit one
+       below instead.
+    */
+    pm_writebigshort(ofP, 0);
+
+    /* Height */
+    pm_writebigshort(ofP, inpamP->height);
+
+    /* Number of colors in palette.  Zero means not paletted image */
+    pm_writebigshort(ofP, 0);
+
+    {
+        unsigned int i;
+        for (i = 0; i < 14; ++i)
+            fputc(0, ofP);  /* pad */
+    }
+    /* Width */
+    pm_writebiglong(ofP, inpamP->width);
+}
+
+
+
+static void
+convertRaster(struct pam * const inpamP,
+              FILE *       const ofP) {
+            
+    tuple * tuplerow;
+    unsigned char * outrow;
+    unsigned int row;
+
+    assert(inpamP->depth == 1);
+
+    tuplerow = pnm_allocpamrow(inpamP);
+
+    MALLOCARRAY(outrow, inpamP->width);
+
+    if (outrow == NULL)
+        pm_error("Unable to allocate space for a %u-column output buffer",
+                 inpamP->width);
+
+    for (row = 0; row < inpamP->height; ++row) {
+        unsigned int col;
+
+        pnm_readpamrow(inpamP, tuplerow);
+
+        for (col = 0; col < inpamP->width; ++col) {
+            outrow[col] =
+                pnm_scalesample(tuplerow[col][0], inpamP->maxval, 255);
+        }
+        
+        fwrite(outrow, 1, inpamP->width, ofP);
+    }
+    free(outrow);
+    pnm_freepamrow(tuplerow);
+}
+
+
+
+int
+main(int argc, char *argv[]) {
+
+    struct cmdlineInfo cmdline;
+    FILE * ifP;
+    struct pam inpam;   /* Input PAM image */
+
+    pnm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFilename);
+
+    pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
+
+    validateInput(&inpam);
+
+    writeMpFontHeader(stdout, &inpam);
+
+    convertRaster(&inpam, stdout);
+
+    return 0;
+}
diff --git a/converter/other/pamtooctaveimg.c b/converter/other/pamtooctaveimg.c
new file mode 100644
index 00000000..b090281d
--- /dev/null
+++ b/converter/other/pamtooctaveimg.c
@@ -0,0 +1,241 @@
+/* ----------------------------------------------------------------------
+ *
+ * Convert a Netpbm file to the GNU Octave image format
+ * by Scott Pakin <scott+pbm@pakin.org>
+ *
+ * ----------------------------------------------------------------------
+ *
+ * Copyright information is at end of file.
+ * ----------------------------------------------------------------------
+ */
+
+#include <assert.h>
+#include <stdio.h>
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "nstring.h"
+#include "pam.h"
+#include "pammap.h"
+
+typedef struct {
+    double comp[3];
+        /* comp[0] is red; comp[1] is green; comp[2] is blue */
+} octaveColor;
+
+typedef struct {
+    struct pam pam;
+    unsigned int nColors;
+    tuplehash hash;
+    unsigned int paletteAlloc;
+        /* 'palette' array has this many slots allocated.  Only the first
+           'nColors' are meaningful.
+        */
+    octaveColor * palette;
+    double normalizer;
+        /* 1/maxval */
+} cmap;
+
+
+
+static void
+initCmap(cmap * const cmapP,
+         sample const maxval) {
+
+    cmapP->pam.size             = sizeof(cmapP->pam.size);
+    cmapP->pam.len              = PAM_STRUCT_SIZE(tuple_type);
+    cmapP->pam.depth            = 3;
+    cmapP->pam.maxval           = maxval;
+    cmapP->pam.bytes_per_sample = pnm_bytespersample(maxval);
+
+    cmapP->normalizer   = 1.0/maxval;
+    cmapP->nColors      = 0;
+    cmapP->paletteAlloc = 0;
+    cmapP->palette      = NULL;
+    cmapP->hash         = pnm_createtuplehash();
+}
+
+
+
+static void
+termCmap(cmap * const cmapP) {
+    pnm_destroytuplehash(cmapP->hash);
+
+    free(cmapP->palette);
+}
+
+
+
+static void
+findOrAddColor(tuple          const color,
+               cmap *         const cmapP,
+               unsigned int * const colorIndexP) {
+/*----------------------------------------------------------------------------
+  Return as *colorIndexP the colormap index of color 'color' in
+  colormap *cmapP.  If the color isn't in the map, give it a new
+  colormap index, put it in the colormap, and return that.
+-----------------------------------------------------------------------------*/
+    bool found;
+    int colorIndex;
+
+    pnm_lookuptuple(&cmapP->pam, cmapP->hash, color, &found, &colorIndex);
+
+    if (!found) {
+        bool fits;
+        unsigned int plane;
+
+        colorIndex = cmapP->nColors++;
+
+        if (cmapP->nColors > cmapP->paletteAlloc) {
+            cmapP->paletteAlloc *= 2;
+            REALLOCARRAY(cmapP->palette, cmapP->nColors);
+        }
+        for (plane = 0; plane < 3; ++plane)
+            cmapP->palette[colorIndex].comp[plane] =
+                color[plane] * cmapP->normalizer;
+
+        pnm_addtotuplehash(&cmapP->pam, cmapP->hash, color, colorIndex, &fits);
+
+        if (!fits)
+            pm_error("Out of memory constructing color map, on %uth color",
+                     cmapP->nColors);
+    }
+    *colorIndexP = colorIndex;
+}
+
+
+
+static void
+outputColormap(FILE * const ofP,
+               cmap   const cmap) {
+/*----------------------------------------------------------------------------
+  Output the colormap as a GNU Octave matrix.
+-----------------------------------------------------------------------------*/
+    unsigned int colorIndex;
+
+    fprintf(ofP, "# name: map\n");
+    fprintf(ofP, "# type: matrix\n");
+    fprintf(ofP, "# rows: %u\n", cmap.nColors);
+    fprintf(ofP, "# columns: 3\n");
+
+    for (colorIndex = 0; colorIndex < cmap.nColors; ++colorIndex) {
+        unsigned int plane;
+
+        assert(cmap.pam.depth == 3);
+
+        for (plane = 0; plane < 3; ++plane)
+            fprintf(ofP, " %.10f", cmap.palette[colorIndex].comp[plane]);
+
+        fprintf(ofP, "\n");
+    }
+}
+
+
+
+static void
+convertToOctave(FILE * const ifP,
+                FILE * const ofP) {
+
+    struct pam inpam;
+    tuple * inRow;
+    unsigned int row;
+    cmap cmap;
+
+    pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(allocation_depth));
+
+    pnm_setminallocationdepth(&inpam, 3);
+    
+    /* Output the image as a GNU Octave matrix.  For each row of the
+     * input file we immediately output indexes into the colormap then,
+     * when we're finished, we output the colormap as a second
+     * matrix. */
+    fprintf(ofP, "# name: img\n");
+    fprintf(ofP, "# type: matrix\n");
+    fprintf(ofP, "# rows: %u\n", inpam.height);
+    fprintf(ofP, "# columns: %u\n", inpam.width);
+
+    initCmap(&cmap, inpam.maxval);
+
+    inRow = pnm_allocpamrow(&inpam);
+    for (row = 0; row < inpam.height; ++row) {
+        unsigned int col;
+        pnm_readpamrow(&inpam, inRow);
+
+        pnm_makerowrgb(&inpam, inRow);
+
+        for (col = 0; col < inpam.width; ++col) {
+            unsigned int colorIndex;
+            findOrAddColor(inRow[col], &cmap, &colorIndex);
+            fprintf(ofP, " %u", colorIndex + 1);
+        }
+        fprintf(ofP, "\n");
+    }
+    pm_message("%u colors in palette", cmap.nColors);
+
+    pnm_freepamrow(inRow);
+    outputColormap(ofP, cmap);
+
+    termCmap(&cmap);
+}
+
+
+
+int
+main(int argc, char *argv[]) {
+
+    FILE * ifP;
+    const char * inputName;
+
+    pnm_init(&argc, argv);
+
+    inputName = argc-1 > 0 ? argv[1] : "-";
+
+    ifP = pm_openr(inputName);
+    
+    if (streq(inputName, "-"))
+        fprintf(stdout, "# Created by pamtooctave\n");
+    else
+        fprintf(stdout, "# Created from '%s' by pamtooctave\n", inputName);
+
+    convertToOctave(ifP, stdout);
+    
+    pm_close(ifP);
+
+    return 0;
+}
+
+
+
+/*
+ * Copyright (C) 2007 Scott Pakin <scott+pbm@pakin.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------
+ */
diff --git a/converter/other/pamtopam.c b/converter/other/pamtopam.c
new file mode 100644
index 00000000..cae54060
--- /dev/null
+++ b/converter/other/pamtopam.c
@@ -0,0 +1,57 @@
+/*=============================================================================
+                               pamtopam
+===============================================================================
+  Part of the Netpbm package.
+
+  Copy PAM and PNM (i.e. PBM, PGM, or PPM) images from Standard Input
+  to Standard Output (while converting PNM images to PAM)
+
+  By Paul Bolle October 2007.
+
+  Contributed to the public domain by its author.
+=============================================================================*/
+
+#include "pm_c_util.h"
+#include "pam.h"
+
+int
+main(int argc, const char * argv[]) {
+
+    bool       eof;     /* no more images in input stream */
+    struct pam inpam;   /* Input PAM image */
+    struct pam outpam;  /* Output PAM image */
+
+    pm_proginit(&argc, argv);
+
+    if (argc-1 != 0)
+        pm_error("Program takes no arguments.  Input is from Standard Input");
+
+    eof = FALSE;
+    while (!eof) {
+        pnm_readpaminit(stdin, &inpam, PAM_STRUCT_SIZE(tuple_type));
+
+        outpam = inpam;
+        outpam.file = stdout;
+        outpam.format = PAM_FORMAT;
+
+        pnm_writepaminit(&outpam);
+
+        {
+            tuple * tuplerow;
+
+            tuplerow = pnm_allocpamrow(&inpam);
+            {
+                unsigned int row;
+
+                for (row = 0; row < inpam.height; ++row) {
+                    pnm_readpamrow(&inpam, tuplerow);
+                    pnm_writepamrow(&outpam, tuplerow);
+                }
+            }
+            pnm_freepamrow(tuplerow);
+        }
+        pnm_nextimage(stdin, &eof);
+    }
+
+    return 0;
+}
diff --git a/converter/other/pamtopfm.c b/converter/other/pamtopfm.c
index ee44eeb5..129b8eee 100644
--- a/converter/other/pamtopfm.c
+++ b/converter/other/pamtopfm.c
@@ -15,6 +15,7 @@
 #include <string.h>
 #include <assert.h>
 
+#include "pm_c_util.h"
 #include "pam.h"
 #include "pm_gamma.h"
 #include "shhopt.h"
diff --git a/converter/other/pamtopnm.c b/converter/other/pamtopnm.c
index cc1164da..86f6514c 100644
--- a/converter/other/pamtopnm.c
+++ b/converter/other/pamtopnm.c
@@ -12,6 +12,7 @@
 
 #include <string.h>
 
+#include "pm_c_util.h"
 #include "pam.h"
 #include "shhopt.h"
 #include "mallocvar.h"
@@ -108,6 +109,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 +119,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/Makefile b/converter/other/pamtosvg/Makefile
index ba03fd68..8b033020 100644
--- a/converter/other/pamtosvg/Makefile
+++ b/converter/other/pamtosvg/Makefile
@@ -5,7 +5,7 @@ endif
 SUBDIR = converter/other/pamtosvg
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
 BINARIES = pamtosvg
 
@@ -47,7 +47,7 @@ MERGEBINARIES = $(BINARIES)
 
 all: $(BINARIES)
 
-include $(SRCDIR)/Makefile.common
+include $(SRCDIR)/common.mk
 
 pamtosvg: $(PAMTOSVG_OBJECTS) $(NETPBMLIB) $(LIBOPT)
 	$(LD) -o $@ $(PAMTOSVG_OBJECTS) \
diff --git a/converter/other/pamtosvg/curve.c b/converter/other/pamtosvg/curve.c
index cc8aeb59..369a0cd3 100644
--- a/converter/other/pamtosvg/curve.c
+++ b/converter/other/pamtosvg/curve.c
@@ -42,18 +42,19 @@ int_to_real_coord(pm_pixelcoord const int_coord) {
 
 /* Return an entirely empty curve.  */
 
-curve_type
-new_curve (void)
-{
-  curve_type curve;
-  MALLOCVAR_NOFAIL(curve);
-  curve->point_list = NULL;
-  CURVE_LENGTH (curve) = 0;
-  CURVE_CYCLIC (curve) = false;
-  CURVE_START_TANGENT (curve) = CURVE_END_TANGENT (curve) = NULL;
-  PREVIOUS_CURVE (curve) = NEXT_CURVE (curve) = NULL;
+curve *
+new_curve(void) {
+  curve * curveP;
 
-  return curve;
+  MALLOCVAR_NOFAIL(curveP);
+
+  curveP->point_list = NULL;
+  CURVE_LENGTH(curveP) = 0;
+  CURVE_CYCLIC(curveP) = false;
+  PREVIOUS_CURVE(curveP)  = NULL;
+  NEXT_CURVE(curveP)      = NULL;
+
+  return curveP;
 }
 
 
@@ -71,23 +72,39 @@ copy_most_of_curve (curve_type old_curve)
   return curve;
 }
 
+void
+move_curve(curve * const dstP,
+           curve * const srcP) {
+
+    /* Move ownership of dynamically allocated memory from source 
+       to destination; destroy source.
+    */
+
+   if (CURVE_LENGTH(dstP) > 0)
+       free(dstP->point_list);
+    
+   *dstP = *srcP;
+
+   free(srcP);
+}
+
+
 
 /* The length of CURVE will be zero if we ended up not being able to fit
    it (which in turn implies a problem elsewhere in the program, but at
    any rate, we shouldn't try here to free the nonexistent curve).  */
 
 void
-free_curve (curve_type curve)
-{
-  if (CURVE_LENGTH (curve) > 0)
-    free (curve->point_list);
-  if (CURVE_START_TANGENT (curve))
-    free (CURVE_START_TANGENT (curve));
-  if (CURVE_END_TANGENT (curve))
-    free (CURVE_END_TANGENT (curve));
+free_curve(curve * const curveP) {
+
+   if (CURVE_LENGTH(curveP) > 0)
+       free(curveP->point_list);
+
+   free(curveP);
 }
 
 
+
 void
 append_point(curve_type  const curve,
              float_coord const coord) {
@@ -123,99 +140,84 @@ append_pixel(curve_type    const curve,
     }									\
   while (0)
 
+
+
 void
-log_curve (curve_type curve, bool print_t)
-{
-  unsigned this_point;
-
-  if (!log_file) return;
-
-  LOG1 ("curve id = %lx:\n", (unsigned long) curve);
-  LOG1 ("  length = %u.\n", CURVE_LENGTH (curve));
-  if (CURVE_CYCLIC (curve))
-    LOG ("  cyclic.\n");
-
-  /* It should suffice to check just one of the tangents for being null
-     -- either they both should be, or neither should be.  */
-  if (CURVE_START_TANGENT (curve) != NULL)
-    LOG4 ("  tangents = (%.3f,%.3f) & (%.3f,%.3f).\n",
-          CURVE_START_TANGENT (curve)->dx, CURVE_START_TANGENT (curve)->dy,
-          CURVE_END_TANGENT (curve)->dx, CURVE_END_TANGENT (curve)->dy);
-
-  LOG ("  ");
-
-  /* If the curve is short enough, don't use ellipses.  */
-  if (CURVE_LENGTH (curve) <= NUM_TO_PRINT * 2)
-    {
-      for (this_point = 0; this_point < CURVE_LENGTH (curve); this_point++)
-        {
-          LOG_CURVE_POINT (curve, this_point, print_t);
-          LOG (" ");
-
-          if (this_point != CURVE_LENGTH (curve) - 1
-              && (this_point + 1) % NUM_TO_PRINT == 0)
-            LOG ("\n  ");
+log_curve(curve * const curveP,
+          bool    const print_t) {
+
+    if (!log_file)
+        return;
+
+    LOG1("curve id = %lx:\n", (unsigned long) curveP);
+    LOG1("  length = %u.\n", CURVE_LENGTH(curveP));
+    if (CURVE_CYCLIC(curveP))
+        LOG("  cyclic.\n");
+
+    LOG("  ");
+
+    /* If the curve is short enough, don't use ellipses.  */
+    if (CURVE_LENGTH(curveP) <= NUM_TO_PRINT * 2) {
+        unsigned int thisPoint;
+    
+        for (thisPoint = 0; thisPoint < CURVE_LENGTH(curveP); ++thisPoint) {
+            LOG_CURVE_POINT(curveP, thisPoint, print_t);
+            LOG(" ");
+
+            if (thisPoint != CURVE_LENGTH(curveP) - 1
+                && (thisPoint + 1) % NUM_TO_PRINT == 0)
+                LOG("\n  ");
         }
-    }
-  else
-    {
-      for (this_point = 0;
-           this_point < NUM_TO_PRINT && this_point < CURVE_LENGTH (curve);
-           this_point++)
-        {
-          LOG_CURVE_POINT (curve, this_point, print_t);
-          LOG (" ");
+    } else {
+        unsigned int thisPoint;
+        for (thisPoint = 0;
+             thisPoint < NUM_TO_PRINT && thisPoint < CURVE_LENGTH(curveP);
+             ++thisPoint) {
+            LOG_CURVE_POINT(curveP, thisPoint, print_t);
+            LOG(" ");
         }
 
-      LOG ("...\n   ...");
+        LOG("...\n   ...");
 
-      for (this_point = CURVE_LENGTH (curve) - NUM_TO_PRINT;
-           this_point < CURVE_LENGTH (curve);
-           this_point++)
-        {
-          LOG (" ");
-          LOG_CURVE_POINT (curve, this_point, print_t);
+        for (thisPoint = CURVE_LENGTH(curveP) - NUM_TO_PRINT;
+             thisPoint < CURVE_LENGTH(curveP);
+             ++thisPoint) {
+            LOG(" ");
+            LOG_CURVE_POINT(curveP, thisPoint, print_t);
         }
     }
-
-  LOG (".\n");
+    LOG(".\n");
 }
 
 
 /* Like `log_curve', but write the whole thing.  */
 
 void
-log_entire_curve (curve_type curve)
-{
-  unsigned this_point;
+log_entire_curve(curve * const curveP) {
 
-  if (!log_file) return;
+    unsigned int thisPoint;
 
-  LOG1 ("curve id = %lx:\n", (unsigned long) curve);
-  LOG1 ("  length = %u.\n", CURVE_LENGTH (curve));
-  if (CURVE_CYCLIC (curve))
-    LOG ("  cyclic.\n");
+    if (!log_file)
+        return;
 
-  /* It should suffice to check just one of the tangents for being null
-     -- either they both should be, or neither should be.  */
-  if (CURVE_START_TANGENT (curve) != NULL)
-    LOG4 ("  tangents = (%.3f,%.3f) & (%.3f,%.3f).\n",
-          CURVE_START_TANGENT (curve)->dx, CURVE_START_TANGENT (curve)->dy,
-          CURVE_END_TANGENT (curve)->dx, CURVE_END_TANGENT (curve)->dy);
+    LOG1("curve id = %lx:\n", (unsigned long) curveP);
+    LOG1("  length = %u.\n", CURVE_LENGTH(curveP));
+    if (CURVE_CYCLIC(curveP))
+        LOG("  cyclic.\n");
 
-  LOG (" ");
+    LOG(" ");
 
-  for (this_point = 0; this_point < CURVE_LENGTH (curve); this_point++)
-    {
-      LOG (" ");
-      LOG_CURVE_POINT (curve, this_point, true);
-      /* Compiler warning `Condition is always true' can be ignored */
+    for (thisPoint = 0; thisPoint < CURVE_LENGTH(curveP); ++thisPoint) {
+        LOG(" ");
+        LOG_CURVE_POINT(curveP, thisPoint, true);
+        /* Compiler warning `Condition is always true' can be ignored */
     }
 
-  LOG (".\n");
+    LOG(".\n");
 }
 
 
+
 /* Return an initialized but empty curve list.  */
 
 curve_list_type
@@ -233,19 +235,16 @@ new_curve_list (void)
 /* Free a curve list and all the curves it contains.  */
 
 void
-free_curve_list(curve_list_type * const curve_list) {
+free_curve_list(curve_list_type * const curveListP) {
 
-  unsigned this_curve;
+    unsigned int thisCurve;
 
-  for (this_curve = 0; this_curve < curve_list->length; this_curve++)
-    {
-      free_curve (curve_list->data[this_curve]);
-      free (curve_list->data[this_curve]);
-    }
+    for (thisCurve = 0; thisCurve < curveListP->length; ++thisCurve)
+        free_curve(curveListP->data[thisCurve]);
 
-  /* If the character was empty, it won't have any curves.  */
-  if (curve_list->data != NULL)
-    free (curve_list->data);
+    /* If the character was empty, it won't have any curves.  */
+    if (curveListP->data != NULL)
+        free (curveListP->data);
 }
 
 
diff --git a/converter/other/pamtosvg/curve.h b/converter/other/pamtosvg/curve.h
index ee046620..ba5f1833 100644
--- a/converter/other/pamtosvg/curve.h
+++ b/converter/other/pamtosvg/curve.h
@@ -20,19 +20,27 @@ typedef struct {
 
 
 
-struct curve {
+typedef struct curve {
 /*----------------------------------------------------------------------------
   An ordered list of contiguous points in the raster, with no corners
   in it.  I.e. something that could reasonably be fit to a spline.
 -----------------------------------------------------------------------------*/
     point_type *   point_list;
+        /* Array of the points in the curve.  Malloc'ed.  Size is 'length'.
+           if 'length' is zero, this is meaningless and no memory is
+           allocated.
+        */
     unsigned       length;
+        /* Number of points in the curve */
     bool           cyclic;
-    vector_type *  start_tangent;
-    vector_type *  end_tangent;
+
+    /* 'previous' and 'next' links are for the doubly linked list which is
+       a chain of all curves in an outline.  The chain is a cycle for a
+       closed outline and linear for an open outline.
+    */
     struct curve * previous;
     struct curve * next;
-};
+} curve;
 
 typedef struct curve * curve_type;
 
@@ -61,9 +69,6 @@ typedef struct curve * curve_type;
   ? CURVE_CYCLIC (c) ? (signed int) CURVE_LENGTH (c) + (signed int) (n) - 1 : -1\
   : (signed int) (n) - 1)
 
-/* The tangents at the endpoints are computed using the neighboring curves.  */
-#define CURVE_START_TANGENT(c) ((c)->start_tangent)
-#define CURVE_END_TANGENT(c) ((c)->end_tangent)
 #define PREVIOUS_CURVE(c) ((c)->previous)
 #define NEXT_CURVE(c) ((c)->next)
 
@@ -74,17 +79,23 @@ extern curve_type new_curve (void);
 /* Return a curve the same as C, except without any points.  */
 extern curve_type copy_most_of_curve (curve_type c);
 
-/* Free the memory C uses.  */
-extern void free_curve (curve_type c);
+void
+move_curve(curve * const dstP,
+           curve * const srcP);
+
+void
+free_curve(curve * const curveP);
+
+/* 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);
@@ -99,11 +110,12 @@ typedef struct {
 /*----------------------------------------------------------------------------
    An ordered list of contiguous curves of a particular color.
 -----------------------------------------------------------------------------*/
-    curve_type * data;
-    unsigned     length;
-    bool         clockwise;
-    pixel        color;
-    bool         open;
+    curve ** data;
+        /* data[i] is the handle of the ith curve in the list */
+    unsigned length;
+    bool     clockwise;
+    pixel    color;
+    bool     open;
         /* The curve list does not form a closed shape;  i.e. the last
            curve doesn't end where the first one starts.
         */
diff --git a/converter/other/pamtosvg/fit.c b/converter/other/pamtosvg/fit.c
index 6bc2fe88..5ba7a2f6 100644
--- a/converter/other/pamtosvg/fit.c
+++ b/converter/other/pamtosvg/fit.c
@@ -54,21 +54,7 @@ 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 +72,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 +132,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 +279,283 @@ 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 be fit only 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;
+        }
+    }
+
+  /* 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 * const curveP,
+                   bool    const clockwise) {
+
+    unsigned int const offset = CURVE_CYCLIC(curveP) ? 0 : 1;
+    curve * const trimmedCurveP = copy_most_of_curve(curveP);
+
+    pm_pixelcoord previous;
+    unsigned int i;
+
+    if (!CURVE_CYCLIC(curveP))
+        append_pixel(trimmedCurveP,
+                     real_to_int_coord(CURVE_POINT(curveP, 0)));
+
+    previous = real_to_int_coord(CURVE_POINT(curveP,
+                                             CURVE_PREV(curveP, offset)));
+
+    for (i = offset; i < CURVE_LENGTH(curveP) - offset; ++i) {
+        pm_pixelcoord const current =
+            real_to_int_coord(CURVE_POINT(curveP, i));
+        pm_pixelcoord const next =
+            real_to_int_coord(CURVE_POINT(curveP, CURVE_NEXT(curveP, 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(trimmedCurveP, current);
+        }
+    }
+
+    if (!CURVE_CYCLIC(curveP))
+        append_pixel(trimmedCurveP,
+                     real_to_int_coord(LAST_CURVE_POINT(curveP)));
+
+    if (CURVE_LENGTH(trimmedCurveP) == CURVE_LENGTH(curveP))
+        LOG(" (none)");
+
+    LOG(".\n");
+
+    move_curve(curveP, trimmedCurveP);
+}
+
+
+
+static void
+filter(curve *             const curveP,
+       fitting_opts_type * const fittingOptsP) {
+/*----------------------------------------------------------------------------
+  Smooth the curve by adding in neighboring points.  Do this
+  fittingOptsP->filter_iterations times.  But don't change the corners.
+-----------------------------------------------------------------------------*/
+    unsigned int const offset = CURVE_CYCLIC(curveP) ? 0 : 1;
+
+    unsigned int iteration, thisPoint;
+    float_coord prevNewPoint;
+    
+    /* 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(curveP) < 5) {
+        LOG1("Length is %u, not enough to filter.\n", CURVE_LENGTH(curveP));
+        return;
+    }
+
+    prevNewPoint.x = FLT_MAX;
+    prevNewPoint.y = FLT_MAX;
+    prevNewPoint.z = FLT_MAX;
+    
+    for (iteration = 0;
+         iteration < fittingOptsP->filter_iterations;
+         ++iteration) {
+        curve * const newcurveP = copy_most_of_curve(curveP);
+
+        bool collapsed;
+        
+        collapsed = false;  /* initial value */
+
+        /* Keep the first point on the curve.  */
+        if (offset)
+            append_point(newcurveP, CURVE_POINT(curveP, 0));
+        
+        for (thisPoint = offset;
+             thisPoint < CURVE_LENGTH(curveP) - offset;
+             ++thisPoint) {
+            vector_type in, out, sum;
+            float_coord newPoint;
+            
+            /* 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(curveP, thisPoint);
+            
+            prev = CURVE_PREV(curveP, thisPoint);
+            prevprev = CURVE_PREV(curveP, prev);
+            next = CURVE_NEXT(curveP, thisPoint);
+            nextnext = CURVE_NEXT(curveP, 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(curveP, prev), candidate));
+            if (prevprev >= 0)
+                in = Vadd(in,
+                          Psubtract(CURVE_POINT(curveP, 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(curveP, next), candidate));
+            if (nextnext < CURVE_LENGTH(curveP))
+                out = Vadd(out,
+                           Psubtract(CURVE_POINT(curveP, nextnext),
+                                     candidate));
+            
+            /* Start with the old point.  */
+            newPoint = candidate;
+            sum = Vadd(in, out);
+            /* We added 2*n+2 points, so we have to divide the sum by 2*n+2 */
+            newPoint.x += sum.dx / 6;
+            newPoint.y += sum.dy / 6;
+            newPoint.z += sum.dz / 6;
+            if (fabs(prevNewPoint.x - newPoint.x) < 0.3
+                && fabs (prevNewPoint.y - newPoint.y) < 0.3
+                && fabs (prevNewPoint.z - newPoint.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(newcurveP, prevNewPoint = newPoint);
+        }
+        
+        if (collapsed)
+            free_curve(newcurveP);
+        else {
+            /* Just as with the first point, we have to keep the last
+               point.
+            */
+            if (offset)
+                append_point(newcurveP, LAST_CURVE_POINT(curveP));
+            
+            /* Set the original curve to the newly filtered one, and go
+               again.
+            */
+            move_curve(curveP, newcurveP);
+        }
+    }
+    log_curve(curveP, false);
+}
+
+
+
+static void
 removeAdjacent(index_list_type *   const cornerListP,
                pixel_outline_type  const outline,
                fitting_opts_type * const fittingOptsP,
@@ -340,25 +686,27 @@ makeOutlineOneCurve(pixel_outline_type const outline,
                     curve_list_type *  const curveListP) {
 /*----------------------------------------------------------------------------
    Add to *curveListP a single curve that represents the outline 'outline'.
+
+   That curve does not have beginning and ending slope information.
 -----------------------------------------------------------------------------*/
-    curve_type curve;
+    curve * curveP;
     unsigned int pixelSeq;
 
-    curve = new_curve();
-    
+    curveP = new_curve();
+
     for (pixelSeq = 0; pixelSeq < O_LENGTH(outline); ++pixelSeq)
-        append_pixel(curve, O_COORDINATE(outline, pixelSeq));
+        append_pixel(curveP, O_COORDINATE(outline, pixelSeq));
     
-    if (curveListP->open)
-        CURVE_CYCLIC(curve) = false;
+    if (outline.open)
+        CURVE_CYCLIC(curveP) = false;
     else
-        CURVE_CYCLIC(curve) = true;
+        CURVE_CYCLIC(curveP) = true;
     
     /* Make it a one-curve cycle */
-    NEXT_CURVE(curve)     = curve;
-    PREVIOUS_CURVE(curve) = curve;
+    NEXT_CURVE(curveP)     = curveP;
+    PREVIOUS_CURVE(curveP) = curveP;
 
-    append_curve(curveListP, curve);
+    append_curve(curveListP, curveP);
 }
 
 
@@ -367,12 +715,22 @@ static void
 addCurveStartingAtCorner(pixel_outline_type const outline,
                          index_list_type    const cornerList,
                          unsigned int       const cornerSeq,
-                         curve_list_type *  const curveListP) {
+                         curve_list_type *  const curveListP,
+                         curve **           const curCurvePP) {
+/*----------------------------------------------------------------------------
+   Add to the list *curveListP a new curve that starts at the cornerSeq'th
+   corner in outline 'outline' (whose corners are 'cornerList') and
+   goes to the next corner (or the end of the outline if no next corner).
+
+   Furthermore, add that curve to the curve chain whose end is pointed
+   to by *curCurvePP (NULL means chain is empty).
 
+   Don't include beginning and ending slope information for that curve.
+-----------------------------------------------------------------------------*/
     unsigned int const cornerPixelSeq = GET_INDEX(cornerList, cornerSeq);
     
     unsigned int lastPixelSeq;
-    curve_type curve;
+    curve * curveP;
     unsigned int pixelSeq;
     
     if (cornerSeq + 1 >= cornerList.length)
@@ -382,20 +740,23 @@ addCurveStartingAtCorner(pixel_outline_type const outline,
         /* Go through the next corner */
         lastPixelSeq = GET_INDEX(cornerList, cornerSeq + 1);
     
-    curve = new_curve();
+    curveP = new_curve();
 
     for (pixelSeq = cornerPixelSeq; pixelSeq <= lastPixelSeq; ++pixelSeq)
-        append_pixel(curve, O_COORDINATE(outline, pixelSeq));
+        append_pixel(curveP, O_COORDINATE(outline, pixelSeq));
     
+    append_curve(curveListP, curveP);
     {
-        /* Add curve to end of chain */
-        if (!CURVE_LIST_EMPTY(*curveListP)) {
-            curve_type const previousCurve = LAST_CURVE_LIST_ELT(*curveListP);
-            NEXT_CURVE(previousCurve) = curve;
-            PREVIOUS_CURVE(curve)     = previousCurve;
+        /* Add the new curve to the outline chain */
+
+        curve * const oldCurCurveP = *curCurvePP;
+
+        if (oldCurCurveP) {
+            NEXT_CURVE(oldCurCurveP) = curveP;
+            PREVIOUS_CURVE(curveP)   = oldCurCurveP;
         }
+        *curCurvePP = curveP;
     }
-    append_curve(curveListP, curve);
 }
 
 
@@ -421,53 +782,60 @@ divideOutlineWithCorners(pixel_outline_type const outline,
    corner).
 
    Assume there is at least one corner.
+
+   The curves do not have beginning and ending slope information.
 -----------------------------------------------------------------------------*/
     unsigned int const firstCurveSeq = CURVE_LIST_LENGTH(*curveListP);
         /* Index in curve list of the first curve we add */
     unsigned int cornerSeq;
+    curve * curCurveP;
+        /* Pointer to the curve we most recently added for this outline.
+           Null if none
+        */
 
     assert(cornerList.length > 0);
 
+    curCurveP = NULL;  /* No curves in outline chain yet */
+
     if (outline.open) {
-        /* Start with a curve that contains the point up to the first
+        /* Start with a curve that contains the points up to the first
            corner
         */
-        curve_type curve;
+        curve * curveP;
         unsigned int pixelSeq;
         
-        curve = new_curve();
+        curveP = new_curve();
 
         for (pixelSeq = 0; pixelSeq <= GET_INDEX(cornerList, 0); ++pixelSeq)
-            append_pixel(curve, O_COORDINATE(outline, pixelSeq));
+            append_pixel(curveP, O_COORDINATE(outline, pixelSeq));
 
-        append_curve(curveListP, curve);
-    } else
+        append_curve(curveListP, curveP);
+        curCurveP = curveP;  /* Only curve in outline chain now */
+    } else {
         /* We'll pick up the pixels before the first corner at the end */
-
+    }
     /* Add to the list a curve that starts at each corner and goes
        through the following corner, or the end of the outline if
        there is no following corner.  Do it in order of the corners.
     */
     for (cornerSeq = 0; cornerSeq < cornerList.length; ++cornerSeq)
-        addCurveStartingAtCorner(outline, cornerList, cornerSeq, curveListP);
+        addCurveStartingAtCorner(outline, cornerList, cornerSeq, curveListP,
+                                 &curCurveP);
 
     if (!outline.open) {
         /* Come around to the start of the curve list -- add the pixels
            before the first corner to the last curve, and chain the last
            curve to the first one.
         */
-        curve_type const firstCurve =
-            CURVE_LIST_ELT(*curveListP, firstCurveSeq);
-        curve_type const lastCurve  =
-            LAST_CURVE_LIST_ELT(*curveListP);
+        curve * const firstCurveP = CURVE_LIST_ELT(*curveListP, firstCurveSeq);
 
         unsigned int pixelSeq;
 
         for (pixelSeq = 0; pixelSeq <= GET_INDEX(cornerList, 0); ++pixelSeq)
-            append_pixel(lastCurve, O_COORDINATE(outline, pixelSeq));
+            append_pixel(curCurveP, O_COORDINATE(outline, pixelSeq));
 
-        NEXT_CURVE(lastCurve)      = firstCurve;
-        PREVIOUS_CURVE(firstCurve) = lastCurve;
+        NEXT_CURVE(curCurveP)       = firstCurveP;
+        PREVIOUS_CURVE(firstCurveP) = curCurveP;
     }
 }
 
@@ -501,6 +869,9 @@ split_at_corners(pixel_outline_list_type const pixel_list,
    To preserve this information, we return an array of curve_lists, one
    element (which in turn consists of several curves, one between each
    pair of corners) for each element in PIXEL_LIST.
+
+   The curves we return do not have beginning and ending slope
+   information.
 -----------------------------------------------------------------------------*/
     unsigned outlineSeq;
     curve_list_array_type curve_array;
@@ -797,27 +1168,30 @@ spline_linear_enough(spline_type *             const spline,
 /* Forward declaration for recursion */
 
 static spline_list_type *
-fitCurve(curve_type                const curve,
-         const fitting_opts_type * const fitting_opts,
-         at_exception_type *       const exception);
+fitCurve(curve *                   const curveP,
+         vector_type               const begSlope,
+         vector_type               const endSlope,
+         const fitting_opts_type * const fittingOptsP,
+         at_exception_type *       const exceptionP);
 
 
 
 static spline_list_type *
-fit_with_line(curve_type const curve) {
+fitWithLine(curve * const curveP) {
 /*----------------------------------------------------------------------------
-  This routine returns the curve fitted to a straight line in a very
-  simple way: make the first and last points on the curve be the
-  endpoints of the line.  This simplicity is justified because we are
-  called only on very short curves.
+  Return a list of splines that fit curve *curveP in a very simple way:
+  a single spline which is a straight line through the first and last
+  points on the curve.
+
+  This simplicity is useful only on a very short curve.
 -----------------------------------------------------------------------------*/
     spline_type line;
 
     LOG("Fitting with straight line:\n");
 
     SPLINE_DEGREE(line) = LINEARTYPE;
-    START_POINT(line) = CONTROL1(line) = CURVE_POINT(curve, 0);
-    END_POINT(line) = CONTROL2(line) = LAST_CURVE_POINT(curve);
+    START_POINT(line)   = CONTROL1(line) = CURVE_POINT(curveP, 0);
+    END_POINT(line)     = CONTROL2(line) = LAST_CURVE_POINT(curveP);
 
     /* Make sure that this line is never changed to a cubic.  */
     SPLINE_LINEARITY(line) = 0;
@@ -838,98 +1212,123 @@ fit_with_line(curve_type const curve) {
 #define B3(t) CUBE (t)
 
 static spline_type
-fit_one_spline(curve_type          const curve, 
-               at_exception_type * const exception) {
+fitOneSpline(curve *             const curveP, 
+             vector_type         const begSlope,
+             vector_type         const endSlope,
+             at_exception_type * const exceptionP) {
 /*----------------------------------------------------------------------------
-   Our job here is to find alpha1 (and alpha2), where t1_hat (t2_hat) is
-   the tangent to CURVE at the starting (ending) point, such that:
+  Return a spline that fits the points of curve *curveP,
+  with slope 'begSlope' at its beginning and 'endSlope' at its end.
 
-   control1 = alpha1 * t1_hat + starting point
-   control2 = alpha2 * t2_hat + ending_point
+  Make it a cubic spline.
+-----------------------------------------------------------------------------*/
+    /* We already have the start and end points of the spline, so all
+      we need are the control points.  And we know in what direction
+      each control point is from its respective end point, so all we
+      need to figure out is its distance.  (The control point's
+      distance from the end point is an indication of how long the
+      curve goes in its direction).
 
-   and the resulting spline (starting_point .. control1 and control2 ..
-   ending_point) minimizes the least-square error from CURVE.
+      We call the distance from an end point to the associated control
+      point "alpha".
 
-   See pp.57--59 of the Phoenix thesis.
+      We want to find starting and ending alpha that minimize the
+      least-square error in approximating *curveP with the spline.
+
+      How we do that is a complete mystery to me, but the original author
+      said to see pp.57--59 of the Phoenix thesis.  I haven't seen that.
+
+      In our expression of the math here, we use a struct with "beg" and
+      "end" members where the paper uses a matrix with "1" and "2"
+      subscripts, respectively.  A C array is a closer match to a math
+      matrix, but we think the struct is easier to read.
+
+      The B?(t) here corresponds to B_i^3(U_i) there.
+      The Bernstein polynomials of degree n are defined by
+      B_i^n(t) = { n \choose i } t^i (1-t)^{n-i}, i = 0..n
 
-   The B?(t) here corresponds to B_i^3(U_i) there.
-   The Bernshte\u in polynomials of degree n are defined by
-   B_i^n(t) = { n \choose i } t^i (1-t)^{n-i}, i = 0..n
------------------------------------------------------------------------------*/
-    /* Since our arrays are zero-based, the `C0' and `C1' here correspond
-       to `C1' and `C2' in the paper. 
     */
-    float X_C1_det, C0_X_det, C0_C1_det;
-    float alpha1, alpha2;
+    struct vectorPair {
+        vector_type beg;
+        vector_type end;
+    };
+    struct vectorPair tang;
+
+    float X_Cend_det, Cbeg_X_det, C_det;
     spline_type spline;
-    vector_type start_vector, end_vector;
+    vector_type begVector, endVector;
     unsigned i;
-    vector_type * A;
-    vector_type t1_hat;
-    vector_type t2_hat;
-    float C[2][2] = { { 0.0, 0.0 }, { 0.0, 0.0 } };
-    float X[2] = { 0.0, 0.0 };
+    struct vectorPair * A;  /* malloc'ed array */
+        /* I don't know the meaning of this array, but it is one entry for
+           each point in the curve (A[i] is for the ith point in the curve).
+        */
+    struct {
+        struct { float beg; float end; } beg;
+        struct { float beg; float end; } end;
+    } C;
+    struct { float beg; float end; } X;
 
-    t1_hat = *CURVE_START_TANGENT(curve);  /* initial value */
-    t2_hat = *CURVE_END_TANGENT(curve);    /* initial value */
+    tang.beg = begSlope; tang.end = endSlope;
 
-    MALLOCARRAY_NOFAIL(A, CURVE_LENGTH(curve) * 2);
+    MALLOCARRAY_NOFAIL(A, CURVE_LENGTH(curveP));
 
-    START_POINT(spline) = CURVE_POINT(curve, 0);
-    END_POINT(spline)   = LAST_CURVE_POINT(curve);
-    start_vector = make_vector(START_POINT(spline));
-    end_vector   = make_vector(END_POINT(spline));
+    BEG_POINT(spline) = CURVE_POINT(curveP, 0);
+    END_POINT(spline) = LAST_CURVE_POINT(curveP);
+    begVector = make_vector(BEG_POINT(spline));
+    endVector = make_vector(END_POINT(spline));
 
-    for (i = 0; i < CURVE_LENGTH(curve); ++i) {
-        A[(i << 1) + 0] = Vmult_scalar(t1_hat, B1(CURVE_T(curve, i)));
-        A[(i << 1) + 1] = Vmult_scalar(t2_hat, B2(CURVE_T(curve, i)));
+    for (i = 0; i < CURVE_LENGTH(curveP); ++i) {
+        A[i].beg = Vmult_scalar(tang.beg, B1(CURVE_T(curveP, i)));
+        A[i].end = Vmult_scalar(tang.end, B2(CURVE_T(curveP, i)));
     }
 
-    for (i = 0; i < CURVE_LENGTH(curve); ++i) {
+    C.beg.beg = 0.0; C.beg.end = 0.0; C.end.end = 0.0;  /* initial value */
+
+    X.beg = 0.0; X.end = 0.0; /* initial value */
+
+    for (i = 0; i < CURVE_LENGTH(curveP); ++i) {
+        struct vectorPair * const AP = &A[i];
         vector_type temp, temp0, temp1, temp2, temp3;
-        vector_type * Ai = A + (i << 1);
 
-        C[0][0] += Vdot(Ai[0], Ai[0]);
-        C[0][1] += Vdot(Ai[0], Ai[1]);
-        /* C[1][0] = C[0][1] (this is assigned outside the loop)  */
-        C[1][1] += Vdot(Ai[1], Ai[1]);
+        C.beg.beg += Vdot(AP->beg, AP->beg);
+        C.beg.end += Vdot(AP->beg, AP->end);
+        /* C.end.beg = Vdot(AP->end, AP->beg) is done outside of loop */
+        C.end.end += Vdot(AP->end, AP->end);
 
         /* Now the right-hand side of the equation in the paper.  */
-        temp0 = Vmult_scalar(start_vector, B0(CURVE_T(curve, i)));
-        temp1 = Vmult_scalar(start_vector, B1(CURVE_T(curve, i)));
-        temp2 = Vmult_scalar(end_vector, B2(CURVE_T(curve, i)));
-        temp3 = Vmult_scalar(end_vector, B3(CURVE_T(curve, i)));
+        temp0 = Vmult_scalar(begVector, B0(CURVE_T(curveP, i)));
+        temp1 = Vmult_scalar(begVector, B1(CURVE_T(curveP, i)));
+        temp2 = Vmult_scalar(endVector, B2(CURVE_T(curveP, i)));
+        temp3 = Vmult_scalar(endVector, B3(CURVE_T(curveP, i)));
 
         temp = make_vector(
-            Vsubtract_point(CURVE_POINT(curve, i),
+            Vsubtract_point(CURVE_POINT(curveP, i),
                             Vadd(temp0, Vadd(temp1, Vadd(temp2, temp3)))));
 
-        X[0] += Vdot(temp, Ai[0]);
-        X[1] += Vdot(temp, Ai[1]);
+        X.beg += Vdot(temp, AP->beg);
+        X.end += Vdot(temp, AP->end);
     }
     free(A);
 
-    C[1][0] = C[0][1];
+    C.end.beg = C.beg.end;
     
-    X_C1_det = X[0] * C[1][1] - X[1] * C[0][1];
-    C0_X_det = C[0][0] * X[1] - C[0][1] * X[0];
-    C0_C1_det = C[0][0] * C[1][1] - C[1][0] * C[0][1];
-    if (C0_C1_det == 0.0) {
-        LOG ("zero determinant of C0*C1");
-        at_exception_fatal(exception, "zero determinant of C0*C1");
-        goto cleanup;
-    }
-
-    alpha1 = X_C1_det / C0_C1_det;
-    alpha2 = C0_X_det / C0_C1_det;
-
-    CONTROL1(spline) = Vadd_point(START_POINT(spline),
-                                  Vmult_scalar(t1_hat, alpha1));
-    CONTROL2(spline) = Vadd_point(END_POINT(spline),
-                                  Vmult_scalar(t2_hat, alpha2));
-    SPLINE_DEGREE(spline) = CUBICTYPE;
-
-cleanup:
+    X_Cend_det  = X.beg * C.end.end - X.end * C.beg.end;
+    Cbeg_X_det  = C.beg.beg * X.end - C.beg.end * X.beg;
+    C_det = C.beg.beg * C.end.end - C.end.beg * C.beg.end;
+    if (C_det == 0.0) {
+        LOG("zero determinant of C matrix");
+        at_exception_fatal(exceptionP, "zero determinant of C matrix");
+    } else {
+        struct { float beg; float end; } alpha;  /* constant */
+        alpha.beg = X_Cend_det / C_det;
+        alpha.end = Cbeg_X_det / C_det;
+
+        CONTROL1(spline) = Vadd_point(BEG_POINT(spline),
+                                      Vmult_scalar(tang.beg, alpha.beg));
+        CONTROL2(spline) = Vadd_point(END_POINT(spline),
+                                      Vmult_scalar(tang.end, alpha.end));
+        SPLINE_DEGREE(spline) = CUBICTYPE;
+    }        
     return spline;
 }
 
@@ -951,214 +1350,538 @@ logSplineFit(spline_type const spline) {
 
 
 
-static spline_list_type *
-fit_with_least_squares(curve_type                const curve,
-                       const fitting_opts_type * const fitting_opts,
-                       at_exception_type *       const exception) {
+static vector_type
+findHalfTangentBeg(curve *      const curveP,
+                   unsigned int const tangentSurround) {
 /*----------------------------------------------------------------------------
-  The least squares method is well described in Schneider's thesis.
-  Briefly, we try to fit the entire curve with one spline.  If that
-  fails, we subdivide the curve. 
+  Find the slope in the vicinity of the beginning of the curve
+  *curveP.
+
+  To wit, this is the mean slope between the first point on the curve and
+  each of the 'tangentSurround' following points, up to half the curve.
+
+  For example, if 'tangentSurround' is 3 and the curve is 10 points
+  long, we imagine a line through Point 0 and Point 1, another through
+  Point 0 and Point 2, and a third through Point 0 and Point 3.  We
+  return the mean of the slopes of those 3 lines.
 -----------------------------------------------------------------------------*/
-    float error;
-    float best_error;
-    spline_type spline;
-    spline_type best_spline;
-    spline_list_type * spline_list;
-    unsigned int worst_point;
-    float previous_error;
-    
-    best_error = FLT_MAX;  /* initial value */
-    previous_error = FLT_MAX;  /* initial value */
-    spline_list = NULL;  /* initial value */
-    worst_point = 0;  /* initial value */
+    float_coord const tangentPoint = CURVE_POINT(curveP, 0);
+    vector_type const zeroZero = { 0.0, 0.0 };
+    unsigned int const surround =
+        MIN(CURVE_LENGTH(curveP) / 2, tangentSurround);
 
-    LOG ("\nFitting with least squares:\n");
-    
-    /* Phoenix reduces the number of points with a ``linear spline
-       technique''.  But for fitting letterforms, that is
-       inappropriate.  We want all the points we can get.
-    */
+    unsigned int p;
+    vector_type sum;
+    vector_type mean;
+    unsigned int n;
+
+    for (p = 0, n = 0, sum = zeroZero; p < surround; ++p) {
+        unsigned int const thisIndex = p + 1;
+        float_coord  const thisPoint = CURVE_POINT(curveP, thisIndex);
+
+        /* Perhaps we should weight the tangent from `thisPoint' by some
+           factor dependent on the distance from the tangent point.
+        */
+        sum = Vadd(sum, Pdirection(thisPoint, tangentPoint));
+        ++n;
+    }
+
+    mean = Vmult_scalar(sum, 1.0 / n);
+
+    return mean;
+}
+
+
+
+static vector_type
+findHalfTangentEnd(curve *      const curveP,
+                   unsigned int const tangentSurround) {
+/*----------------------------------------------------------------------------
+  Find the slope in the vicinity of the end of the curve
+  *curveP.
+
+  This is analogous to findHalfTangentBeg(), but at the other end of the
+  curve.
+-----------------------------------------------------------------------------*/
+    float_coord const tangentPoint =
+        CURVE_POINT(curveP, CURVE_LENGTH(curveP) - 1);
+    vector_type const zeroZero = { 0.0, 0.0 };
+    unsigned int const surround =
+        MIN(CURVE_LENGTH(curveP) / 2, tangentSurround);
+
+    unsigned int p;
+    vector_type sum;
+    vector_type mean;
+    unsigned int n;
+
+    for (p = 0, n = 0, sum = zeroZero; p < surround; ++p) {
+        unsigned int const thisIndex = CURVE_LENGTH(curveP) - 1 - p;
+        float_coord  const thisPoint = CURVE_POINT(curveP, thisIndex);
+
+        sum = Vadd(sum, Pdirection(tangentPoint, thisPoint));
+        ++n;
+    }
+
+    mean = Vmult_scalar(sum, 1.0 / n);
+
+    return mean;
+}
+
+
+
+static vector_type
+findHalfTangent(bool         const toStartPoint,
+                curve *      const curveP,
+                unsigned int const tangentSurround) {
+
+    if (toStartPoint)
+        return findHalfTangentBeg(curveP, tangentSurround);
+    else
+        return findHalfTangentEnd(curveP, tangentSurround);
+}
+
+
+
+static void
+findTangent(curve *       const curveP,
+            bool          const toStartPoint,
+            curve *       const adjacentCurveP,
+            unsigned int  const tangentSurroundArg,
+            vector_type * const tangentP) {
+/*----------------------------------------------------------------------------
+  Find an approximation to the slope of *curveP (i.e. slope of tangent
+  line) at an endpoint (the first point if 'toStartPoint' is true,
+  else the last).
+
+  If 'adjacentCurveP' is non-null, consider points on the adjacent
+  curve to *curveP.  The adjacent curve is *adjacentCurveP.  Adjacent
+  means the previous curve in the outline chain for the slope at the
+  start point ('toStartPoint' == true), the next curve otherwise.
+  If *curveP is cyclic, then it is its own adjacent 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 slopes and endpoints, and
+  we never recompute the tangent after this.
+-----------------------------------------------------------------------------*/
+    vector_type slope;
+    unsigned int tangentSurround;
+
+    LOG2("  tangent to %s of curve %lx: ",
+         toStartPoint ? "start" : "end", (unsigned long)curveP);
+
+    tangentSurround = tangentSurroundArg;  /* initial value */
+    do {
+        slope = findHalfTangent(toStartPoint, curveP, tangentSurround);
+
+        if (adjacentCurveP) {
+            vector_type const slopeAdj =
+                findHalfTangent(!toStartPoint, adjacentCurveP,
+                                tangentSurround);
+               
+            LOG3("(adjacent curve half tangent (%.3f,%.3f,%.3f)) ",
+                 slopeAdj.dx, slopeAdj.dy, slopeAdj.dz);
+            slope = Vmult_scalar(Vadd(slope, slopeAdj), 0.5);
+        }
+        --tangentSurround;
+    } while (slope.dx == 0.0 && slope.dy == 0.0);
+
+    *tangentP = slope;
     
-    /* It makes no difference whether we first set the `t' values or
-       find the tangents.  This order makes the documentation a little
-       more coherent.
-    */
+    LOG3("(%.3f,%.3f,%.3f).\n",
+         tangentP->dx, tangentP->dy, tangentP->dz);
+}
 
-    LOG("Finding tangents:\n");
-    find_tangent(curve, /* to_start */ true,  /* cross_curve */ false,
-                 fitting_opts->tangent_surround);
-    find_tangent(curve, /* to_start */ false, /* cross_curve */ false,
-                 fitting_opts->tangent_surround);
 
-    set_initial_parameter_values(curve);
 
-    /* Now we loop, subdividing, until CURVE has been fit.  */
-    while (true) {
-        float error;
+static void
+findError(curve *             const curveP,
+          spline_type         const spline,
+          float *             const errorP,
+          unsigned int *      const worstPointP,
+          at_exception_type * const exceptionP) {
+/*----------------------------------------------------------------------------
+  Tell how good a fit 'spline' is for *curveP.
+  
+  Return the error (maximum Euclidian distance between a point on
+  *curveP and the corresponding point on 'spline') as *errorP and the
+  sequence number of the point on the curve where the error is
+  greatest as *worstPointP.
+
+  If there are multiple equally bad points, return an arbitrary one of
+  them as *worstPointP.
+-----------------------------------------------------------------------------*/
+    unsigned int thisPoint;
+    float totalError;
+    float worstError;
+    unsigned int worstPoint;
 
-        spline = fit_one_spline(curve, exception);
-        best_spline = spline;
-        if (at_exception_got_fatal(exception))
-            goto cleanup;
+    assert(CURVE_LENGTH(curveP) > 0);
 
-        logSplineFit(spline);
+    totalError = 0.0;  /* initial value */
+    worstError = FLT_MIN; /* initial value */
+    worstPoint = 0;
         
-        if (SPLINE_DEGREE(spline) == LINEARTYPE)
-            break;
-
-        error = find_error(curve, spline, &worst_point, exception);
-        if (error <= previous_error) {
-            best_error  = error;
-            best_spline = spline;
+    for (thisPoint = 0; thisPoint < CURVE_LENGTH(curveP); ++thisPoint) {
+        float_coord const curvePoint = CURVE_POINT(curveP, thisPoint);
+        float const t = CURVE_T(curveP, thisPoint);
+        float_coord const splinePoint = evaluate_spline(spline, t);
+        float const thisError = distance(curvePoint, splinePoint);
+        if (thisError >= worstError) {
+            worstPoint = thisPoint;
+            worstError = thisError;
         }
-        break;
+        totalError += thisError;
     }
 
-    if (SPLINE_DEGREE(spline) == LINEARTYPE) {
-        spline_list = new_spline_list_with_spline(spline);
-        LOG1("Accepted error of %.3f.\n", error);
-        return spline_list;
+    if (epsilon_equal(totalError, 0.0))
+        LOG("  Every point fits perfectly.\n");
+    else {
+        LOG5("  Worst error (at (%.3f,%.3f,%.3f), point #%u) was %.3f.\n",
+             CURVE_POINT(curveP, worstPoint).x,
+             CURVE_POINT(curveP, worstPoint).y,
+             CURVE_POINT(curveP, worstPoint).z,
+             worstPoint, worstError);
+        LOG1("  Total error was %.3f.\n", totalError);
+        LOG2("  Average error (over %u points) was %.3f.\n",
+                 CURVE_LENGTH(curveP), totalError / CURVE_LENGTH(curveP));
     }
+    assert(worstPoint < CURVE_LENGTH(curveP));
+    *errorP      = worstError;
+    *worstPointP = worstPoint;
+}
+
+
+
+static void
+setInitialParameterValues(curve * const curveP) {
+/*----------------------------------------------------------------------------
+   Fill in the 't' values in *curveP.
 
-    /* Go back to the best fit.  */
-    spline = best_spline;
-    error = best_error;
+   The t value for point P on a curve is the distance P is along the
+   curve from the initial point, normalized so the entire curve is
+   length 1.0 (i.e. t of the initial point is 0.0; t of the final
+   point is 1.0).
 
-    if (error < fitting_opts->error_threshold && !CURVE_CYCLIC(curve)) {
-        /* The points were fitted with a spline.  We end up here
-           whenever a fit is accepted.  We have one more job: see if
-           the ``curve'' that was fit should really be a straight
-           line.
+   There are a lot of curves that pass through the points indicated by
+   *curveP, but for practical computation of t, we just take the
+   piecewise linear locus that runs through all of them.  That means
+   we can just step through *curveP, adding up the distance from one
+   point to the next to get the t value for each point.
+
+   This is the "chord-length parameterization" method, which is
+   described in Plass & Stone.
+-----------------------------------------------------------------------------*/
+    unsigned int p;
+
+    LOG("\nAssigning initial t values:\n  ");
+
+    CURVE_T(curveP, 0) = 0.0;
+
+    for (p = 1; p < CURVE_LENGTH(curveP); ++p) {
+        float_coord const point      = CURVE_POINT(curveP, p);
+        float_coord const previous_p = CURVE_POINT(curveP, p - 1);
+        float const d = distance(point, previous_p);
+        CURVE_T(curveP, p) = CURVE_T(curveP, p - 1) + d;
+    }
+
+    assert(LAST_CURVE_T(curveP) != 0.0);
+
+    /* Normalize to a curve length of 1.0 */
+
+    for (p = 1; p < CURVE_LENGTH(curveP); ++p)
+        CURVE_T(curveP, p) = CURVE_T(curveP, p) / LAST_CURVE_T(curveP);
+
+    log_entire_curve(curveP);
+}
+
+
+
+static void
+subdivideCurve(curve *                   const curveP,
+               unsigned int              const subdivisionIndex,
+               const fitting_opts_type * const fittingOptsP,
+               curve **                  const leftCurvePP,
+               curve **                  const rghtCurvePP,
+               vector_type *             const joinSlopeP) {
+/*----------------------------------------------------------------------------
+  Split curve *curveP into two, at 'subdivisionIndex'.  (Actually,
+  leave *curveP alone, but return as *leftCurvePP and *rghtCurvePP
+  two new curves that are the pieces).
+  
+  Return as *joinSlopeP what should be the slope where the subcurves
+  join, i.e. the slope of the end of the left subcurve and of the start
+  of the right subcurve.
+
+  To be precise, the point with sequence number 'subdivisionIndex'
+  becomes the first pixel of the right-hand curve.
+-----------------------------------------------------------------------------*/
+    curve * leftCurveP;
+    curve * rghtCurveP;
+
+    leftCurveP = new_curve();
+    rghtCurveP = new_curve();
+
+    LOG4("  Subdividing curve %lx into %lx and %lx at point #%u\n",
+         (unsigned long)curveP,
+         (unsigned long)leftCurveP, (unsigned long)rghtCurveP,
+         subdivisionIndex);
+
+    /* The last point of the left-hand curve will also be the first
+       point of the right-hand curve.
+    */
+    assert(subdivisionIndex < CURVE_LENGTH(curveP));
+    CURVE_LENGTH(leftCurveP) = subdivisionIndex + 1;
+    CURVE_LENGTH(rghtCurveP) = CURVE_LENGTH(curveP) - subdivisionIndex;
+
+    MALLOCARRAY_NOFAIL(leftCurveP->point_list, CURVE_LENGTH(leftCurveP));
+    memcpy(leftCurveP->point_list, &curveP->point_list[0],
+           CURVE_LENGTH(leftCurveP) * sizeof(curveP->point_list[0]));
+
+    MALLOCARRAY_NOFAIL(rghtCurveP->point_list, CURVE_LENGTH(rghtCurveP));
+    memcpy(rghtCurveP->point_list, &curveP->point_list[subdivisionIndex],
+           CURVE_LENGTH(rghtCurveP) * sizeof(curveP->point_list[0]));
+
+    /* We have to set up the two curves before finding the slope at
+       the subdivision point.  The slope at that point must be the
+       same for both curves, or noticeable bumps will occur in the
+       character.  But we want to use information on both sides of the
+       point to compute the slope, hence we use adjacentCurveP.
+    */
+    findTangent(leftCurveP,
+                /* toStartPoint: */   false,
+                /* adjacentCurveP: */ rghtCurveP,
+                fittingOptsP->tangent_surround, joinSlopeP);
+
+    *leftCurvePP = leftCurveP;
+    *rghtCurvePP = rghtCurveP;
+}
+
+
+
+static spline_list_type *
+leftRightConcat(const spline_list_type *  const leftSplineListP,
+                const spline_list_type *  const rghtSplineListP,
+                at_exception_type *       const exceptionP) {
+/*----------------------------------------------------------------------------
+   Return a spline list which is the concatenation of the spline lists
+   obtained by splitting a curve in two and fitting each independently.
+   NULL for a spline list pointer means Caller was unable to fit a list
+   of splines to that side of the curve.
+-----------------------------------------------------------------------------*/
+    spline_list_type * retval;
+                
+    retval = new_spline_list();
+
+    if (leftSplineListP == NULL) {
+        LOG("Could not fit spline to left curve.\n");
+        at_exception_warning(exceptionP, "Could not fit left spline list");
+    } else
+        concat_spline_lists(retval, *leftSplineListP);
+    
+    if (rghtSplineListP == NULL) {
+        LOG("Could not fit spline to right curve.\n");
+        at_exception_warning(exceptionP, "Could not fit right spline list");
+    } else
+        concat_spline_lists(retval, *rghtSplineListP);
+
+    return retval;
+}
+
+
+
+static unsigned int
+divisionPoint(curve *      const curveP,
+              unsigned int const worstFitPoint) {
+/*----------------------------------------------------------------------------
+   Return the sequence number of the point at which we should divide
+   curve *curveP for the purpose of doing a separate fit of each side,
+   assuming the point which least matches a single spline is sequence
+   number 'worstFitPoint'.
+
+   We get as close as we can to that while still having at least two
+   points on each side.
+
+   Assume the curve is at least 4 points long.
+
+   The return value is the sequence number of the first point of the
+   second (right-hand) subcurve.
+-----------------------------------------------------------------------------*/
+    assert(CURVE_LENGTH(curveP) >= 4);
+
+    return MAX(2, MIN(worstFitPoint, CURVE_LENGTH(curveP) - 2));
+}
+
+
+
+static spline_list_type *
+divideAndFit(curve *                   const curveP,
+             vector_type               const begSlope,
+             vector_type               const endSlope,
+             unsigned int              const subdivisionIndex,
+             const fitting_opts_type * const fittingOptsP,
+             at_exception_type *       const exceptionP) {
+/*----------------------------------------------------------------------------
+  Same as fitWithLeastSquares() (i.e. return a list of splines that fit
+  the curve *curveP), except assuming no single spline will fit the
+  entire curve.
+
+  Divide it into two curves at 'subdivisionIndex' and fit each
+  separately to a list of splines.  Return the concatenation of those
+  spline lists.
+
+  Assume 'subdivisionIndex' leaves at least two pixels on each side.
+-----------------------------------------------------------------------------*/
+    spline_list_type * retval;
+    curve * leftCurveP;
+        /* The beginning (lower indexes) subcurve */
+    curve * rghtCurveP;
+        /* The other subcurve */
+    vector_type joinSlope;
+        /* The slope of the end of the left subcurve and start of the right
+           subcurve.
         */
-        if (spline_linear_enough(&spline, curve, fitting_opts)) {
-            SPLINE_DEGREE(spline) = LINEARTYPE;
-            LOG("Changed to line.\n");
+    spline_list_type * leftSplineListP;
+    
+    assert(subdivisionIndex > 1);
+    assert(subdivisionIndex < CURVE_LENGTH(curveP)-1);
+    subdivideCurve(curveP, subdivisionIndex, fittingOptsP,
+                   &leftCurveP, &rghtCurveP, &joinSlope);
+
+    leftSplineListP = fitCurve(leftCurveP, begSlope, joinSlope,
+                               fittingOptsP, exceptionP);
+
+    if (!at_exception_got_fatal(exceptionP)) {
+        spline_list_type * rghtSplineListP;
+
+        rghtSplineListP = fitCurve(rghtCurveP, joinSlope, endSlope,
+                                   fittingOptsP, exceptionP);
+
+        if (!at_exception_got_fatal(exceptionP)) {
+            if (leftSplineListP == NULL && rghtSplineListP == NULL)
+                retval = NULL;
+            else
+                retval = leftRightConcat(leftSplineListP, rghtSplineListP,
+                                         exceptionP);
+
+            if (rghtSplineListP) {
+                free_spline_list(*rghtSplineListP);
+                free(rghtSplineListP);
+            }
         }
-        spline_list = new_spline_list_with_spline(spline);
-        LOG1("Accepted error of %.3f.\n", error);
-    } else {
-        /* We couldn't fit the curve acceptably, so subdivide.  */
-        unsigned subdivision_index;
-        spline_list_type * left_spline_list;
-        spline_list_type * right_spline_list;
-        curve_type left_curve, right_curve;
-
-        left_curve  = new_curve();
-        right_curve = new_curve();
-
-        /* Insert 'left_curve', then 'right_curve' after 'curve' in the list */
-        NEXT_CURVE(right_curve) = NEXT_CURVE(curve);
-        PREVIOUS_CURVE(right_curve) = left_curve;
-        NEXT_CURVE(left_curve) = right_curve;
-        PREVIOUS_CURVE(left_curve) = curve;
-        NEXT_CURVE(curve) = left_curve;
-
-        LOG1("\nSubdividing (error %.3f):\n", error);
-        LOG3("  Original point: (%.3f,%.3f), #%u.\n",
-             CURVE_POINT (curve, worst_point).x,
-             CURVE_POINT (curve, worst_point).y, worst_point);
-        subdivision_index = worst_point;
-        LOG3 ("  Final point: (%.3f,%.3f), #%u.\n",
-              CURVE_POINT (curve, subdivision_index).x,
-              CURVE_POINT (curve, subdivision_index).y, subdivision_index);
-
-        /* The last point of the left-hand curve will also be the first
-           point of the right-hand curve.  */
-        CURVE_LENGTH(left_curve)  = subdivision_index + 1;
-        CURVE_LENGTH(right_curve) = CURVE_LENGTH(curve) - subdivision_index;
-        left_curve->point_list = curve->point_list;
-        right_curve->point_list = curve->point_list + subdivision_index;
-
-        /* We want to use the tangents of the curve which we are
-           subdividing for the start tangent for left_curve and the
-           end tangent for right_curve.
-        */
-        CURVE_START_TANGENT(left_curve) = CURVE_START_TANGENT(curve);
-        CURVE_END_TANGENT(right_curve)  = CURVE_END_TANGENT(curve);
-
-        /* We have to set up the two curves before finding the tangent at
-           the subdivision point.  The tangent at that point must be the
-           same for both curves, or noticeable bumps will occur in the
-           character.  But we want to use information on both sides of the
-           point to compute the tangent, hence cross_curve = true.
-        */
-        find_tangent(left_curve, /* to_start_point: */ false,
-                     /* cross_curve: */ true, fitting_opts->tangent_surround);
-        CURVE_START_TANGENT(right_curve) = CURVE_END_TANGENT(left_curve);
-
-        /* Now that we've set up the curves, we can fit them.  */
-        left_spline_list = fitCurve(left_curve, fitting_opts, exception);
-        if (at_exception_got_fatal(exception))
-            /* TODO: Memory allocated for left_curve and right_curve
-               will leak.*/
-            goto cleanup;
+        if (leftSplineListP) {
+            free_spline_list(*leftSplineListP);
+            free(leftSplineListP);
+        }
+    }
 
-        right_spline_list = fitCurve(right_curve, fitting_opts, exception);
-        /* TODO: Memory allocated for left_curve and right_curve
-           will leak.*/
-        if (at_exception_got_fatal(exception))
-            goto cleanup;
-        
-        /* Neither of the subdivided curves could be fit, so fail.  */
-        if (left_spline_list == NULL && right_spline_list == NULL)
-            return NULL;
+    free_curve(leftCurveP);
+    free_curve(rghtCurveP);
 
-        /* Put the two together (or whichever of them exist).  */
-        spline_list = new_spline_list();
+    return retval;
+}
 
-        if (left_spline_list == NULL) {
-            LOG1("Could not fit spline to left curve (%lx).\n",
-                 (unsigned long) left_curve);
-            at_exception_warning(exception, "Could not fit left spline list");
-        } else {
-            concat_spline_lists(spline_list, *left_spline_list);
-            free_spline_list(*left_spline_list);
-            free(left_spline_list);
+
+
+static spline_list_type *
+fitWithLeastSquares(curve *                   const curveP,
+                    vector_type               const begSlope,
+                    vector_type               const endSlope,
+                    const fitting_opts_type * const fittingOptsP,
+                    at_exception_type *       const exceptionP) {
+/*----------------------------------------------------------------------------
+  The least squares method is well described in Schneider's thesis.
+  Briefly, we try to fit the entire curve with one spline.  If that
+  fails, we subdivide the curve. 
+-----------------------------------------------------------------------------*/
+    spline_list_type * retval;
+    spline_type spline;
+    
+    LOG("\nFitting with least squares:\n");
+    
+    /* Phoenix reduces the number of points with a "linear spline
+       technique."  But for fitting letterforms, that is
+       inappropriate.  We want all the points we can get.
+    */
+    
+    setInitialParameterValues(curveP);
+
+    if (CURVE_CYCLIC(curveP) && CURVE_LENGTH(curveP) < 4) {
+        unsigned i;
+        for (i = 0; i < CURVE_LENGTH(curveP); ++i) {
+            float_coord const point = CURVE_POINT(curveP, i);
+            fprintf(stderr, "point %u = (%f, %f)\n", i, point.x, point.y);
         }
+    }
+
+    /* Try a single spline over whole curve */
+
+    spline = fitOneSpline(curveP, begSlope, endSlope, exceptionP);
+    if (!at_exception_got_fatal(exceptionP)) {
+        float error;
+        unsigned int worstPoint;
+
+        logSplineFit(spline);
         
-        if (right_spline_list == NULL) {
-            LOG1("Could not fit spline to right curve (%lx).\n",
-                 (unsigned long) right_curve);
-            at_exception_warning(exception, "Could not fit right spline list");
+        findError(curveP, spline, &error, &worstPoint, exceptionP);
+        assert(worstPoint < CURVE_LENGTH(curveP));
+
+        if (error < fittingOptsP->error_threshold && !CURVE_CYCLIC(curveP)) {
+            /* The points were fitted adequately with a spline.  But
+               see if the "curve" that was fit should really just be a
+               straight line.
+            */
+            if (spline_linear_enough(&spline, curveP, fittingOptsP)) {
+                SPLINE_DEGREE(spline) = LINEARTYPE;
+                LOG("Changed to line.\n");
+            }
+            retval = new_spline_list_with_spline(spline);
+            LOG1("Accepted error of %.3f.\n", error);
         } else {
-            concat_spline_lists(spline_list, *right_spline_list);
-            free_spline_list(*right_spline_list);
-            free(right_spline_list);
+            /* We couldn't fit the curve acceptably with a single spline,
+               so divide into two curves and try to fit each separately.
+            */
+            unsigned int const divIndex = divisionPoint(curveP, worstPoint);
+            LOG1("\nSubdividing at point #%u\n", divIndex);
+            LOG4("  Worst match point: (%.3f,%.3f), #%u.  Error %.3f\n",
+                 CURVE_POINT(curveP, worstPoint).x,
+                 CURVE_POINT(curveP, worstPoint).y, worstPoint, error);
+
+            retval = divideAndFit(curveP, begSlope, endSlope, divIndex,
+                                  fittingOptsP, exceptionP);
         }
-        if (CURVE_END_TANGENT(left_curve))
-            free(CURVE_END_TANGENT(left_curve));
-        free(left_curve);
-        free(right_curve);
-    }
-cleanup:
+    } else
+        retval = NULL; /* quiet compiler warning */
 
-    return spline_list;
+    return retval;
 }
 
 
 
 static spline_list_type *
-fitCurve(curve_type                const curve,
+fitCurve(curve *                   const curveP,
+         vector_type               const begSlope,
+         vector_type               const endSlope,
          const fitting_opts_type * const fittingOptsP,
-         at_exception_type *       const exception) {
+         at_exception_type *       const exceptionP) {
 /*----------------------------------------------------------------------------
   Transform a set of locations to a list of splines (the fewer the
-  better).  We are guaranteed that CURVE does not contain any corners.
+  better).  We are guaranteed that *curveP does not contain any corners.
   We return NULL if we cannot fit the points at all.
 -----------------------------------------------------------------------------*/
     spline_list_type * fittedSplinesP;
 
-    if (CURVE_LENGTH(curve) < 2) {
-        LOG("Tried to fit curve with less than two points");
-        at_exception_warning(exception, 
+    if (CURVE_LENGTH(curveP) < 2) {
+        LOG("Tried to fit curve with fewer than two points");
+        at_exception_warning(exceptionP, 
                              "Tried to fit curve with less than two points");
         fittedSplinesP = NULL;
-    } else if (CURVE_LENGTH(curve) < 4)
-        fittedSplinesP = fit_with_line(curve);
+    } else if (CURVE_LENGTH(curveP) < 4)
+        fittedSplinesP = fitWithLine(curveP);
     else
         fittedSplinesP =
-            fit_with_least_squares(curve, fittingOptsP, exception);
+            fitWithLeastSquares(curveP, begSlope, endSlope, fittingOptsP,
+                                exceptionP);
 
     return fittedSplinesP;
 }
@@ -1185,13 +1908,24 @@ fitCurves(curve_list_type           const curveList,
          curveSeq < curveList.length && !at_exception_got_fatal(exceptionP);
          ++curveSeq) {
 
-        curve_type const currentCurve = CURVE_LIST_ELT(curveList, curveSeq);
+        curve * const curveP = CURVE_LIST_ELT(curveList, curveSeq);
 
+        vector_type begSlope, endSlope;
         spline_list_type * curveSplinesP;
 
-        LOG1("\nFitting curve #%u:\n", curveSeq);
+        LOG2("\nFitting curve #%u (%lx):\n", curveSeq, (unsigned long)curveP);
 
-        curveSplinesP = fitCurve(currentCurve, fittingOptsP, exceptionP);
+        LOG("Finding tangents:\n");
+        findTangent(curveP, /* toStart */ true,
+                    CURVE_CYCLIC(curveP) ? curveP : NULL,
+                    fittingOptsP->tangent_surround,
+                    &begSlope);
+        findTangent(curveP, /* toStart */ false,
+                    CURVE_CYCLIC(curveP) ? curveP : NULL,
+                    fittingOptsP->tangent_surround, &endSlope);
+
+        curveSplinesP = fitCurve(curveP, begSlope, endSlope, fittingOptsP,
+                                 exceptionP);
         if (!at_exception_got_fatal(exceptionP)) {
             if (curveSplinesP == NULL) {
                 LOG1("Could not fit curve #%u", curveSeq);
@@ -1369,7 +2103,6 @@ fit_outlines_to_splines(pixel_outline_list_type  const pixelOutlineList,
                        exception, notifyProgress, progressData,
                        testCancel, testcancelData, splineListArrayP);
 
-
     free_curve_list_array(&curveListArray, notifyProgress, progressData);
     
     flush_log_output();
@@ -1377,548 +2110,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.  */
-      *worst_point = 0;
-      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/pamtosvg/pamtosvg.c b/converter/other/pamtosvg/pamtosvg.c
index 7262204c..dbe67c74 100644
--- a/converter/other/pamtosvg/pamtosvg.c
+++ b/converter/other/pamtosvg/pamtosvg.c
@@ -4,6 +4,7 @@
 #include <assert.h>
 #include <math.h>
 
+#include "pm_c_util.h"
 #include "mallocvar.h"
 #include "nstring.h"
 #include "shhopt.h"
@@ -211,6 +212,7 @@ parseCommandLine(int argc,
             pm_error("Too many arguments (%u).  The only non-option argument "
                      "is the input file name.", argc-1);
     }
+    free(option_def);
 }
 
 
@@ -389,7 +391,7 @@ main(int argc, char * argv[]) {
     pm_close(ifP);
     if (cmdline.log)
         pm_close(log_file);
-    
+
     at_splines_free(splinesP);
     at_bitmap_free(bitmapP);
 
diff --git a/converter/other/pamtosvg/pamtosvg.test b/converter/other/pamtosvg/pamtosvg.test
index df3a07d3..3217287e 100644
--- a/converter/other/pamtosvg/pamtosvg.test
+++ b/converter/other/pamtosvg/pamtosvg.test
@@ -1,6 +1,8 @@
+echo "Test 1.  Should print nothing"
 # This will print nothing if successful (diff will find no difference)
-ppmmake black 20 20 | ppmdraw -script="line 5 2 15 17" | pamtosvg | \
+ppmmake black 20 20 | ppmdraw -script="line 5 2 15 17" | ./pamtosvg | \
   diff testline.svg -
 
+echo "Test 2.  Should print nothing"
 # This will print nothing if successful (diff will find no difference)
-pamtosvg ../../../../testgrid.pbm | diff testgrid.svg -
+./pamtosvg ../../../testgrid.pbm | diff testgrid.svg -
diff --git a/converter/other/pamtosvg/pxl-outline.c b/converter/other/pamtosvg/pxl-outline.c
index a55a8b95..a1fa5299 100644
--- a/converter/other/pamtosvg/pxl-outline.c
+++ b/converter/other/pamtosvg/pxl-outline.c
@@ -83,8 +83,9 @@ getBitmapColor(bitmap_type  const bitmap,
                unsigned int const row,
                unsigned int const col) {
 
+    unsigned char * const p = BITMAP_PIXEL(bitmap, row, col);
+
     pixel pix;
-    unsigned char *p = BITMAP_PIXEL (bitmap, row, col);
   
     if (bitmap.np >= 3)
         PPM_ASSIGN(pix, p[0], p[1], p[2]);
@@ -248,19 +249,19 @@ next_unmarked_pixel(unsigned int *   const row,
 
 
 static pixel_outline_type
-find_one_centerline(bitmap_type    const bitmap,
-                    direction_type const original_dir,
-                    unsigned int   const original_row,
-                    unsigned int   const original_col,
-                    bitmap_type *  const marked) {
+findOneCenterline(bitmap_type    const bitmap,
+                  direction_type const originalDir,
+                  unsigned int   const originalRow,
+                  unsigned int   const originalCol,
+                  bitmap_type *  const marked) {
 
-    direction_type search_dir;
+    direction_type searchDir;
     unsigned int row, col;
     pixel_outline_type outline;
 
     outline = new_pixel_outline();
     outline.open  = false;
-    outline.color = getBitmapColor(bitmap, original_row, original_col);
+    outline.color = getBitmapColor(bitmap, originalRow, originalCol);
 
     /* Add the starting pixel to the output list, changing from bitmap
        to Cartesian coordinates and specifying the left edge so that
@@ -268,22 +269,22 @@ find_one_centerline(bitmap_type    const bitmap,
     */
     {
         pm_pixelcoord pos;
-        pos.col = original_col; pos.row = bitmap.height - original_row - 1;
+        pos.col = originalCol; pos.row = bitmap.height - originalRow - 1;
         LOG2(" (%d,%d)", pos.col, pos.row);
         append_outline_pixel(&outline, pos);
     }
-    search_dir = original_dir;  /* initial value */
-    row = original_row;         /* initial value */
-    col = original_col;         /* initial values */
+    searchDir = originalDir;  /* initial value */
+    row = originalRow;         /* initial value */
+    col = originalCol;         /* initial values */
 
     for ( ; ; ) {
-        unsigned int const prev_row = row;
-        unsigned int const prev_col = col;
+        unsigned int const prevRow = row;
+        unsigned int const prevCol = col;
 
         /* If there is no adjacent, unmarked pixel, we can't proceed
            any further, so return an open outline.
         */
-        if (!next_unmarked_pixel(&row, &col, &search_dir, bitmap, marked)) {
+        if (!next_unmarked_pixel(&row, &col, &searchDir, bitmap, marked)) {
             outline.open = true;
             break;
         }
@@ -291,12 +292,12 @@ find_one_centerline(bitmap_type    const bitmap,
         /* If we've moved to a new pixel, mark all edges of the previous
            pixel so that it won't be revisited.
         */
-        if (!(prev_row == original_row && prev_col == original_col))
-            mark_dir(prev_row, prev_col, search_dir, marked);
-        mark_dir(row, col, (search_dir + 4) % 8, marked);
+        if (!(prevRow == originalRow && prevCol == originalCol))
+            mark_dir(prevRow, prevCol, searchDir, marked);
+        mark_dir(row, col, (searchDir + 4) % 8, marked);
 
         /* If we've returned to the starting pixel, we're done. */
-        if (row == original_row && col == original_col)
+        if (row == originalRow && col == originalCol)
             break;
 
         
@@ -308,7 +309,7 @@ find_one_centerline(bitmap_type    const bitmap,
             append_outline_pixel(&outline, pos);
         }
     }
-    mark_dir(original_row, original_col, original_dir, marked);
+    mark_dir(originalRow, originalCol, originalDir, marked);
 
     return outline;
 }
@@ -392,7 +393,7 @@ find_centerline_pixels(bitmap_type         const bitmap,
           LOG2("#%u: (%sclockwise) ", O_LIST_LENGTH(outline_list),
                clockwise ? "" : "counter");
 
-          outline = find_one_centerline(bitmap, dir, row, col, &marked);
+          outline = findOneCenterline(bitmap, dir, row, col, &marked);
 
           /* If the outline is open (i.e., we didn't return to the
              starting pixel), search from the starting pixel in the
@@ -450,7 +451,7 @@ find_centerline_pixels(bitmap_type         const bitmap,
               }
               if (okay) {
                   partial_outline =
-                      find_one_centerline(bitmap, dir, row, col, &marked);
+                      findOneCenterline(bitmap, dir, row, col, &marked);
                   concat_pixel_outline(&outline, &partial_outline);
                   if (partial_outline.data)
                       free(partial_outline.data);
diff --git a/converter/other/pamtosvg/spline.c b/converter/other/pamtosvg/spline.c
index 5bdf0c0e..61167ec4 100644
--- a/converter/other/pamtosvg/spline.c
+++ b/converter/other/pamtosvg/spline.c
@@ -105,11 +105,13 @@ new_spline_list_with_spline (spline_type spline)
    elements, since they are arrays in automatic storage.  And we don't
    want to free the list if it was empty.  */
 
+
+
 void
-free_spline_list (spline_list_type spline_list)
-{
-  if (SPLINE_LIST_DATA (spline_list) != NULL)
-    free (SPLINE_LIST_DATA (spline_list));
+free_spline_list(spline_list_type spline_list) {
+
+    if (SPLINE_LIST_DATA(spline_list) != NULL)
+        free(SPLINE_LIST_DATA(spline_list));
 }
 
 
diff --git a/converter/other/pamtosvg/spline.h b/converter/other/pamtosvg/spline.h
index 05a56e23..96ceab4e 100644
--- a/converter/other/pamtosvg/spline.h
+++ b/converter/other/pamtosvg/spline.h
@@ -21,6 +21,7 @@ typedef at_spline_type spline_type;
 #define START_POINT(spl)        ((spl).v[0])
 #define CONTROL1(spl)           ((spl).v[1])
 #define CONTROL2(spl)           ((spl).v[2])
+#define BEG_POINT(spl)          ((spl).v[0])
 #define END_POINT(spl)          ((spl).v[3])
 #define SPLINE_DEGREE(spl)      ((spl).degree)
 #define SPLINE_LINEARITY(spl)   ((spl).linearity)
diff --git a/converter/other/pamtosvg/vector.c b/converter/other/pamtosvg/vector.c
index 18d6de59..7678f73a 100644
--- a/converter/other/pamtosvg/vector.c
+++ b/converter/other/pamtosvg/vector.c
@@ -17,137 +17,150 @@ static float acos_d (float, at_exception_type * excep);
 /* Given the point COORD, return the corresponding vector.  */
 
 vector_type
-make_vector (const float_coord c)
-{
-  vector_type v;
+make_vector(float_coord const c) {
 
-  v.dx = c.x;
-  v.dy = c.y;
-  v.dz = c.z;
+    vector_type v;
+
+    v.dx = c.x;
+    v.dy = c.y;
+    v.dz = c.z;
 
-  return v;
+    return v;
 }
 
 
+
 /* And the converse: given a vector, return the corresponding point.  */
 
 float_coord
-vector_to_point (const vector_type v)
-{
-  float_coord coord;
+vector_to_point(vector_type const v) {
+
+    float_coord coord;
 
-  coord.x = v.dx;
-  coord.y = v.dy;
-  coord.z = v.dz;
+    coord.x = v.dx;
+    coord.y = v.dy;
+    coord.z = v.dz;
 
-  return coord;
+    return coord;
 }
 
 
-float
-magnitude (const vector_type v)
-{
-  return (float) sqrt (v.dx * v.dx + v.dy * v.dy + v.dz * v.dz);
-}
 
+float
+magnitude(vector_type const v) {
 
-vector_type
-normalize (const vector_type v)
-{
-  vector_type new_v;
-  float m = magnitude (v);
+    return sqrt(SQR(v.dx) + SQR(v.dy) + SQR(v.dz));
+}
 
-  /* assert (m > 0.0); */
 
-  if (m > 0.0)
-  {
-    new_v.dx = v.dx / m;
-    new_v.dy = v.dy / m;
-    new_v.dz = v.dz / m;
-  }
-  else
-  {
-	new_v.dx = v.dx;
-    new_v.dy = v.dy;
-    new_v.dz = v.dz;
-  }
 
-  return new_v;
+vector_type
+normalize(vector_type const v) {
+
+    vector_type new_v;
+    float const m = magnitude(v);
+
+    if (m > 0.0) {
+        new_v.dx = v.dx / m;
+        new_v.dy = v.dy / m;
+        new_v.dz = v.dz / m;
+    } else {
+        new_v.dx = v.dx;
+        new_v.dy = v.dy;
+        new_v.dz = v.dz;
+    }
+    
+    return new_v;
 }
 
 
+
 vector_type
-Vadd (const vector_type v1, const vector_type v2)
-{
-  vector_type new_v;
+Vadd(vector_type const v1,
+     vector_type const v2) {
+
+    vector_type new_v;
 
-  new_v.dx = v1.dx + v2.dx;
-  new_v.dy = v1.dy + v2.dy;
-  new_v.dz = v1.dz + v2.dz;
+    new_v.dx = v1.dx + v2.dx;
+    new_v.dy = v1.dy + v2.dy;
+    new_v.dz = v1.dz + v2.dz;
 
-  return new_v;
+    return new_v;
 }
 
 
+
 float
-Vdot (const vector_type v1, const vector_type v2)
-{
-  return v1.dx * v2.dx + v1.dy * v2.dy + v1.dz * v2.dz;
+Vdot(vector_type const v1,
+     vector_type const v2) {
+
+    return v1.dx * v2.dx + v1.dy * v2.dy + v1.dz * v2.dz;
 }
 
 
+
 vector_type
-Vmult_scalar (const vector_type v, const float r)
-{
-  vector_type new_v;
+Vmult_scalar(vector_type const v,
+             float       const r) {
 
-  new_v.dx = v.dx * r;
-  new_v.dy = v.dy * r;
-  new_v.dz = v.dz * r;
+    vector_type new_v;
 
-  return new_v;
+    new_v.dx = v.dx * r;
+    new_v.dy = v.dy * r;
+    new_v.dz = v.dz * r;
+
+    return new_v;
 }
 
 
+
 /* Given the IN_VECTOR and OUT_VECTOR, return the angle between them in
-   degrees, in the range zero to 180.  */
+   degrees, in the range zero to 180.
+*/
 
 float
-Vangle (const vector_type in_vector, 
-	const vector_type out_vector,
-	at_exception_type * exp)
-{
-  vector_type v1 = normalize (in_vector);
-  vector_type v2 = normalize (out_vector);
+Vangle(vector_type         const in_vector, 
+       vector_type         const out_vector,
+       at_exception_type * const exP) {
+
+    vector_type const v1 = normalize(in_vector);
+    vector_type const v2 = normalize(out_vector);
 
-  return acos_d (Vdot (v2, v1), exp);
+    return acos_d(Vdot(v2, v1), exP);
 }
 
 
+
 float_coord
-Vadd_point (const float_coord c, const vector_type v)
-{
-  float_coord new_c;
+Vadd_point(float_coord const c,
+           vector_type const v) {
+
+    float_coord new_c;
 
-  new_c.x = c.x + v.dx;
-  new_c.y = c.y + v.dy;
-  new_c.z = c.z + v.dz;
-  return new_c;
+    new_c.x = c.x + v.dx;
+    new_c.y = c.y + v.dy;
+    new_c.z = c.z + v.dz;
+
+    return new_c;
 }
 
 
+
 float_coord
-Vsubtract_point (const float_coord c, const vector_type v)
-{
-  float_coord new_c;
+Vsubtract_point(float_coord const c,
+                vector_type const v) {
+
+    float_coord new_c;
 
-  new_c.x = c.x - v.dx;
-  new_c.y = c.y - v.dy;
-  new_c.z = c.z - v.dz;
-  return new_c;
+    new_c.x = c.x - v.dx;
+    new_c.y = c.y - v.dy;
+    new_c.z = c.z - v.dz;
+
+    return new_c;
 }
 
 
+
 pm_pixelcoord
 Vadd_int_point(pm_pixelcoord const c,
                vector_type   const v) {
@@ -161,56 +174,73 @@ Vadd_int_point(pm_pixelcoord const c,
 }
 
 
+
 vector_type
-Vabs (const vector_type v)
-{
-  vector_type new_v;
+Vabs(vector_type const v) {
 
-  new_v.dx = (float) fabs (v.dx);
-  new_v.dy = (float) fabs (v.dy);
-  new_v.dz = (float) fabs (v.dz);
-  return new_v;
+    vector_type new_v;
+
+    new_v.dx = (float) fabs (v.dx);
+    new_v.dy = (float) fabs (v.dy);
+    new_v.dz = (float) fabs (v.dz);
+
+    return new_v;
 }
 
 
+
 /* Operations on points.  */
 
 float_coord
-Padd (const float_coord coord1, const float_coord coord2)
-{
-  float_coord sum;
+Padd(float_coord const coord1,
+     float_coord const coord2) {
 
-  sum.x = coord1.x + coord2.x;
-  sum.y = coord1.y + coord2.y;
-  sum.z = coord1.z + coord2.z;
+    float_coord sum;
 
-  return sum;
+    sum.x = coord1.x + coord2.x;
+    sum.y = coord1.y + coord2.y;
+    sum.z = coord1.z + coord2.z;
+
+    return sum;
 }
 
 
+
 float_coord
-Pmult_scalar (const float_coord coord, const float r)
-{
-  float_coord answer;
+Pmult_scalar(float_coord const coord,
+             float       const r) {
+
+    float_coord answer;
 
-  answer.x = coord.x * r;
-  answer.y = coord.y * r;
-  answer.z = coord.z * r;
+    answer.x = coord.x * r;
+    answer.y = coord.y * r;
+    answer.z = coord.z * r;
 
-  return answer;
+    return answer;
 }
 
 
+
 vector_type
-Psubtract (const float_coord c1, const float_coord c2)
-{
-  vector_type v;
+Psubtract(float_coord const c1,
+          float_coord const c2) {
+
+    vector_type v;
 
-  v.dx = c1.x - c2.x;
-  v.dy = c1.y - c2.y;
-  v.dz = c1.z - c2.z;
+    v.dx = c1.x - c2.x;
+    v.dy = c1.y - c2.y;
+    v.dz = c1.z - c2.z;
 
-  return v;
+    return v;
+}
+
+
+
+vector_type
+Pdirection(float_coord const final,
+           float_coord const initial) {
+
+    return normalize(Psubtract(final, initial));
 }
 
 
@@ -233,23 +263,27 @@ IPsubtract(pm_pixelcoord const coord1,
 
 
 static float
-acos_d (float v, at_exception_type * excep)
-{
-  float a;
-
-  if (epsilon_equal (v, 1.0))
-    v = 1.0;
-  else if (epsilon_equal (v, -1.0))
-    v = -1.0;
-
-  errno = 0;
-  a = (float) acos (v);
-  if (errno == ERANGE || errno == EDOM)
-    {
-      at_exception_fatal(excep, strerror(errno));
-      return 0.0;
-    }
-  
-  
-  return a * (float) 180.0 / (float) M_PI;
+acos_d(float               const v,
+       at_exception_type * const excepP) {
+
+    float vAdj;
+    float a;
+    float retval;
+
+    if (epsilon_equal(v, 1.0))
+        vAdj = 1.0;
+    else if (epsilon_equal(v, -1.0))
+        vAdj = -1.0;
+    else
+        vAdj = v;
+
+    errno = 0;
+    a = acos(vAdj);
+    if (errno == ERANGE || errno == EDOM) {
+        at_exception_fatal(excepP, strerror(errno));
+        retval = 0.0;
+    } else
+        retval = a * 180.0 / M_PI;
+
+    return retval;
 }
diff --git a/converter/other/pamtosvg/vector.h b/converter/other/pamtosvg/vector.h
index 74fb2fd2..b5c85c38 100644
--- a/converter/other/pamtosvg/vector.h
+++ b/converter/other/pamtosvg/vector.h
@@ -15,32 +15,58 @@ typedef struct
 
 
 /* Consider a point as a vector from the origin.  */
-extern vector_type make_vector (const float_coord);
+vector_type
+make_vector(float_coord const);
 
 /* And a vector as a point, i.e., a displacement from the origin.  */
-extern float_coord vector_to_point (const vector_type);
+float_coord
+vector_to_point(vector_type const);
 
 
 /* Definitions for these common operations can be found in any decent
    linear algebra book, and most calculus books.  */
 
-extern float magnitude (const vector_type);
-extern vector_type normalize (const vector_type);
+float
+magnitude(vector_type const);
+
+vector_type
+normalize(vector_type const);
+
+vector_type
+Vadd(vector_type const,
+     vector_type const);
 
-extern vector_type Vadd (const vector_type, const vector_type);
-extern float Vdot (const vector_type, const vector_type);
-extern vector_type Vmult_scalar (const vector_type, const float);
-extern float Vangle (const vector_type in, const vector_type out, at_exception_type * exp);
+float
+Vdot(vector_type const,
+     vector_type const);
+
+vector_type
+Vmult_scalar(vector_type const,
+             float       const);
+
+float
+Vangle(vector_type         const in,
+       vector_type         const out,
+       at_exception_type * const exP);
 
 /* These operations could have been named `P..._vector' just as well as
    V..._point, so we may as well allow both names.  */
+
 #define Padd_vector Vadd_point
-extern float_coord Vadd_point
-  (const float_coord, const vector_type);
+
+float_coord
+Vadd_point(float_coord const,
+           vector_type const);
 
 #define Psubtract_vector Vsubtract_point
-extern float_coord Vsubtract_point
-  (const float_coord, const vector_type);
+
+float_coord
+Vsubtract_point(float_coord const,
+                vector_type const);
+
+vector_type
+Pdirection(float_coord const final,
+           float_coord const initial);
 
 /* This returns the rounded sum.  */
 #define IPadd_vector Vadd_int_point
@@ -50,22 +76,28 @@ Vadd_int_point(pm_pixelcoord const c,
                vector_type   const v);
 
 /* Take the absolute value of both components.  */
-extern vector_type Vabs (const vector_type);
+vector_type
+Vabs(vector_type const);
 
 /* Operations on points with real coordinates.  It is not orthogonal,
    but more convenient, to have the subtraction operator return a
    vector, and the addition operator return a point.  */
-extern vector_type Psubtract
-  (const float_coord, const float_coord);
+vector_type
+Psubtract(float_coord const,
+          float_coord const);
 
 vector_type
 IPsubtract(pm_pixelcoord const coord1,
            pm_pixelcoord const coord2);
 
 /* These are heavily used in spline fitting.  */
-extern float_coord Padd (const float_coord,
-                                  const float_coord);
-extern float_coord Pmult_scalar (const float_coord, const float);
 
-#endif
+float_coord
+Padd(float_coord const,
+     float_coord const);
 
+float_coord
+Pmult_scalar(float_coord const,
+             float       const);
+
+#endif
diff --git a/converter/other/pamtotga.c b/converter/other/pamtotga.c
index 6c8769ed..c23b92b1 100644
--- a/converter/other/pamtotga.c
+++ b/converter/other/pamtotga.c
@@ -15,6 +15,7 @@
 
 #include <string.h>
 
+#include "pm_c_util.h"
 #include "pam.h"
 #include "pammap.h"
 #include "shhopt.h"
@@ -270,7 +271,7 @@ computeRunlengths(struct pam * const pamP,
 
 static void
 computeOutName(struct cmdlineInfo const cmdline, 
-               const char ** const outNameP) {
+               const char **      const outNameP) {
     
     char * workarea;
 
diff --git a/converter/other/pamtotiff.c b/converter/other/pamtotiff.c
index 62315f9b..1b31c65b 100644
--- a/converter/other/pamtotiff.c
+++ b/converter/other/pamtotiff.c
@@ -788,16 +788,6 @@ createTiffGenerator(int          const ofd,
 
     const char * option;
 
-    /* Before 10.12 (November 2002), we set O_NONBLOCK here:
-
-       fcntl( 1, F_SETFL, O_NONBLOCK ) ; 
-   
-       I have no idea why.  The comment attached said, 
-
-         acooke dec99 - otherwise blocks on read inside 
-         next line (Linux i386) 
-    */
-
     validateSeekableOutputFile(ofd, outFileName);
 
     if (append)
@@ -1031,6 +1021,8 @@ validateReadableStdout(void) {
   error message about a file I/O error.  We, on the other hand, produce
   a helpful error message.
 -----------------------------------------------------------------------------*/
+#if !defined(WIN32) || defined(__CYGWIN__)
+
     int flags;
 
     flags = fcntl(STDOUT_FILENO, F_GETFL);
@@ -1045,6 +1037,7 @@ validateReadableStdout(void) {
                      "In order to create a multi-image TIFF stream, "
                      "Standard Output must be both readable and writable.");
     }
+#endif
 }
 
 
diff --git a/converter/other/pamtouil.c b/converter/other/pamtouil.c
index b9972abd..1a53be0f 100644
--- a/converter/other/pamtouil.c
+++ b/converter/other/pamtouil.c
@@ -17,6 +17,8 @@
 #define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
 #include <ctype.h>
 #include <string.h>
+
+#include "pm_c_util.h"
 #include "pam.h"
 #include "pammap.h"
 #include "colorname.h"
@@ -34,18 +36,18 @@ struct cmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    const char *inputFilespec;  /* Filespecs of input files */
-    char *outname;         /* output filename, less "_icon" */
+    const char * inputFilespec;  /* Filespecs of input files */
+    char * outname;         /* output filename, less "_icon" */
     unsigned int verbose;
 };
 
 
 
 typedef struct {    /* character-pixel mapping */
-    const char* cixel;    /* character string printed for pixel */
-    const char* rgbname;  /* ascii rgb color, either mnemonic or #rgb value */
-    const char* uilname;  /* same, with spaces replaced by underbars */
-    bool        transparent;
+    const char * cixel;    /* character string printed for pixel */
+    const char * rgbname;  /* ascii rgb color, either mnemonic or #rgb value */
+    const char * uilname;  /* same, with spaces replaced by underbars */
+    bool         transparent;
 } cixel_map;
 
 
@@ -95,10 +97,10 @@ parseCommandLine(int argc, char ** argv,
 
         /* Remove trailing "_icon" */
         barPos = strrchr(cmdlineP->outname, '_');
-        if (barPos && STREQ(barPos, "_icon")) 
+        if (barPos && streq(barPos, "_icon")) 
             *barPos = '\0';
     } else {
-        if (STREQ(cmdlineP->inputFilespec, "-"))
+        if (streq(cmdlineP->inputFilespec, "-"))
             cmdlineP->outname = strdup("noname");
         else {
             char * dotPos;
@@ -154,7 +156,8 @@ genNumstr(int  const number,
 
 
 static const char * 
-uilName(const char * const rgbname, bool const transparent) {
+uilName(const char * const rgbname,
+        bool         const transparent) {
 /*----------------------------------------------------------------------------
    Return a string in newly malloc'ed storage which is an appropriate 
    color name for the UIL palette.  It is the same as the rgb name,
@@ -200,8 +203,8 @@ genCmap(struct pam *   const pamP,
     unsigned int colorIndex;
     {
         /* Figure out how many characters per pixel we'll be using.
-        ** Don't want to be forced to link with libm.a, so using a
-        ** division loop rather than a log function.  
+           Don't want to be forced to link with libm.a, so using a
+           division loop rather than a log function.  
         */
         unsigned int i;
         for (*charsppP = 0, i = ncolors; i > 0; ++(*charsppP))
@@ -209,7 +212,7 @@ genCmap(struct pam *   const pamP,
     }
 
     /* Generate the character-pixel string and the rgb name for each colormap
-    ** entry.
+       entry.
     */
     for (colorIndex = 0; colorIndex < ncolors; ++colorIndex) {
         bool nameAlreadyInCmap;
@@ -237,7 +240,7 @@ genCmap(struct pam *   const pamP,
         nameAlreadyInCmap = FALSE;   /* initial assumption */
         for (j = 0; j < colorIndex; ++j) {
             if (cmap[j].rgbname != NULL && 
-                STREQ(colorname, cmap[j].rgbname) &&
+                streq(colorname, cmap[j].rgbname) &&
                 cmap[j].transparent == transparent) {
                 nameAlreadyInCmap = TRUE;
                 indexOfName = j;
@@ -247,12 +250,12 @@ genCmap(struct pam *   const pamP,
             /* Make the entry a cross-reference to the earlier entry */
             cmap[colorIndex].uilname = NULL;
             cmap[colorIndex].rgbname = NULL;
-            cmap[colorIndex].cixel = cmap[indexOfName].cixel;
+            cmap[colorIndex].cixel   = cmap[indexOfName].cixel;
         } else {
             cmap[colorIndex].uilname = uilName(colorname, transparent);
             cmap[colorIndex].rgbname = strdup(colorname);
             if (cmap[colorIndex].rgbname == NULL)
-                pm_error( "out of memory allocating color name" );
+                pm_error("out of memory allocating color name");
             
             cmap[colorIndex].transparent = transparent;
             
@@ -329,15 +332,16 @@ writeRaster(struct pam *  const pamP,
             unsigned int  const ncolors,
             tuplehash     const cht, 
             unsigned int  const charspp) {
-    
-    int row;
-    /* Write out the ascii character-pixel image. */
+/*----------------------------------------------------------------------------
+   Write out the ascii character-pixel image.
+-----------------------------------------------------------------------------*/
+    unsigned int row;
 
     printf("\n");
     printf("%s_icon : exported icon( color_table = %s_rgb,\n",
            outname, outname);
     for (row = 0; row < pamP->height; ++row) {
-        int col;
+        unsigned int col;
 
         printf("    '");
         for (col = 0; col < pamP->width; ++col) {
@@ -360,27 +364,19 @@ writeRaster(struct pam *  const pamP,
 }
 
 
-static void
-freeString(const char * const s) {
-/*----------------------------------------------------------------------------
-   This is just free(), but with type checking for const char *.
------------------------------------------------------------------------------*/
-    free((void *)s);
-}
-
-
 
 static void
-freeCmap(cixel_map cmap[], unsigned int const ncolors) {
+freeCmap(cixel_map    const cmap[],
+         unsigned int const ncolors) {
 
-    int i;
+    unsigned int i;
 
     for (i = 0; i < ncolors; ++i) {
         cixel_map const cmapEntry = cmap[i];
         if (cmapEntry.uilname)
-            freeString(cmapEntry.uilname);
+            strfree(cmapEntry.uilname);
         if (cmapEntry.rgbname)
-            freeString(cmapEntry.rgbname);
+            strfree(cmapEntry.rgbname);
     }
 }
 
@@ -391,8 +387,8 @@ main(int argc, char *argv[]) {
 
     struct cmdlineInfo cmdline;
     struct pam pam;   /* Input PAM image */
-    FILE* ifP;
-    tuple** tuples;
+    FILE * ifP;
+    tuple ** tuples;
     unsigned int ncolors;
     tuplehash cht;
     tupletable chv;
diff --git a/converter/other/pamtoxvmini.c b/converter/other/pamtoxvmini.c
index 3207b0d5..e1aa9b52 100644
--- a/converter/other/pamtoxvmini.c
+++ b/converter/other/pamtoxvmini.c
@@ -67,7 +67,6 @@ makeXvPalette(xvPalette * const xvPaletteP) {
             }
         }
     }
-
 }
 
 
@@ -237,7 +236,7 @@ main(int    argc,
     struct pam pam;
     xvPalette xvPalette;
  
-    ppm_init(&argc, argv);
+    pnm_init(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
diff --git a/converter/other/pfmtopam.c b/converter/other/pfmtopam.c
index 9430f5fa..1617ed31 100644
--- a/converter/other/pfmtopam.c
+++ b/converter/other/pfmtopam.c
@@ -15,6 +15,7 @@
 #include <string.h>
 #include <assert.h>
 
+#include "pm_c_util.h"
 #include "pam.h"
 #include "pm_gamma.h"
 #include "shhopt.h"
diff --git a/converter/other/pgmtopbm.c b/converter/other/pgmtopbm.c
index 98bdc332..f828b716 100644
--- a/converter/other/pgmtopbm.c
+++ b/converter/other/pgmtopbm.c
@@ -11,10 +11,12 @@
 */
 
 #include <assert.h>
+
+#include "pm_c_util.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};
 
@@ -346,6 +348,10 @@ struct converter {
 
 
 
+/*=============================================================================
+                 Converter: fs
+=============================================================================*/
+
 unsigned int const fs_scale      = 1024;
 unsigned int const half_fs_scale = 512;
 
@@ -445,7 +451,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]) */
@@ -468,6 +474,10 @@ createFsConverter(unsigned int const cols,
 
 
 
+/*=============================================================================
+                 Converter: thresh
+=============================================================================*/
+
 struct threshState {
     gray threshval;
 };
@@ -521,16 +531,28 @@ createThreshConverter(unsigned int const cols,
 
 
 
+/*=============================================================================
+                 Converter: dither8
+=============================================================================*/
+
+struct dither8State {
+    int dither8[16][16];
+};
+
+
+
 static void
 dither8ConvertRow(struct converter * const converterP,
                   unsigned int       const row,
                   gray                     grayrow[],
                   bit                      bitrow[]) {
 
+    struct dither8State * const stateP = converterP->stateP;
+
     unsigned int col;
 
     for (col = 0; col < converterP->cols; ++col)
-        if (grayrow[col] > dither8[row % 16][col % 16])
+        if (grayrow[col] > stateP->dither8[row % 16][col % 16])
             bitrow[col] = PBM_WHITE;
         else
             bitrow[col] = PBM_BLACK;
@@ -538,29 +560,47 @@ dither8ConvertRow(struct converter * const converterP,
 
 
 
+static void
+dither8Destroy(struct converter * const converterP) {
+
+    struct dither8State * const stateP = converterP->stateP;
+
+    free(stateP);
+}
+
+
+
 static struct converter
 createDither8Converter(unsigned int const cols, 
                        gray         const maxval) {
 
     struct converter converter;
+    struct dither8State * stateP;
 
     unsigned int row;
 
+    MALLOCVAR_NOFAIL(stateP);
+
     converter.cols = cols;
     converter.convertRow = &dither8ConvertRow;
-    converter.destroy = NULL;
+    converter.destroy = dither8Destroy;
+    converter.stateP = stateP;
 
     /* Scale dither matrix. */
     for (row = 0; row < 16; ++row) {
         unsigned int col;
         for (col = 0; col < 16; ++col)
-            dither8[row][col] = dither8[row][col] * maxval / 256;
+            stateP->dither8[row][col] = dither8[row][col] * maxval / 256;
     }
     return converter;
 }
 
 
 
+/*=============================================================================
+                 Converter: cluster
+=============================================================================*/
+
 struct clusterState {
     unsigned int radius;
     int ** clusterMatrix;
diff --git a/converter/other/pgmtoppm.c b/converter/other/pgmtoppm.c
index 7693fe0a..7194db49 100644
--- a/converter/other/pgmtoppm.c
+++ b/converter/other/pgmtoppm.c
@@ -10,147 +10,232 @@
 ** implied warranty.
 */
 
+#define _BSD_SOURCE  /* Make sure strdup() is in <string.h> */
 #include <string.h>
+
+#include "pm_c_util.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/pngtopam.c b/converter/other/pngtopam.c
new file mode 100644
index 00000000..89ac100a
--- /dev/null
+++ b/converter/other/pngtopam.c
@@ -0,0 +1,1281 @@
+/*
+** Copyright (C) 1995,1998 by Alexander Lehmann <alex@hal.rhein-main.de>
+**                        and Willem van Schaik <willem@schaik.com>
+**
+** 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.
+**
+** modeled after giftopnm by David Koblas and
+** with lots of bits pasted from libpng.txt by Guy Eric Schalnat
+*/
+
+#ifndef PNMTOPNG_WARNING_LEVEL
+#  define PNMTOPNG_WARNING_LEVEL 0   /* use 0 for backward compatibility, */
+#endif                               /*  2 for warnings (1 == error) */
+
+
+#include <assert.h>
+#include <math.h>
+#include <float.h>
+#include <png.h>    /* includes zlib.h and setjmp.h */
+#define VERSION "2.37.4 (5 December 1999) +netpbm"
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "nstring.h"
+#include "shhopt.h"
+#include "pam.h"
+
+/* A hack until we can remove direct access to png_info from the program */
+#if PNG_LIBPNG_VER >= 10400
+#define trans_values trans_color
+#define TRANS_ALPHA trans_alpha
+#else
+#define TRANS_ALPHA trans
+#endif
+
+typedef struct _jmpbuf_wrapper {
+  jmp_buf jmpbuf;
+} jmpbuf_wrapper;
+
+enum alpha_handling {ALPHA_NONE, ALPHA_ONLY, ALPHA_MIX, ALPHA_IN};
+
+struct cmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char *inputFilespec;  /* '-' if stdin */
+    unsigned int verbose;
+    enum alpha_handling alpha;
+    const char * background;
+    float gamma;  /* -1.0 means unspecified */
+    const char * text;
+    unsigned int time;
+};
+
+
+typedef struct {
+/*----------------------------------------------------------------------------
+   A color in a format compatible with the PNG library.
+
+   Note that the PNG library declares types png_color and png_color_16
+   which are similar.
+-----------------------------------------------------------------------------*/
+    png_uint_16 r;
+    png_uint_16 g;
+    png_uint_16 b;
+} pngcolor;
+
+
+static png_uint_16 maxval;
+static bool verbose;
+static jmpbuf_wrapper pngtopnm_jmpbuf_struct;
+
+
+static void
+parseCommandLine(int                  argc, 
+                 const char **        argv,
+                 struct cmdlineInfo * cmdlineP ) {
+/*----------------------------------------------------------------------------
+   Parse program command line described in Unix standard form by argc
+   and argv.  Return the information in the options as *cmdlineP.  
+
+   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 alphaSpec, alphapamSpec, mixSpec,
+        backgroundSpec, gammaSpec, textSpec;
+
+    MALLOCARRAY(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "verbose",     OPT_FLAG,   NULL,                  
+            &cmdlineP->verbose,       0);
+    OPTENT3(0, "alpha",       OPT_FLAG,   NULL,                  
+            &alphaSpec,               0);
+    OPTENT3(0, "alphapam",    OPT_FLAG,   NULL,                  
+            &alphapamSpec,            0);
+    OPTENT3(0, "mix",         OPT_FLAG,   NULL,                  
+            &mixSpec,                 0);
+    OPTENT3(0, "background",  OPT_STRING, &cmdlineP->background,
+            &backgroundSpec,          0);
+    OPTENT3(0, "gamma",       OPT_FLOAT,  &cmdlineP->gamma,
+            &gammaSpec,               0);
+    OPTENT3(0, "text",        OPT_STRING, &cmdlineP->text,
+            &textSpec,                0);
+    OPTENT3(0, "time",        OPT_FLAG,   NULL,                  
+            &cmdlineP->time,          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, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+
+    if (alphaSpec + mixSpec + alphapamSpec > 1)
+        pm_error("You cannot specify more than one of -alpha -alphapam -mix");
+    else if (alphaSpec)
+        cmdlineP->alpha = ALPHA_ONLY;
+    else if (mixSpec)
+        cmdlineP->alpha = ALPHA_MIX;
+    else if (alphapamSpec)
+        cmdlineP->alpha = ALPHA_IN;
+    else
+        cmdlineP->alpha = ALPHA_NONE;
+
+    if (backgroundSpec && !mixSpec)
+        pm_error("-background is useless without -mix");
+
+    if (!backgroundSpec)
+        cmdlineP->background = NULL;
+
+    if (!gammaSpec)
+        cmdlineP->gamma = -1.0;
+
+    if (!textSpec)
+        cmdlineP->text = NULL;
+
+    if (argc-1 < 1)
+        cmdlineP->inputFilespec = "-";
+    else if (argc-1 == 1)
+        cmdlineP->inputFilespec = argv[1];
+    else
+        pm_error("Program takes at most one argument: input file name.  "
+            "you specified %d", argc-1);
+}
+
+
+
+static png_uint_16
+get_png_val(const png_byte ** const pp,
+            int               const bit_depth) {
+
+    png_uint_16 c;
+    
+    if (bit_depth == 16)
+        c = (*((*pp)++)) << 8;
+    else
+        c = 0;
+
+    c |= (*((*pp)++));
+    
+    return c;
+}
+
+
+
+static bool
+isGrayscale(pngcolor const color) {
+
+    return color.r == color.g && color.r == color.b;
+}
+
+
+
+static sample
+alphaMix(png_uint_16 const foreground,
+         png_uint_16 const background,
+         png_uint_16 const alpha,
+         sample      const maxval) {
+
+    double const opacity      = (double)alpha / maxval;
+    double const transparency = 1.0 - opacity;
+
+    return ROUNDU(foreground * opacity + background * transparency);
+}
+
+
+
+static void
+setTuple(const struct pam *  const pamP,
+         tuple               const tuple,
+         pngcolor            const foreground,
+         pngcolor            const background,
+         enum alpha_handling const alphaHandling,
+         png_uint_16         const alpha) {
+
+    if (alphaHandling == ALPHA_ONLY)
+        tuple[0] = alpha;
+    else if (alphaHandling == ALPHA_NONE ||
+             (alphaHandling == ALPHA_MIX && alpha == maxval)) {
+        if (pamP->depth < 3)
+            tuple[0] = foreground.r;
+        else {
+            tuple[PAM_RED_PLANE] = foreground.r;
+            tuple[PAM_GRN_PLANE] = foreground.g;
+            tuple[PAM_BLU_PLANE] = foreground.b;
+        }
+    } else if (alphaHandling == ALPHA_IN) {
+        if (pamP->depth < 4) {
+            tuple[0] = foreground.r;
+            tuple[PAM_GRAY_TRN_PLANE] = alpha;
+        } else {
+            tuple[PAM_RED_PLANE] = foreground.r;
+            tuple[PAM_GRN_PLANE] = foreground.g;
+            tuple[PAM_BLU_PLANE] = foreground.b;
+            tuple[PAM_TRN_PLANE] = alpha;
+        }    
+    } else {
+        assert(alphaHandling == ALPHA_MIX);
+
+        if (pamP->depth < 3)
+            tuple[0] =
+                alphaMix(foreground.r, background.r, alpha, maxval);
+        else {
+            tuple[PAM_RED_PLANE] =
+                alphaMix(foreground.r, background.r, alpha, maxval);
+            tuple[PAM_GRN_PLANE] =
+                alphaMix(foreground.g, background.g, alpha, maxval);
+            tuple[PAM_BLU_PLANE] =
+                alphaMix(foreground.b, background.b, alpha, maxval);
+        }
+    }
+}
+
+
+
+static png_uint_16
+gamma_correct(png_uint_16 const v,
+              float       const g) {
+
+    if (g != -1.0)
+        return (png_uint_16) ROUNDU(pow((double) v / maxval, (1.0 / g)) *
+                                    maxval);
+    else
+        return v;
+}
+
+
+
+static int iscolor (png_color c)
+{
+  return c.red != c.green || c.green != c.blue;
+}
+
+static void save_text (png_info *info_ptr, FILE *tfp)
+{
+  int i, j, k;
+
+  for (i = 0 ; i < info_ptr->num_text ; i++) {
+    j = 0;
+    while (info_ptr->text[i].key[j] != '\0' && info_ptr->text[i].key[j] != ' ')
+      j++;    
+    if (info_ptr->text[i].key[j] != ' ') {
+      fprintf (tfp, "%s", info_ptr->text[i].key);
+      for (j = strlen (info_ptr->text[i].key) ; j < 15 ; j++)
+        putc (' ', tfp);
+    } else {
+      fprintf (tfp, "\"%s\"", info_ptr->text[i].key);
+      for (j = strlen (info_ptr->text[i].key) ; j < 13 ; j++)
+        putc (' ', tfp);
+    }
+    putc (' ', tfp); /* at least one space between key and text */
+    
+    for (j = 0 ; j < info_ptr->text[i].text_length ; j++) {
+      putc (info_ptr->text[i].text[j], tfp);
+      if (info_ptr->text[i].text[j] == '\n')
+        for (k = 0 ; k < 16 ; k++)
+          putc ((int)' ', tfp);
+    }
+    putc ((int)'\n', tfp);
+  }
+}
+
+static void show_time (png_info *info_ptr)
+{
+    static const char * const month[] = {
+        "", "January", "February", "March", "April", "May", "June",
+        "July", "August", "September", "October", "November", "December"
+    };
+
+  if (info_ptr->valid & PNG_INFO_tIME) {
+    if (info_ptr->mod_time.month < 1 ||
+      info_ptr->mod_time.month >= ARRAY_SIZE(month)) {
+      pm_message("tIME chunk in PNG input is invalid; "
+                 "modification time of image is unknown.  "
+                 "The month value, which should be in the range "
+                 "1-12, is %u", info_ptr->mod_time.month);
+    } else
+    pm_message ("modification time: %02d %s %d %02d:%02d:%02d",
+                info_ptr->mod_time.day, month[info_ptr->mod_time.month],
+                info_ptr->mod_time.year, info_ptr->mod_time.hour,
+                info_ptr->mod_time.minute, info_ptr->mod_time.second);
+  }
+}
+
+static void pngtopnm_error_handler (png_structp png_ptr, png_const_charp msg)
+{
+  jmpbuf_wrapper  *jmpbuf_ptr;
+
+  /* this function, aside from the extra step of retrieving the "error
+   * pointer" (below) and the fact that it exists within the application
+   * rather than within libpng, is essentially identical to libpng's
+   * default error handler.  The second point is critical:  since both
+   * setjmp() and longjmp() are called from the same code, they are
+   * guaranteed to have compatible notions of how big a jmp_buf is,
+   * regardless of whether _BSD_SOURCE or anything else has (or has not)
+   * been defined. */
+
+  pm_message("fatal libpng error: %s", msg);
+
+  jmpbuf_ptr = png_get_error_ptr(png_ptr);
+  if (jmpbuf_ptr == NULL) {
+      /* we are completely hosed now */
+      pm_error("EXTREMELY fatal error: jmpbuf unrecoverable; terminating.");
+  }
+
+  longjmp(jmpbuf_ptr->jmpbuf, 1);
+}
+
+
+
+static void
+dump_png_info(png_info *info_ptr) {
+
+    const char *type_string;
+    const char *filter_string;
+
+    switch (info_ptr->color_type) {
+      case PNG_COLOR_TYPE_GRAY:
+        type_string = "gray";
+        break;
+
+      case PNG_COLOR_TYPE_GRAY_ALPHA:
+        type_string = "gray+alpha";
+        break;
+
+      case PNG_COLOR_TYPE_PALETTE:
+        type_string = "palette";
+        break;
+
+      case PNG_COLOR_TYPE_RGB:
+        type_string = "truecolor";
+        break;
+
+      case PNG_COLOR_TYPE_RGB_ALPHA:
+        type_string = "truecolor+alpha";
+        break;
+    }
+
+    switch (info_ptr->filter_type) {
+    case PNG_FILTER_TYPE_BASE:
+        asprintfN(&filter_string, "base filter");
+        break;
+    default:
+        asprintfN(&filter_string, "unknown filter type %d", 
+                  info_ptr->filter_type);
+    }
+
+    pm_message("reading a %ldw x %ldh image, %d bit%s",
+               info_ptr->width, info_ptr->height,
+               info_ptr->bit_depth, info_ptr->bit_depth > 1 ? "s" : "");
+    pm_message("%s, %s, %s",
+               type_string,
+               info_ptr->interlace_type ? 
+               "Adam7 interlaced" : "not interlaced",
+               filter_string);
+    pm_message("background {index, gray, red, green, blue} = "
+               "{%d, %d, %d, %d, %d}",
+               info_ptr->background.index,
+               info_ptr->background.gray,
+               info_ptr->background.red,
+               info_ptr->background.green,
+               info_ptr->background.blue);
+
+    strfree(filter_string);
+
+    if (info_ptr->valid & PNG_INFO_tRNS)
+        pm_message("tRNS chunk (transparency): %u entries",
+                   info_ptr->num_trans);
+    else
+        pm_message("tRNS chunk (transparency): not present");
+
+    if (info_ptr->valid & PNG_INFO_gAMA)
+        pm_message("gAMA chunk (image gamma): gamma = %4.2f", info_ptr->gamma);
+    else
+        pm_message("gAMA chunk (image gamma): not present");
+
+    if (info_ptr->valid & PNG_INFO_sBIT)
+        pm_message("sBIT chunk: present");
+    else
+        pm_message("sBIT chunk: not present");
+
+    if (info_ptr->valid & PNG_INFO_cHRM)
+        pm_message("cHRM chunk: present");
+    else
+        pm_message("cHRM chunk: not present");
+
+    if (info_ptr->valid & PNG_INFO_PLTE)
+        pm_message("PLTE chunk: %d entries", info_ptr->num_palette);
+    else
+        pm_message("PLTE chunk: not present");
+
+    if (info_ptr->valid & PNG_INFO_bKGD)
+        pm_message("bKGD chunk: present");
+    else
+        pm_message("bKGD chunk: not present");
+
+    if (info_ptr->valid & PNG_INFO_hIST)
+        pm_message("hIST chunk: present");
+    else
+        pm_message("hIST chunk: not present");
+
+    if (info_ptr->valid & PNG_INFO_pHYs)
+        pm_message("pHYs chunk: present");
+    else
+        pm_message("pHYs chunk: not present");
+
+    if (info_ptr->valid & PNG_INFO_oFFs)
+        pm_message("oFFs chunk: present");
+    else
+        pm_message("oFFs chunk: not present");
+
+    if (info_ptr->valid & PNG_INFO_tIME)
+        pm_message("tIME chunk: present");
+    else
+        pm_message("tIME chunk: not present");
+
+    if (info_ptr->valid & PNG_INFO_pCAL)
+        pm_message("pCAL chunk: present");
+    else
+        pm_message("pCAL chunk: not present");
+
+    if (info_ptr->valid & PNG_INFO_sRGB)
+        pm_message("sRGB chunk: present");
+    else
+        pm_message("sRGB chunk: not present");
+}
+
+
+
+static unsigned int
+computePngLineSize(png_info * const pngInfoP) {
+
+    unsigned int const bytesPerSample = pngInfoP->bit_depth == 16 ? 2 : 1;
+
+    unsigned int samplesPerPixel;
+
+    switch (pngInfoP->color_type) {
+    case PNG_COLOR_TYPE_GRAY_ALPHA: samplesPerPixel = 2; break;
+    case PNG_COLOR_TYPE_RGB:        samplesPerPixel = 3; break;
+    case PNG_COLOR_TYPE_RGB_ALPHA:  samplesPerPixel = 4; break;
+    default:                        samplesPerPixel = 1;
+    }
+
+    if (UINT_MAX / bytesPerSample / samplesPerPixel < pngInfoP->width)
+        pm_error("Width %u of PNG is uncomputably large",
+                 (unsigned int)pngInfoP->width);
+       
+    return pngInfoP->width * bytesPerSample * samplesPerPixel;
+}
+
+
+
+static void
+allocPngRaster(png_info *   const pngInfoP,
+               png_byte *** const pngImageP) {
+
+    unsigned int const lineSize = computePngLineSize(pngInfoP);
+
+    png_byte ** pngImage;
+    unsigned int row;
+
+    MALLOCARRAY(pngImage, pngInfoP->height);
+
+    if (pngImage == NULL)
+        pm_error("couldn't allocate space for %u PNG raster rows",
+                 (unsigned int)pngInfoP->height);
+
+    for (row = 0; row < pngInfoP->height; ++row) {
+        MALLOCARRAY(pngImage[row], lineSize);
+        if (pngImage[row] == NULL)
+            pm_error("couldn't allocate space for %uth row of PNG raster",
+                     row);
+    }
+    *pngImageP = pngImage;
+}
+
+
+
+static void
+freePngRaster(png_byte ** const pngRaster,
+              png_info *  const pngInfoP) {
+
+    unsigned int row;
+
+    for (row = 0; row < pngInfoP->height; ++row)
+        free(pngRaster[row]);
+
+    free(pngRaster);
+}
+
+
+
+static bool
+isTransparentColor(pngcolor   const color,
+                   png_info * const pngInfoP,
+                   double     const totalgamma) {
+/*----------------------------------------------------------------------------
+   Return TRUE iff pixels of color 'color' are supposed to be transparent
+   everywhere they occur.  Assume it's an RGB image.
+
+   'color' has been gamma-corrected.
+-----------------------------------------------------------------------------*/
+    bool retval;
+
+    if (pngInfoP->valid & PNG_INFO_tRNS) {
+        const png_color_16 * const transColorP = &pngInfoP->trans_values;
+
+        /* It seems odd that libpng lets you get gamma-corrected pixel
+           values, but not gamma-corrected transparency or background
+           values.  But as that is the case, we have to gamma-correct
+           the transparency values.
+
+           Note that because we compare the gamma-corrected values and
+           there may be many-to-one mapping of uncorrected to corrected
+           values, more pixels may be transparent than what the user
+           intended.
+
+           We could fix this by not letting libpng gamma-correct the
+           pixels, and just do it ourselves.
+        */
+    
+        switch (pngInfoP->color_type) {
+        case PNG_COLOR_TYPE_GRAY:
+            retval = color.r == gamma_correct(transColorP->gray, totalgamma);
+            break;
+        default:
+            retval = 
+                color.r == gamma_correct(transColorP->red,   totalgamma) &&
+                color.g == gamma_correct(transColorP->green, totalgamma) &&
+                color.b == gamma_correct(transColorP->blue,  totalgamma);
+        }
+    } else 
+        retval = FALSE;
+
+    return retval;
+}
+
+
+
+#define SIG_CHECK_SIZE 4
+
+static void
+read_sig_buf(FILE * const ifP) {
+
+    unsigned char sig_buf[SIG_CHECK_SIZE];
+    size_t bytesRead;
+
+    bytesRead = fread(sig_buf, 1, SIG_CHECK_SIZE, ifP);
+    if (bytesRead != SIG_CHECK_SIZE)
+        pm_error ("input file is empty or too short");
+
+    if (png_sig_cmp(sig_buf, (png_size_t) 0, (png_size_t) SIG_CHECK_SIZE)
+        != 0)
+        pm_error ("input file is not a PNG file");
+}
+
+
+
+static void
+setupGammaCorrection(png_struct * const png_ptr,
+                     png_info *   const info_ptr,
+                     float        const displaygamma,
+                     float *      const totalgammaP) {
+
+    if (displaygamma == -1.0)
+        *totalgammaP = -1.0;
+    else {
+        float imageGamma;
+        if (info_ptr->valid & PNG_INFO_gAMA)
+            imageGamma = info_ptr->gamma;
+        else {
+            if (verbose)
+                pm_message("PNG doesn't specify image gamma.  Assuming 1.0");
+            imageGamma = 1.0;
+        }
+
+        if (fabs(displaygamma * imageGamma - 1.0) < .01) {
+            *totalgammaP = -1.0;
+            if (verbose)
+                pm_message("image gamma %4.2f matches "
+                           "display gamma %4.2f.  No conversion.",
+                           imageGamma, displaygamma);
+        } else {
+            png_set_gamma(png_ptr, displaygamma, imageGamma);
+            *totalgammaP = imageGamma * displaygamma;
+            /* in case of gamma-corrections, sBIT's as in the
+               PNG-file are not valid anymore 
+            */
+            info_ptr->valid &= ~PNG_INFO_sBIT;
+            if (verbose)
+                pm_message("image gamma is %4.2f, "
+                           "converted for display gamma of %4.2f",
+                           imageGamma, displaygamma);
+        }
+    }
+}
+
+
+
+static bool
+paletteHasPartialTransparency(png_info * const info_ptr) {
+
+    bool retval;
+
+    if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
+        if (info_ptr->valid & PNG_INFO_tRNS) {
+            bool foundGray;
+            unsigned int i;
+            
+            for (i = 0, foundGray = FALSE;
+                 i < info_ptr->num_trans && !foundGray;
+                 ++i) {
+                if (info_ptr->TRANS_ALPHA[i] != 0 &&
+                    info_ptr->TRANS_ALPHA[i] != maxval) {
+                    foundGray = TRUE;
+                }
+            }
+            retval = foundGray;
+        } else
+            retval = FALSE;
+    } else
+        retval = FALSE;
+
+    return retval;
+}
+
+
+
+static void
+getComponentSbitFg(png_info * const pngInfoP,
+                   png_byte * const fgSbitP,
+                   bool *     const notUniformP) {
+
+    if (pngInfoP->color_type == PNG_COLOR_TYPE_RGB ||
+        pngInfoP->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
+        pngInfoP->color_type == PNG_COLOR_TYPE_PALETTE) {
+        if (pngInfoP->sig_bit.red == pngInfoP->sig_bit.blue &&
+            pngInfoP->sig_bit.red == pngInfoP->sig_bit.green) {
+            *notUniformP = false;
+            *fgSbitP     = pngInfoP->sig_bit.red;
+        } else
+            *notUniformP = true;
+    } else {
+        /* It has only a gray channel so it's obviously uniform */
+        *notUniformP = false;
+        *fgSbitP     = pngInfoP->sig_bit.gray;
+    }
+}
+
+
+
+static void
+getComponentSbit(png_info *          const pngInfoP,
+                 enum alpha_handling const alphaHandling,
+                 png_byte *          const componentSbitP,
+                 bool *              const notUniformP) {
+
+    switch (alphaHandling) {
+
+    case ALPHA_ONLY:
+        /* We care only about the alpha channel, so the uniform Sbit is
+           the alpha Sbit
+        */
+        *notUniformP = false;
+        *componentSbitP = pngInfoP->sig_bit.alpha;
+        break;
+    case ALPHA_NONE:
+    case ALPHA_MIX:
+        /* We aren't going to produce an alpha channel, so we care only
+           about the uniformity of the foreground channels.
+        */
+        getComponentSbitFg(pngInfoP, componentSbitP, notUniformP);
+        break;
+    case ALPHA_IN: {
+        /* We care about both the foreground and the alpha */
+        bool fgNotUniform;
+        png_byte fgSbit;
+        
+        getComponentSbitFg(pngInfoP, &fgSbit, &fgNotUniform);
+
+        if (fgNotUniform)
+            *notUniformP = true;
+        else {
+            if (fgSbit == pngInfoP->sig_bit.alpha) {
+                *notUniformP    = false;
+                *componentSbitP = fgSbit;
+            } else
+                *notUniformP = true;
+        }
+    } break;
+    }
+}
+
+                 
+
+static void
+shiftPalette(png_info *   const pngInfoP,
+             unsigned int const shift) {
+/*----------------------------------------------------------------------------
+   Shift every component of every color in the PNG palette right by
+   'shift' bits because sBIT chunk says only those are significant.
+-----------------------------------------------------------------------------*/
+    if (shift > 7)
+        pm_error("Invalid PNG: paletted image can't have "
+                 "more than 8 significant bits per component, "
+                 "but sBIT chunk says %u bits",
+                 shift);
+    else {
+        unsigned int i;
+        
+        for (i = 0; i < pngInfoP->num_palette; ++i) {
+            pngInfoP->palette[i].red   >>= (8 - shift);
+            pngInfoP->palette[i].green >>= (8 - shift);
+            pngInfoP->palette[i].blue  >>= (8 - shift);
+        }
+    }
+}
+
+
+
+static void
+computeMaxvalFromSbit(png_struct *        const pngP,
+                      png_info *          const pngInfoP,
+                      enum alpha_handling const alphaHandling,
+                      png_uint_16 *       const maxvalP,
+                      bool *              const succeededP,
+                      int *               const errorlevelP) {
+
+    /* sBIT handling is very tricky. If we are extracting only the
+       image, we can use the sBIT info for grayscale and color images,
+       if the three values agree. If we extract the transparency/alpha
+       mask, sBIT is irrelevant for trans and valid for alpha. If we
+       mix both, the multiplication may result in values that require
+       the normal bit depth, so we will use the sBIT info only for
+       transparency, if we know that only solid and fully transparent
+       is used 
+    */
+
+    bool notUniform;
+        /* The sBIT chunk says the number of significant high-order bits
+           in each component varies among the components we care about.
+        */
+    png_byte componentSigBit;
+        /* The number of high-order significant bits in each RGB component.
+           Meaningless if they aren't all the same (i.e. 'notUniform')
+        */
+
+    getComponentSbit(pngInfoP, alphaHandling, &componentSigBit, &notUniform);
+
+    if (notUniform) {
+        pm_message("This program cannot handle "
+                   "different bit depths for color channels");
+        pm_message("writing file with %u bit resolution", pngInfoP->bit_depth);
+        *succeededP = false;
+        *errorlevelP = PNMTOPNG_WARNING_LEVEL;
+    } else if (componentSigBit > 15) {
+        pm_message("Invalid PNG: says %u significant bits for a component; "
+                   "max possible is 16.  Ignoring sBIT chunk.",
+                   componentSigBit);
+        *succeededP = false;
+        *errorlevelP = PNMTOPNG_WARNING_LEVEL;
+    } else {
+        if (alphaHandling == ALPHA_MIX &&
+            (pngInfoP->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
+             pngInfoP->color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
+             paletteHasPartialTransparency(pngInfoP)))
+            *succeededP = false;
+        else {
+            if (componentSigBit < pngInfoP->bit_depth) {
+                pm_message("Image has fewer significant bits, "
+                           "writing file with %u bits", componentSigBit);
+                *maxvalP = (1l << componentSigBit) - 1;
+                *succeededP = true;
+
+                if (pngInfoP->color_type == PNG_COLOR_TYPE_PALETTE)
+                    shiftPalette(pngInfoP, componentSigBit);
+                else
+                    png_set_shift(pngP, &pngInfoP->sig_bit);
+            } else
+                *succeededP = false;
+        }
+    }
+}
+
+
+
+static void
+setupSignificantBits(png_struct *        const pngP,
+                     png_info *          const pngInfoP,
+                     enum alpha_handling const alphaHandling,
+                     png_uint_16 *       const maxvalP,
+                     int *               const errorlevelP) {
+/*----------------------------------------------------------------------------
+  Figure out what maxval would best express the information in the PNG
+  described by *pngP and *pngInfoP, with 'alpha' telling which
+  information in the PNG we care about (image or alpha mask).
+
+  Return the result as *maxvalP.
+
+  Also set up *pngP for the corresponding significant bits.
+-----------------------------------------------------------------------------*/
+    bool gotItFromSbit;
+    
+    if (pngInfoP->valid & PNG_INFO_sBIT)
+        computeMaxvalFromSbit(pngP, pngInfoP, alphaHandling,
+                              maxvalP, &gotItFromSbit, errorlevelP);
+    else
+        gotItFromSbit = false;
+
+    if (!gotItFromSbit) {
+        if (pngInfoP->color_type == PNG_COLOR_TYPE_PALETTE) {
+            if (alphaHandling == ALPHA_ONLY) {
+                if (pngInfoP->color_type == PNG_COLOR_TYPE_GRAY ||
+                    pngInfoP->color_type == PNG_COLOR_TYPE_RGB)
+                    /* The alpha mask will be all opaque, so maxval 1
+                       is plenty
+                    */
+                    *maxvalP = 1;
+                else if (paletteHasPartialTransparency(pngInfoP))
+                    /* Use same maxval as PNG transparency palette for
+                       simplicity
+                    */
+                    *maxvalP = 255;
+                else
+                    /* A common case, so we conserve bits */
+                    *maxvalP = 1;
+            } else
+                /* Use same maxval as PNG palette for simplicity */
+                *maxvalP = 255;
+        } else {
+            *maxvalP = (1l << pngInfoP->bit_depth) - 1;
+        }
+    }
+}
+
+
+
+static bool
+imageHasColor(png_info * const info_ptr) {
+
+    bool retval;
+
+    if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
+        info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+
+        retval = FALSE;
+    else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
+        bool foundColor;
+        unsigned int i;
+            
+        for (i = 0, foundColor = FALSE;
+             i < info_ptr->num_palette && !foundColor;
+             ++i) {
+            if (iscolor(info_ptr->palette[i]))
+                foundColor = TRUE;
+        }
+        retval = foundColor;
+    } else
+        retval = TRUE;
+
+    return retval;
+}
+
+
+
+static void
+determineOutputType(png_info *          const pngInfoP,
+                    enum alpha_handling const alphaHandling,
+                    pngcolor            const bgColor,
+                    xelval              const maxval,
+                    int *               const formatP,
+                    unsigned int *      const depthP,
+                    char *              const tupleType) {
+
+    if (alphaHandling == ALPHA_ONLY) {
+        /* The output is a old style pseudo-PNM transparency image */
+        *depthP = 1;
+        *formatP = maxval > 1 ? PGM_FORMAT : PBM_FORMAT;
+    } else {            
+        /* The output is a normal Netpbm image */
+        bool const outputIsColor =
+            imageHasColor(pngInfoP) || !isGrayscale(bgColor);
+
+        if (alphaHandling == ALPHA_IN) {
+            *formatP = PAM_FORMAT;
+            if (outputIsColor) {
+                *depthP = 4;
+                strcpy(tupleType, "RGB_ALPHA");
+            } else {
+                *depthP = 2;
+                strcpy(tupleType, "GRAYSCALE_ALPHA");
+            }
+        } else {
+            if (outputIsColor) {
+                *formatP = PPM_FORMAT;
+                *depthP = 3;
+            } else {
+                *depthP = 1;
+                *formatP = maxval > 1 ? PGM_FORMAT : PBM_FORMAT;
+            }
+        }
+    }
+}
+
+
+
+static void
+getBackgroundColor(png_info *   const info_ptr,
+                   const char * const requestedColor,
+                   float        const totalgamma,
+                   xelval       const maxval,
+                   pngcolor *   const bgColorP) {
+/*----------------------------------------------------------------------------
+   Figure out what the background color should be.  If the user requested
+   a particular color ('requestedColor' not null), that's the one.
+   Otherwise, if the PNG specifies a background color, that's the one.
+   And otherwise, it's white.
+-----------------------------------------------------------------------------*/
+    if (requestedColor) {
+        /* Background was specified from the command-line; we always
+           use that.  I chose to do no gamma-correction in this case;
+           which is a bit arbitrary.  
+        */
+        pixel const backcolor = ppm_parsecolor(requestedColor, maxval);
+
+        bgColorP->r = PPM_GETR(backcolor);
+        bgColorP->g = PPM_GETG(backcolor);
+        bgColorP->b = PPM_GETB(backcolor);
+
+    } else if (info_ptr->valid & PNG_INFO_bKGD) {
+        /* didn't manage to get libpng to work (bugs?) concerning background
+           processing, therefore we do our own.
+        */
+        switch (info_ptr->color_type) {
+        case PNG_COLOR_TYPE_GRAY:
+        case PNG_COLOR_TYPE_GRAY_ALPHA:
+            bgColorP->r = bgColorP->g = bgColorP->b = 
+                gamma_correct(info_ptr->background.gray, totalgamma);
+            break;
+        case PNG_COLOR_TYPE_PALETTE: {
+            png_color const rawBgcolor = 
+                info_ptr->palette[info_ptr->background.index];
+            bgColorP->r = gamma_correct(rawBgcolor.red, totalgamma);
+            bgColorP->g = gamma_correct(rawBgcolor.green, totalgamma);
+            bgColorP->b = gamma_correct(rawBgcolor.blue, totalgamma);
+        }
+        break;
+        case PNG_COLOR_TYPE_RGB:
+        case PNG_COLOR_TYPE_RGB_ALPHA: {
+            png_color_16 const rawBgcolor = info_ptr->background;
+            
+            bgColorP->r = gamma_correct(rawBgcolor.red,   totalgamma);
+            bgColorP->g = gamma_correct(rawBgcolor.green, totalgamma);
+            bgColorP->b = gamma_correct(rawBgcolor.blue,  totalgamma);
+        }
+        break;
+        }
+    } else 
+        /* when no background given, we use white [from version 2.37] */
+        bgColorP->r = bgColorP->g = bgColorP->b = maxval;
+}
+
+
+
+#define GET_PNG_VAL(p) get_png_val(&(p), pngInfoP->bit_depth)
+
+
+
+static void
+makeTupleRow(const struct pam *  const pamP,
+             const tuple *       const tuplerow,
+             png_info *          const pngInfoP,
+             const png_byte *    const pngRasterRow,
+             pngcolor            const bgColor,
+             enum alpha_handling const alphaHandling,
+             double              const totalgamma) {
+
+    const png_byte * pngPixelP;
+    unsigned int col;
+
+    pngPixelP = &pngRasterRow[0];  /* initial value */
+    for (col = 0; col < pngInfoP->width; ++col) {
+        switch (pngInfoP->color_type) {
+        case PNG_COLOR_TYPE_GRAY: {
+            pngcolor fgColor;
+            fgColor.r = fgColor.g = fgColor.b = GET_PNG_VAL(pngPixelP);
+            setTuple(pamP, tuplerow[col], fgColor, bgColor, alphaHandling,
+                   isTransparentColor(fgColor, pngInfoP, totalgamma) ?
+                   0 : maxval);
+        }
+        break;
+
+        case PNG_COLOR_TYPE_GRAY_ALPHA: {
+            pngcolor fgColor;
+            png_uint_16 alpha;
+
+            fgColor.r = fgColor.g = fgColor.b = GET_PNG_VAL(pngPixelP);
+            alpha = GET_PNG_VAL(pngPixelP);
+            setTuple(pamP, tuplerow[col], fgColor, bgColor,
+                     alphaHandling, alpha);
+        }
+        break;
+
+        case PNG_COLOR_TYPE_PALETTE: {
+            png_uint_16 const index        = GET_PNG_VAL(pngPixelP);
+            png_color   const paletteColor = pngInfoP->palette[index];
+
+            pngcolor fgColor;
+
+            fgColor.r = paletteColor.red;
+            fgColor.g = paletteColor.green;
+            fgColor.b = paletteColor.blue;
+
+            setTuple(pamP, tuplerow[col], fgColor, bgColor, alphaHandling,
+                     (pngInfoP->valid & PNG_INFO_tRNS) &&
+                     index < pngInfoP->num_trans ?
+                     pngInfoP->TRANS_ALPHA[index] : maxval);
+        }
+        break;
+                
+        case PNG_COLOR_TYPE_RGB: {
+            pngcolor fgColor;
+
+            fgColor.r = GET_PNG_VAL(pngPixelP);
+            fgColor.g = GET_PNG_VAL(pngPixelP);
+            fgColor.b = GET_PNG_VAL(pngPixelP);
+            setTuple(pamP, tuplerow[col], fgColor, bgColor, alphaHandling,
+                     isTransparentColor(fgColor, pngInfoP, totalgamma) ?
+                     0 : maxval);
+        }
+        break;
+
+        case PNG_COLOR_TYPE_RGB_ALPHA: {
+            pngcolor fgColor;
+            png_uint_16 alpha;
+
+            fgColor.r = GET_PNG_VAL(pngPixelP);
+            fgColor.g = GET_PNG_VAL(pngPixelP);
+            fgColor.b = GET_PNG_VAL(pngPixelP);
+            alpha     = GET_PNG_VAL(pngPixelP);
+            setTuple(pamP, tuplerow[col], fgColor, bgColor,
+                     alphaHandling, alpha);
+        }
+        break;
+
+        default:
+            pm_error("unknown PNG color type: %d", pngInfoP->color_type);
+        }
+    }
+}
+
+
+
+static void
+reportOutputFormat(const struct pam * const pamP) {
+
+    switch (pamP->format) {
+
+    case PBM_FORMAT:
+        pm_message("Writing a PBM file");
+        break;
+    case PGM_FORMAT:
+        pm_message("Writing a PGM file with maxval %lu", pamP->maxval);
+        break;
+    case PPM_FORMAT:
+        pm_message("Writing a PPM file with maxval %lu", pamP->maxval);
+        break;
+    case PAM_FORMAT:
+        pm_message("Writing a PAM file with tuple type %s, maxval %u",
+                   pamP->tuple_type, maxval);
+        break;
+    default:
+        assert(false); /* Every possible value handled above */
+    }
+}
+    
+
+
+static void
+writeNetpbm(struct pam *        const pamP,
+            png_info *          const pngInfoP,
+            png_byte **         const pngRaster,
+            pngcolor            const bgColor,
+            enum alpha_handling const alphaHandling,
+            double              const totalgamma) {
+/*----------------------------------------------------------------------------
+   Write a Netpbm image of either the image or the alpha mask, according to
+   'alphaHandling' that is in the PNG image described by 'pngInfoP' and
+   pngRaster.
+
+   *pamP describes the required output image and is consistent with
+   *pngInfoP.
+
+   Use background color 'bgColor' in the output if the PNG is such that a
+   background color is needed.
+-----------------------------------------------------------------------------*/
+    tuple * tuplerow;
+    unsigned int row;
+
+    if (verbose)
+        reportOutputFormat(pamP);
+
+    pnm_writepaminit(pamP);
+
+    tuplerow = pnm_allocpamrow(pamP);
+
+    for (row = 0; row < pngInfoP->height; ++row) {
+        makeTupleRow(pamP, tuplerow, pngInfoP, pngRaster[row], bgColor,
+                     alphaHandling, totalgamma);
+
+        pnm_writepamrow(pamP, tuplerow);
+    }
+    pnm_freepamrow(tuplerow);
+}
+
+
+
+static void 
+convertpng(FILE *             const ifp, 
+           FILE *             const tfp, 
+           struct cmdlineInfo const cmdline,
+           int *              const errorlevelP) {
+
+    png_struct * png_ptr;
+    png_info * info_ptr;
+    png_byte ** png_image;
+    pngcolor bgColor;
+    float totalgamma;
+    struct pam pam;
+
+    *errorlevelP = 0;
+
+    read_sig_buf(ifp);
+
+    png_ptr = png_create_read_struct(
+        PNG_LIBPNG_VER_STRING,
+        &pngtopnm_jmpbuf_struct, pngtopnm_error_handler, NULL);
+    if (png_ptr == NULL)
+        pm_error("cannot allocate main libpng structure (png_ptr)");
+
+    info_ptr = png_create_info_struct (png_ptr);
+    if (info_ptr == NULL)
+        pm_error("cannot allocate LIBPNG structures");
+
+    if (setjmp(pngtopnm_jmpbuf_struct.jmpbuf))
+        pm_error ("setjmp returns error condition");
+
+    png_init_io (png_ptr, ifp);
+    png_set_sig_bytes (png_ptr, SIG_CHECK_SIZE);
+    png_read_info (png_ptr, info_ptr);
+
+    allocPngRaster(info_ptr, &png_image);
+
+    if (info_ptr->bit_depth < 8)
+        png_set_packing (png_ptr);
+
+    setupGammaCorrection(png_ptr, info_ptr, cmdline.gamma, &totalgamma);
+
+    setupSignificantBits(png_ptr, info_ptr, cmdline.alpha,
+                         &maxval, errorlevelP);
+
+    getBackgroundColor(info_ptr, cmdline.background, totalgamma, maxval,
+                       &bgColor);
+
+    png_read_image(png_ptr, png_image);
+    png_read_end(png_ptr, info_ptr);
+
+    if (verbose)
+        /* Note that some of info_ptr is not defined until png_read_end() 
+           completes.  That's because it comes from chunks that are at the
+           end of the stream.
+        */
+        dump_png_info(info_ptr);
+
+    if (cmdline.time)
+        show_time(info_ptr);
+    if (tfp)
+        save_text(info_ptr, tfp);
+
+    if (info_ptr->valid & PNG_INFO_pHYs) {
+        float const r =
+            (float)info_ptr->x_pixels_per_unit / info_ptr->y_pixels_per_unit;
+        if (r != 1.0) {
+            pm_message ("warning - non-square pixels; "
+                        "to fix do a 'pamscale -%cscale %g'",
+                        r < 1.0 ? 'x' : 'y',
+                        r < 1.0 ? 1.0 / r : r );
+            *errorlevelP = PNMTOPNG_WARNING_LEVEL;
+        }
+    }
+
+    pam.size        = sizeof(pam);
+    pam.len         = PAM_STRUCT_SIZE(tuple_type);
+    pam.file        = stdout;
+    pam.plainformat = 0;
+    pam.height      = info_ptr->height;
+    pam.width       = info_ptr->width;
+    pam.maxval      = maxval;
+
+    determineOutputType(info_ptr, cmdline.alpha, bgColor, maxval,
+                        &pam.format, &pam.depth, pam.tuple_type);
+
+    writeNetpbm(&pam, info_ptr, png_image, bgColor, cmdline.alpha, totalgamma);
+
+    fflush(stdout);
+
+    freePngRaster(png_image, info_ptr);
+
+    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+}
+
+
+
+int 
+main(int argc, const char *argv[]) {
+
+    struct cmdlineInfo cmdline;
+    FILE * ifP;
+    FILE * tfP;
+    int errorlevel;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    verbose = cmdline.verbose;
+
+    ifP = pm_openr(cmdline.inputFilespec);
+
+    if (cmdline.text)
+        tfP = pm_openw(cmdline.text);
+    else
+        tfP = NULL;
+
+    convertpng(ifP, tfP, cmdline, &errorlevel);
+
+    if (tfP)
+        pm_close(tfP);
+
+    pm_close(ifP);
+    pm_close(stdout);
+
+    return errorlevel;
+}
diff --git a/converter/other/pngtopnm.c b/converter/other/pngtopnm.c
index 59149acd..a8ea25a7 100644
--- a/converter/other/pngtopnm.c
+++ b/converter/other/pngtopnm.c
@@ -1,6 +1,6 @@
 /*
 ** pngtopnm.c -
-** read a Portable Network Graphics file and produce a portable anymap
+** read a Portable Network Graphics file and produce a PNM.
 **
 ** Copyright (C) 1995,1998 by Alexander Lehmann <alex@hal.rhein-main.de>
 **                        and Willem van Schaik <willem@schaik.com>
@@ -16,61 +16,29 @@
 ** with lots of bits pasted from libpng.txt by Guy Eric Schalnat
 */
 
-/* 
-   BJH 20000408:  rename PPM_MAXMAXVAL to PPM_OVERALLMAXVAL
-   BJH 20000303:  fix include statement so dependencies work out right.
-*/
-/* GRR 19991203:  moved VERSION to new version.h header file */
-
-/* GRR 19990713:  fixed redundant freeing of png_ptr and info_ptr in setjmp()
- *  blocks and added "pm_close(ifp)" in each.  */
-
-/* GRR 19990317:  declared "clobberable" automatic variables in convertpng()
- *  static to fix Solaris/gcc stack-corruption bug.  Also installed custom
- *  error-handler to avoid jmp_buf size-related problems (i.e., jmp_buf
- *  compiled with one size in libpng and another size here).  */
-
 #ifndef PNMTOPNG_WARNING_LEVEL
 #  define PNMTOPNG_WARNING_LEVEL 0   /* use 0 for backward compatibility, */
 #endif                               /*  2 for warnings (1 == error) */
 
+#include <assert.h>
 #include <math.h>
 #include <float.h>
 #include <png.h>    /* includes zlib.h and setjmp.h */
 #define VERSION "2.37.4 (5 December 1999) +netpbm"
 
-#include "pnm.h"
+#include "pm_c_util.h"
 #include "mallocvar.h"
 #include "nstring.h"
 #include "shhopt.h"
+#include "pnm.h"
 
+/* A hack until we can remove direct access to png_info from the program */
 #if PNG_LIBPNG_VER >= 10400
-#error Your PNG library (<png.h>) is incompatible with this Netpbm source code.
-#error You need either an older PNG library (older than 1.4)
-#error newer Netpbm source code (at least 10.48)
-#endif
-
-typedef struct _jmpbuf_wrapper {
-  jmp_buf jmpbuf;
-} jmpbuf_wrapper;
-
-/* GRR 19991205:  this is used as a test for pre-1999 versions of netpbm and
- *   pbmplus vs. 1999 or later (in which pm_close was split into two)
- */
-#ifdef PBMPLUS_RAWBITS
-#  define pm_closer pm_close
-#  define pm_closew pm_close
+#define TRANS_ALPHA trans_alpha
+#else
+#define TRANS_ALPHA trans
 #endif
 
-#ifndef TRUE
-#  define TRUE 1
-#endif
-#ifndef FALSE
-#  define FALSE 0
-#endif
-#ifndef NONE
-#  define NONE 0
-#endif
 
 enum alpha_handling {ALPHA_NONE, ALPHA_ONLY, ALPHA_MIX};
 
@@ -88,7 +56,7 @@ struct cmdlineInfo {
 };
 
 
-typedef struct pngcolor {
+typedef struct {
 /*----------------------------------------------------------------------------
    A color in a format compatible with the PNG library.
 
@@ -102,15 +70,13 @@ typedef struct pngcolor {
 
 
 static png_uint_16 maxval;
-static int verbose = FALSE;
-static int mtime;
-static jmpbuf_wrapper pngtopnm_jmpbuf_struct;
+static bool verbose;
 
 
 static void
-parseCommandLine(int                 argc, 
-                 char **             argv,
-                 struct cmdlineInfo *cmdlineP ) {
+parseCommandLine(int                  argc, 
+                 const char **        argv,
+                 struct cmdlineInfo * cmdlineP ) {
 /*----------------------------------------------------------------------------
    Parse program command line described in Unix standard form by argc
    and argv.  Return the information in the options as *cmdlineP.  
@@ -121,7 +87,7 @@ parseCommandLine(int                 argc,
    Note that the strings we return are stored in the storage that
    was passed to us as the argv array.  We also trash *argv.
 -----------------------------------------------------------------------------*/
-    optEntry *option_def = malloc(100*sizeof(optEntry));
+    optEntry * option_def;
         /* Instructions to optParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
@@ -130,6 +96,8 @@ parseCommandLine(int                 argc,
 
     unsigned int alphaSpec, mixSpec, backgroundSpec, gammaSpec, textSpec;
 
+    MALLOCARRAY(option_def, 100);
+
     option_def_index = 0;   /* incremented by OPTENT3 */
     OPTENT3(0, "verbose",     OPT_FLAG,   NULL,                  
             &cmdlineP->verbose,       0);
@@ -150,7 +118,7 @@ parseCommandLine(int                 argc,
     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, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
 
@@ -186,12 +154,215 @@ parseCommandLine(int                 argc,
 
 
 
+static void
+pngtopnmErrorHandler(png_structp     const png_ptr,
+                     png_const_charp const msg) {
+
+    jmp_buf * jmpbufP;
+
+    /* this function, aside from the extra step of retrieving the "error
+       pointer" (below) and the fact that it exists within the application
+       rather than within libpng, is essentially identical to libpng's
+       default error handler.  The second point is critical:  since both
+       setjmp() and longjmp() are called from the same code, they are
+       guaranteed to have compatible notions of how big a jmp_buf is,
+       regardless of whether _BSD_SOURCE or anything else has (or has not)
+       been defined.
+    */
+
+    pm_message("fatal libpng error: %s", msg);
+
+    jmpbufP = png_get_error_ptr(png_ptr);
+
+    if (!jmpbufP) {
+        /* we are completely hosed now */
+        pm_error("EXTREMELY fatal error: jmpbuf unrecoverable; terminating.");
+    }
+
+    longjmp(*jmpbufP, 1);
+}
+
+
+
+struct pngx {
+    png_structp png_ptr;
+    png_infop info_ptr;
+};
+
+
+
+static void
+pngx_createRead(struct pngx ** const pngxPP,
+                jmp_buf *      const jmpbufP) {
+
+    struct pngx * pngxP;
+
+    MALLOCVAR(pngxP);
+
+    if (!pngxP)
+        pm_error("Failed to allocate memory for PNG object");
+    else {
+        pngxP->png_ptr = png_create_read_struct(
+            PNG_LIBPNG_VER_STRING,
+            jmpbufP, pngtopnmErrorHandler, NULL);
+
+        if (!pngxP->png_ptr)
+            pm_error("cannot allocate main libpng structure (png_ptr)");
+        else {
+            pngxP->info_ptr = png_create_info_struct(pngxP->png_ptr);
+
+            if (!pngxP->info_ptr)
+                pm_error("cannot allocate libpng info structure (info_ptr)");
+            else
+                *pngxPP = pngxP;
+        }
+    }
+}
+
+
+
+static void
+pngx_destroy(struct pngx * const pngxP) {
+
+    png_destroy_read_struct(&pngxP->png_ptr, &pngxP->info_ptr, NULL);
+
+    free(pngxP);
+}
+
+
+
+static bool
+pngx_chunkIsPresent(struct pngx * const pngxP,
+                    uint32_t      const chunkType) {
+
+    return png_get_valid(pngxP->png_ptr, pngxP->info_ptr, chunkType);
+}
+
+
+
+static void
+verifyFileIsPng(FILE *   const ifP,
+                size_t * const consumedByteCtP) {
+
+    unsigned char buffer[4];
+    size_t bytesRead;
+
+    bytesRead = fread(buffer, 1, sizeof(buffer), ifP);
+    if (bytesRead != sizeof(buffer))
+        pm_error("input file is empty or too short");
+
+    if (png_sig_cmp(buffer, (png_size_t) 0, (png_size_t) sizeof(buffer)) != 0)
+        pm_error("input file is not a PNG file "
+                 "(does not have the PNG signature in its first 4 bytes)");
+    else
+        *consumedByteCtP = bytesRead;
+}
+
+
+
+static unsigned int
+computePngLineSize(struct pngx * const pngxP) {
+
+    unsigned int const bytesPerSample =
+        pngxP->info_ptr->bit_depth == 16 ? 2 : 1;
+
+    unsigned int samplesPerPixel;
+
+    switch (pngxP->info_ptr->color_type) {
+    case PNG_COLOR_TYPE_GRAY_ALPHA: samplesPerPixel = 2; break;
+    case PNG_COLOR_TYPE_RGB:        samplesPerPixel = 3; break;
+    case PNG_COLOR_TYPE_RGB_ALPHA:  samplesPerPixel = 4; break;
+    default:                        samplesPerPixel = 1;
+    }
+
+    if (UINT_MAX / bytesPerSample / samplesPerPixel < pngxP->info_ptr->width)
+        pm_error("Width %u of PNG is uncomputably large",
+                 (unsigned int)pngxP->info_ptr->width);
+       
+    return pngxP->info_ptr->width * bytesPerSample * samplesPerPixel;
+}
+
+
+
+static void
+allocPngRaster(struct pngx * const pngxP,
+               png_byte ***  const pngImageP) {
+
+    unsigned int const lineSize = computePngLineSize(pngxP);
+
+    png_byte ** pngImage;
+    unsigned int row;
+
+    MALLOCARRAY(pngImage, pngxP->info_ptr->height);
+
+    if (pngImage == NULL)
+        pm_error("couldn't allocate space for %u PNG raster rows",
+                 (unsigned int)pngxP->info_ptr->height);
+
+    for (row = 0; row < pngxP->info_ptr->height; ++row) {
+        MALLOCARRAY(pngImage[row], lineSize);
+        if (pngImage[row] == NULL)
+            pm_error("couldn't allocate space for %uth row of PNG raster",
+                     row);
+    }
+    *pngImageP = pngImage;
+}
+
+
+
+static void
+freePngRaster(png_byte **   const pngRaster,
+              struct pngx * const pngxP) {
+
+    unsigned int row;
+
+    for (row = 0; row < pngxP->info_ptr->height; ++row)
+        free(pngRaster[row]);
+
+    free(pngRaster);
+}
+
+
+
+static void
+readPng(struct pngx * const pngxP,
+        FILE *        const ifP,
+        png_byte ***  const pngRasterP) {
+
+    size_t sigByteCt;
+    png_byte ** pngRaster;
+            
+    verifyFileIsPng(ifP, &sigByteCt);
+
+    /* Declare that we already read the signature bytes */
+    png_set_sig_bytes(pngxP->png_ptr, (int)sigByteCt);
+
+    png_init_io(pngxP->png_ptr, ifP);
+
+    png_read_info(pngxP->png_ptr, pngxP->info_ptr);
+
+    allocPngRaster(pngxP, &pngRaster);
+
+    if (pngxP->info_ptr->bit_depth < 8)
+        png_set_packing(pngxP->png_ptr);
+
+    png_read_image(pngxP->png_ptr, pngRaster);
+
+    png_read_end(pngxP->png_ptr, pngxP->info_ptr);
+
+    /* Note that some of info_ptr is not defined until png_read_end() 
+       completes.  That's because it comes from chunks that are at the
+       end of the stream.
+    */
+
+    *pngRasterP = pngRaster;
+}
+
 
-#define get_png_val(p) _get_png_val (&(p), info_ptr->bit_depth)
 
 static png_uint_16
-_get_png_val (png_byte ** const pp,
-              int         const bit_depth) {
+get_png_val(const png_byte ** const pp,
+            int               const bit_depth) {
 
     png_uint_16 c;
     
@@ -247,121 +418,95 @@ gamma_correct(png_uint_16 const v,
               float       const g) {
 
     if (g != -1.0)
-        return (png_uint_16) (pow ((double) v / maxval, 
-                                   (1.0 / g)) * maxval + 0.5);
+        return (png_uint_16) ROUNDU(pow((double) v / maxval, (1.0 / g)) *
+                                    maxval);
     else
         return 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;
+static bool
+iscolor(png_color const c) {
+
+    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;
-
-  for (i = 0 ; i < info_ptr->num_text ; i++) {
-    j = 0;
-    while (info_ptr->text[i].key[j] != '\0' && info_ptr->text[i].key[j] != ' ')
-      j++;    
-    if (info_ptr->text[i].key[j] != ' ') {
-      fprintf (tfp, "%s", info_ptr->text[i].key);
-      for (j = strlen (info_ptr->text[i].key) ; j < 15 ; j++)
-        putc (' ', tfp);
-    } else {
-      fprintf (tfp, "\"%s\"", info_ptr->text[i].key);
-      for (j = strlen (info_ptr->text[i].key) ; j < 13 ; j++)
-        putc (' ', tfp);
-    }
-    putc (' ', tfp); /* at least one space between key and text */
+
+
+static void
+saveText(struct pngx * const pngxP,
+         FILE *        const tfP) {
+
+    png_info * const info_ptr = pngxP->info_ptr;
+
+    unsigned int i;
+
+    for (i = 0 ; i < info_ptr->num_text; ++i) {
+        unsigned int j;
+        j = 0;
+
+        while (info_ptr->text[i].key[j] != '\0' &&
+               info_ptr->text[i].key[j] != ' ')
+            ++j;    
+
+        if (info_ptr->text[i].key[j] != ' ') {
+            fprintf(tfP, "%s", info_ptr->text[i].key);
+            for (j = strlen (info_ptr->text[i].key); j < 15; ++j)
+                putc(' ', tfP);
+        } else {
+            fprintf(tfP, "\"%s\"", info_ptr->text[i].key);
+            for (j = strlen (info_ptr->text[i].key); j < 13; ++j)
+                putc(' ', tfP);
+        }
+        putc(' ', tfP); /* at least one space between key and text */
     
-    for (j = 0 ; j < info_ptr->text[i].text_length ; j++) {
-      putc (info_ptr->text[i].text[j], tfp);
-      if (info_ptr->text[i].text[j] == '\n')
-        for (k = 0 ; k < 16 ; k++)
-          putc ((int)' ', tfp);
+        for (j = 0; j < info_ptr->text[i].text_length; ++j) {
+            putc(info_ptr->text[i].text[j], tfP);
+            if (info_ptr->text[i].text[j] == '\n') {
+                unsigned int k;
+                for (k = 0; k < 16; ++k)
+                    putc(' ', tfP);
+            }
+        }
+        putc('\n', tfP);
     }
-    putc ((int)'\n', tfp);
-  }
 }
 
-#ifdef __STDC__
-static void show_time (png_info *info_ptr)
-#else
-static void show_time (info_ptr)
-png_info *info_ptr;
-#endif
-{
+
+
+static void
+showTime(struct pngx * const pngxP) {
+
     static const char * const month[] = {
         "", "January", "February", "March", "April", "May", "June",
         "July", "August", "September", "October", "November", "December"
     };
 
-  if (info_ptr->valid & PNG_INFO_tIME) {
-    if (info_ptr->mod_time.month < 1 ||
-      info_ptr->mod_time.month >= ARRAY_SIZE(month)) {
-      pm_message("tIME chunk in PNG input is invalid; "
-                 "modification time of image is unknown.  "
-                 "The month value, which should be in the range "
-                 "1-12, is %u", info_ptr->mod_time.month);
-    } else
-    pm_message ("modification time: %02d %s %d %02d:%02d:%02d",
-                info_ptr->mod_time.day, month[info_ptr->mod_time.month],
-                info_ptr->mod_time.year, info_ptr->mod_time.hour,
-                info_ptr->mod_time.minute, info_ptr->mod_time.second);
-  }
-}
-
-#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;
-
-  /* this function, aside from the extra step of retrieving the "error
-   * pointer" (below) and the fact that it exists within the application
-   * rather than within libpng, is essentially identical to libpng's
-   * default error handler.  The second point is critical:  since both
-   * setjmp() and longjmp() are called from the same code, they are
-   * guaranteed to have compatible notions of how big a jmp_buf is,
-   * regardless of whether _BSD_SOURCE or anything else has (or has not)
-   * been defined. */
-
-  pm_message("fatal libpng error: %s", msg);
-
-  jmpbuf_ptr = png_get_error_ptr(png_ptr);
-  if (jmpbuf_ptr == NULL) {
-      /* we are completely hosed now */
-      pm_error("EXTREMELY fatal error: jmpbuf unrecoverable; terminating.");
-  }
-
-  longjmp(jmpbuf_ptr->jmpbuf, 1);
+    if (pngxP->info_ptr->valid & PNG_INFO_tIME) {
+      if (pngxP->info_ptr->mod_time.month < 1 ||
+        pngxP->info_ptr->mod_time.month >= ARRAY_SIZE(month)) {
+        pm_message("tIME chunk in PNG input is invalid; "
+                   "modification time of image is unknown.  "
+                   "The month value, which should be in the range "
+                   "1-12, is %u", pngxP->info_ptr->mod_time.month);
+      } else
+        pm_message("modification time: %02d %s %d %02d:%02d:%02d",
+                   pngxP->info_ptr->mod_time.day,
+                   month[pngxP->info_ptr->mod_time.month],
+                   pngxP->info_ptr->mod_time.year,
+                   pngxP->info_ptr->mod_time.hour,
+                   pngxP->info_ptr->mod_time.minute,
+                   pngxP->info_ptr->mod_time.second);
+    }
 }
 
 
 
 static void
-dump_png_info(png_info *info_ptr) {
+dumpPngInfo(struct pngx * const pngxP) {
 
+    png_info * const info_ptr = pngxP->info_ptr;
     const char *type_string;
     const char *filter_string;
 
@@ -445,7 +590,7 @@ dump_png_info(png_info *info_ptr) {
     else
         pm_message("bKGD chunk: not present");
 
-    if (info_ptr->valid & PNG_INFO_hIST)
+    if (info_ptr->valid & PNG_INFO_PLTE)
         pm_message("hIST chunk: present");
     else
         pm_message("hIST chunk: not present");
@@ -478,29 +623,62 @@ dump_png_info(png_info *info_ptr) {
 
 
 
+static const png_color_16 *
+transColor(struct pngx * const pngxP) {
+
+    png_bytep trans;
+    int numTrans;
+    png_color_16 * transColor;
+
+    assert(pngx_chunkIsPresent(pngxP, PNG_INFO_tRNS));
+    
+    png_get_tRNS(pngxP->png_ptr, pngxP->info_ptr,
+                 &trans, &numTrans, &transColor);
+
+    return transColor;
+}
+
+
+
 static bool
-isTransparentColor(pngcolor   const color,
-                   png_info * const info_ptr,
-                   double     const totalgamma) {
+isTransparentColor(pngcolor      const color,
+                   struct pngx * const pngxP,
+                   double        const totalgamma) {
 /*----------------------------------------------------------------------------
    Return TRUE iff pixels of color 'color' are supposed to be transparent
    everywhere they occur.  Assume it's an RGB image.
+
+   'color' has been gamma-corrected.
 -----------------------------------------------------------------------------*/
     bool retval;
 
-    if (info_ptr->valid & PNG_INFO_tRNS) {
-        const png_color_16 * const transColorP = &info_ptr->trans_values;
-    
+    if (pngx_chunkIsPresent(pngxP, PNG_INFO_tRNS)) {
+        const png_color_16 * const transColorP = transColor(pngxP);
 
-        /* There seems to be a problem here: you can't compare real
-           numbers for equality.  Also, I'm not sure the gamma
-           corrected/uncorrected color spaces are right here.  
-        */
+        /* It seems odd that libpng lets you get gamma-corrected pixel
+           values, but not gamma-corrected transparency or background
+           values.  But as that is the case, we have to gamma-correct
+           the transparency values.
 
-        retval = 
-            color.r == gamma_correct(transColorP->red,   totalgamma) &&
-            color.g == gamma_correct(transColorP->green, totalgamma) &&
-            color.b == gamma_correct(transColorP->blue,  totalgamma);
+           Note that because we compare the gamma-corrected values and
+           there may be many-to-one mapping of uncorrected to corrected
+           values, more pixels may be transparent than what the user
+           intended.
+
+           We could fix this by not letting libpng gamma-correct the
+           pixels, and just do it ourselves.
+        */
+    
+        switch (pngxP->info_ptr->color_type) {
+        case PNG_COLOR_TYPE_GRAY:
+            retval = color.r == gamma_correct(transColorP->gray, totalgamma);
+            break;
+        default:
+            retval = 
+                color.r == gamma_correct(transColorP->red,   totalgamma) &&
+                color.g == gamma_correct(transColorP->green, totalgamma) &&
+                color.b == gamma_correct(transColorP->blue,  totalgamma);
+        }
     } else 
         retval = FALSE;
 
@@ -509,37 +687,17 @@ isTransparentColor(pngcolor   const color,
 
 
 
-#define SIG_CHECK_SIZE 4
-
 static void
-read_sig_buf(FILE * const ifP) {
-
-    unsigned char sig_buf[SIG_CHECK_SIZE];
-    size_t bytesRead;
-
-    bytesRead = fread(sig_buf, 1, SIG_CHECK_SIZE, ifP);
-    if (bytesRead != SIG_CHECK_SIZE)
-        pm_error ("input file is empty or too short");
-
-    if (png_sig_cmp(sig_buf, (png_size_t) 0, (png_size_t) SIG_CHECK_SIZE)
-        != 0)
-        pm_error ("input file is not a PNG file");
-}
-
-
-
-static void
-setupGammaCorrection(png_struct * const png_ptr,
-                     png_info *   const info_ptr,
-                     float        const displaygamma,
-                     float *      const totalgammaP) {
+setupGammaCorrection(struct pngx * const pngxP,
+                     float         const displaygamma,
+                     float *       const totalgammaP) {
 
     if (displaygamma == -1.0)
         *totalgammaP = -1.0;
     else {
         float imageGamma;
-        if (info_ptr->valid & PNG_INFO_gAMA)
-            imageGamma = info_ptr->gamma;
+        if (pngxP->info_ptr->valid & PNG_INFO_gAMA)
+            imageGamma = pngxP->info_ptr->gamma;
         else {
             if (verbose)
                 pm_message("PNG doesn't specify image gamma.  Assuming 1.0");
@@ -553,12 +711,12 @@ setupGammaCorrection(png_struct * const png_ptr,
                            "display gamma %4.2f.  No conversion.",
                            imageGamma, displaygamma);
         } else {
-            png_set_gamma(png_ptr, displaygamma, imageGamma);
+            png_set_gamma(pngxP->png_ptr, displaygamma, imageGamma);
             *totalgammaP = imageGamma * displaygamma;
             /* in case of gamma-corrections, sBIT's as in the
                PNG-file are not valid anymore 
             */
-            info_ptr->valid &= ~PNG_INFO_sBIT;
+            pngxP->info_ptr->valid &= ~PNG_INFO_sBIT;
             if (verbose)
                 pm_message("image gamma is %4.2f, "
                            "converted for display gamma of %4.2f",
@@ -582,8 +740,8 @@ paletteHasPartialTransparency(png_info * const info_ptr) {
             for (i = 0, foundGray = FALSE;
                  i < info_ptr->num_trans && !foundGray;
                  ++i) {
-                if (info_ptr->trans[i] != 0 &&
-                    info_ptr->trans[i] != maxval) {
+                if (info_ptr->TRANS_ALPHA[i] != 0 &&
+                    info_ptr->TRANS_ALPHA[i] != maxval) {
                     foundGray = TRUE;
                 }
             }
@@ -599,18 +757,19 @@ paletteHasPartialTransparency(png_info * const info_ptr) {
 
 
 static void
-setupSignificantBits(png_struct *        const png_ptr,
-                     png_info *          const info_ptr,
+setupSignificantBits(struct pngx *       const pngxP,
                      enum alpha_handling const alpha,
                      png_uint_16 *       const maxvalP,
-                     int *               const errorlevelP) {
+                     int *               const errorLevelP) {
 /*----------------------------------------------------------------------------
   Figure out what maxval would best express the information in the PNG
-  described by 'png_ptr' and 'info_ptr', with 'alpha' telling which
-  information in the PNG we care about (image or alpha mask).
+  described by *pngxP, with 'alpha' telling which information in the PNG we
+  care about (image or alpha mask).
 
   Return the result as *maxvalP.
 -----------------------------------------------------------------------------*/
+    png_info * const info_ptr = pngxP->info_ptr;
+
     /* Initial assumption of maxval */
     if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
         if (alpha == ALPHA_ONLY) {
@@ -654,7 +813,7 @@ setupSignificantBits(png_struct *        const png_ptr,
                 unsigned int i;
                 trans_mix = TRUE;
                 for (i = 0; i < info_ptr->num_trans; ++i)
-                    if (info_ptr->trans[i] != 0 && info_ptr->trans[i] != 255) {
+                    if (info_ptr->TRANS_ALPHA[i] != 0 && info_ptr->TRANS_ALPHA[i] != 255) {
                         trans_mix = FALSE;
                         break;
                     }
@@ -675,7 +834,7 @@ setupSignificantBits(png_struct *        const png_ptr,
                            "different bit depths for color channels");
                 pm_message("writing file with %d bit resolution",
                            info_ptr->bit_depth);
-                *errorlevelP = PNMTOPNG_WARNING_LEVEL;
+                *errorLevelP = PNMTOPNG_WARNING_LEVEL;
             } else {
                 if ((info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) &&
                     (info_ptr->sig_bit.red < 255)) {
@@ -697,7 +856,7 @@ setupSignificantBits(png_struct *        const png_ptr,
                     if ((info_ptr->color_type == PNG_COLOR_TYPE_RGB ||
                          info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&
                         (info_ptr->sig_bit.red < info_ptr->bit_depth)) {
-                        png_set_shift (png_ptr, &(info_ptr->sig_bit));
+                        png_set_shift(pngxP->png_ptr, &(info_ptr->sig_bit));
                         *maxvalP = (1l << info_ptr->sig_bit.red) - 1;
                         if (verbose)
                             pm_message("image has fewer significant bits, "
@@ -709,7 +868,7 @@ setupSignificantBits(png_struct *        const png_ptr,
                              info_ptr->color_type ==
                                  PNG_COLOR_TYPE_GRAY_ALPHA) &&
                             (info_ptr->sig_bit.gray < info_ptr->bit_depth)) {
-                            png_set_shift (png_ptr, &(info_ptr->sig_bit));
+                            png_set_shift(pngxP->png_ptr, &info_ptr->sig_bit);
                             *maxvalP = (1l << info_ptr->sig_bit.gray) - 1;
                             if (verbose)
                                 pm_message("image has fewer significant bits, "
@@ -723,7 +882,7 @@ setupSignificantBits(png_struct *        const png_ptr,
             if ((info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
                  info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) && 
                 (info_ptr->sig_bit.gray < info_ptr->bit_depth)) {
-                png_set_shift (png_ptr, &(info_ptr->sig_bit));
+                png_set_shift(pngxP->png_ptr, &info_ptr->sig_bit);
                 if (verbose)
                     pm_message ("image has fewer significant bits, "
                                 "writing file with %d bits", 
@@ -739,22 +898,22 @@ setupSignificantBits(png_struct *        const png_ptr,
 
 
 static bool
-imageHasColor(png_info * const info_ptr) {
+imageHasColor(struct pngx * const pngxP) {
 
     bool retval;
 
-    if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
-        info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+    if (pngxP->info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
+        pngxP->info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
 
         retval = FALSE;
-    else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
+    else if (pngxP->info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
         bool foundColor;
         unsigned int i;
             
         for (i = 0, foundColor = FALSE;
-             i < info_ptr->num_palette && !foundColor;
+             i < pngxP->info_ptr->num_palette && !foundColor;
              ++i) {
-            if (iscolor(info_ptr->palette[i]))
+            if (iscolor(pngxP->info_ptr->palette[i]))
                 foundColor = TRUE;
         }
         retval = foundColor;
@@ -767,14 +926,14 @@ imageHasColor(png_info * const info_ptr) {
 
 
 static void
-determineOutputType(png_info *          const info_ptr,
+determineOutputType(struct pngx *       const pngxP,
                     enum alpha_handling const alphaHandling,
                     pngcolor            const bgColor,
                     xelval              const maxval,
                     int *               const pnmTypeP) {
 
     if (alphaHandling != ALPHA_ONLY &&
-        (imageHasColor(info_ptr) || !isGrayscale(bgColor)))
+        (imageHasColor(pngxP) || !isGrayscale(bgColor)))
         *pnmTypeP = PPM_TYPE;
     else {
         if (maxval > 1)
@@ -787,11 +946,11 @@ determineOutputType(png_info *          const info_ptr,
 
 
 static void
-getBackgroundColor(png_info *        const info_ptr,
-                   const char *      const requestedColor,
-                   float             const totalgamma,
-                   xelval            const maxval,
-                   struct pngcolor * const bgColorP) {
+getBackgroundColor(struct pngx * const pngxP,
+                   const char *  const requestedColor,
+                   float         const totalgamma,
+                   xelval        const maxval,
+                   pngcolor *    const bgColorP) {
 /*----------------------------------------------------------------------------
    Figure out what the background color should be.  If the user requested
    a particular color ('requestedColor' not null), that's the one.
@@ -809,19 +968,19 @@ getBackgroundColor(png_info *        const info_ptr,
         bgColorP->g = PPM_GETG(backcolor);
         bgColorP->b = PPM_GETB(backcolor);
 
-    } else if (info_ptr->valid & PNG_INFO_bKGD) {
+    } else if (pngxP->info_ptr->valid & PNG_INFO_bKGD) {
         /* didn't manage to get libpng to work (bugs?) concerning background
            processing, therefore we do our own.
         */
-        switch (info_ptr->color_type) {
+        switch (pngxP->info_ptr->color_type) {
         case PNG_COLOR_TYPE_GRAY:
         case PNG_COLOR_TYPE_GRAY_ALPHA:
             bgColorP->r = bgColorP->g = bgColorP->b = 
-                gamma_correct(info_ptr->background.gray, totalgamma);
+                gamma_correct(pngxP->info_ptr->background.gray, totalgamma);
             break;
         case PNG_COLOR_TYPE_PALETTE: {
             png_color const rawBgcolor = 
-                info_ptr->palette[info_ptr->background.index];
+                pngxP->info_ptr->palette[pngxP->info_ptr->background.index];
             bgColorP->r = gamma_correct(rawBgcolor.red, totalgamma);
             bgColorP->g = gamma_correct(rawBgcolor.green, totalgamma);
             bgColorP->b = gamma_correct(rawBgcolor.blue, totalgamma);
@@ -829,7 +988,7 @@ getBackgroundColor(png_info *        const info_ptr,
         break;
         case PNG_COLOR_TYPE_RGB:
         case PNG_COLOR_TYPE_RGB_ALPHA: {
-            png_color_16 const rawBgcolor = info_ptr->background;
+            png_color_16 const rawBgcolor = pngxP->info_ptr->background;
             
             bgColorP->r = gamma_correct(rawBgcolor.red,   totalgamma);
             bgColorP->g = gamma_correct(rawBgcolor.green, totalgamma);
@@ -845,115 +1004,159 @@ getBackgroundColor(png_info *        const info_ptr,
 
 
 static void
+warnNonsquarePixels(struct pngx * const pngxP,
+                    int *         const errorLevelP) {
+
+    if (pngxP->info_ptr->valid & PNG_INFO_pHYs) {
+        float const r =
+            (float)pngxP->info_ptr->x_pixels_per_unit /
+            pngxP->info_ptr->y_pixels_per_unit;
+
+        if (r != 1.0) {
+            pm_message ("warning - non-square pixels; "
+                        "to fix do a 'pamscale -%cscale %g'",
+                        r < 1.0 ? 'x' : 'y',
+                        r < 1.0 ? 1.0 / r : r );
+            *errorLevelP = PNMTOPNG_WARNING_LEVEL;
+        }
+    }
+}
+
+
+
+#define GET_PNG_VAL(p) get_png_val(&(p), pngxP->info_ptr->bit_depth)
+
+
+
+static void
+makeXelRow(xel *               const xelrow,
+           xelval              const maxval,
+           int                 const pnmType,
+           struct pngx *       const pngxP,
+           const png_byte *    const pngRasterRow,
+           pngcolor            const bgColor,
+           enum alpha_handling const alphaHandling,
+           double              const totalgamma) {
+
+    const png_byte * pngPixelP;
+    unsigned int col;
+
+    pngPixelP = &pngRasterRow[0];  /* initial value */
+    for (col = 0; col < pngxP->info_ptr->width; ++col) {
+        switch (pngxP->info_ptr->color_type) {
+        case PNG_COLOR_TYPE_GRAY: {
+            pngcolor fgColor;
+            fgColor.r = fgColor.g = fgColor.b = GET_PNG_VAL(pngPixelP);
+            setXel(&xelrow[col], fgColor, bgColor, alphaHandling,
+                   isTransparentColor(fgColor, pngxP, totalgamma) ?
+                   0 : maxval);
+        }
+        break;
+
+        case PNG_COLOR_TYPE_GRAY_ALPHA: {
+            pngcolor fgColor;
+            png_uint_16 alpha;
+
+            fgColor.r = fgColor.g = fgColor.b = GET_PNG_VAL(pngPixelP);
+            alpha = GET_PNG_VAL(pngPixelP);
+            setXel(&xelrow[col], fgColor, bgColor, alphaHandling, alpha);
+        }
+        break;
+
+        case PNG_COLOR_TYPE_PALETTE: {
+            png_uint_16 const index        = GET_PNG_VAL(pngPixelP);
+            png_color   const paletteColor = pngxP->info_ptr->palette[index];
+
+            pngcolor fgColor;
+
+            fgColor.r = paletteColor.red;
+            fgColor.g = paletteColor.green;
+            fgColor.b = paletteColor.blue;
+
+            setXel(&xelrow[col], fgColor, bgColor, alphaHandling,
+                   (pngxP->info_ptr->valid & PNG_INFO_tRNS) &&
+                   index < pngxP->info_ptr->num_trans ?
+                   pngxP->info_ptr->TRANS_ALPHA[index] : maxval);
+        }
+        break;
+                
+        case PNG_COLOR_TYPE_RGB: {
+            pngcolor fgColor;
+
+            fgColor.r = GET_PNG_VAL(pngPixelP);
+            fgColor.g = GET_PNG_VAL(pngPixelP);
+            fgColor.b = GET_PNG_VAL(pngPixelP);
+            setXel(&xelrow[col], fgColor, bgColor, alphaHandling,
+                   isTransparentColor(fgColor, pngxP, totalgamma) ?
+                   0 : maxval);
+        }
+        break;
+
+        case PNG_COLOR_TYPE_RGB_ALPHA: {
+            pngcolor fgColor;
+            png_uint_16 alpha;
+
+            fgColor.r = GET_PNG_VAL(pngPixelP);
+            fgColor.g = GET_PNG_VAL(pngPixelP);
+            fgColor.b = GET_PNG_VAL(pngPixelP);
+            alpha     = GET_PNG_VAL(pngPixelP);
+            setXel(&xelrow[col], fgColor, bgColor, alphaHandling, alpha);
+        }
+        break;
+
+        default:
+            pm_error("unknown PNG color type: %d",
+                     pngxP->info_ptr->color_type);
+        }
+    }
+}
+
+
+
+static void
 writePnm(FILE *              const ofP,
          xelval              const maxval,
-         int                 const pnm_type,
-         png_info *          const info_ptr,
-         png_byte **         const png_image,
+         int                 const pnmType,
+         struct pngx *       const pngxP,
+         png_byte **         const pngRaster,
          pngcolor            const bgColor,
-         enum alpha_handling const alpha_handling,
+         enum alpha_handling const alphaHandling,
          double              const totalgamma) {
 /*----------------------------------------------------------------------------
    Write a PNM of either the image or the alpha mask, according to
-   'alpha_handling' that is in the PNG image described by 'info_ptr' and
-   png_image.
+   'alphaHandling' that is in the PNG image described by *pngxP and
+   pngRaster[][].
 
-   'pnm_type' and 'maxval' are of the output image.
+   'pnmType' and 'maxval' are of the output image.
 
    Use background color 'bgColor' in the output if the PNG is such that a
    background color is needed.
 -----------------------------------------------------------------------------*/
+    int const plainFalse = 0;
+
     xel * xelrow;
     unsigned int row;
 
     if (verbose)
-        pm_message ("writing a %s file (maxval=%u)",
-                    pnm_type == PBM_TYPE ? "PBM" :
-                    pnm_type == PGM_TYPE ? "PGM" :
-                    pnm_type == PPM_TYPE ? "PPM" :
-                    "UNKNOWN!", 
-                    maxval);
+        pm_message("writing a %s file (maxval=%u)",
+                   pnmType == PBM_TYPE ? "PBM" :
+                   pnmType == PGM_TYPE ? "PGM" :
+                   pnmType == PPM_TYPE ? "PPM" :
+                   "UNKNOWN!", 
+                   maxval);
     
-    xelrow = pnm_allocrow(info_ptr->width);
-
-    pnm_writepnminit(stdout, info_ptr->width, info_ptr->height, maxval,
-                     pnm_type, FALSE);
-
-    for (row = 0; row < info_ptr->height; ++row) {
-        png_byte * png_pixelP;
-        int col;
-
-        png_pixelP = &png_image[row][0];  /* initial value */
-        for (col = 0; col < info_ptr->width; ++col) {
-            switch (info_ptr->color_type) {
-            case PNG_COLOR_TYPE_GRAY: {
-                pngcolor fgColor;
-                fgColor.r = fgColor.g = fgColor.b = get_png_val(png_pixelP);
-                setXel(&xelrow[col], fgColor, bgColor, alpha_handling,
-                       ((info_ptr->valid & PNG_INFO_tRNS) &&
-                        (fgColor.r == 
-                         gamma_correct(info_ptr->trans_values.gray,
-                                       totalgamma))) ?
-                       0 : maxval);
-            }
-            break;
-
-            case PNG_COLOR_TYPE_GRAY_ALPHA: {
-                pngcolor fgColor;
-                png_uint_16 alpha;
-
-                fgColor.r = fgColor.g = fgColor.b = get_png_val(png_pixelP);
-                alpha = get_png_val(png_pixelP);
-                setXel(&xelrow[col], fgColor, bgColor, alpha_handling, alpha);
-            }
-            break;
+    xelrow = pnm_allocrow(pngxP->info_ptr->width);
 
-            case PNG_COLOR_TYPE_PALETTE: {
-                png_uint_16 const index        = get_png_val(png_pixelP);
-                png_color   const paletteColor = info_ptr->palette[index];
-
-                pngcolor fgColor;
-
-                fgColor.r = paletteColor.red;
-                fgColor.g = paletteColor.green;
-                fgColor.b = paletteColor.blue;
-
-                setXel(&xelrow[col], fgColor, bgColor, alpha_handling,
-                       (info_ptr->valid & PNG_INFO_tRNS) &&
-                       index < info_ptr->num_trans ?
-                       info_ptr->trans[index] : maxval);
-            }
-            break;
-                
-            case PNG_COLOR_TYPE_RGB: {
-                pngcolor fgColor;
-
-                fgColor.r = get_png_val(png_pixelP);
-                fgColor.g = get_png_val(png_pixelP);
-                fgColor.b = get_png_val(png_pixelP);
-                setXel(&xelrow[col], fgColor, bgColor, alpha_handling,
-                       isTransparentColor(fgColor, info_ptr, totalgamma) ?
-                       0 : maxval);
-            }
-            break;
+    pnm_writepnminit(stdout,
+                     pngxP->info_ptr->width, pngxP->info_ptr->height, maxval,
+                     pnmType, plainFalse);
 
-            case PNG_COLOR_TYPE_RGB_ALPHA: {
-                pngcolor fgColor;
-                png_uint_16 alpha;
+    for (row = 0; row < pngxP->info_ptr->height; ++row) {
+        makeXelRow(xelrow, maxval, pnmType, pngxP, pngRaster[row], bgColor,
+                   alphaHandling, totalgamma);
 
-                fgColor.r = get_png_val(png_pixelP);
-                fgColor.g = get_png_val(png_pixelP);
-                fgColor.b = get_png_val(png_pixelP);
-                alpha     = get_png_val(png_pixelP);
-                setXel(&xelrow[col], fgColor, bgColor, alpha_handling, alpha);
-            }
-            break;
-
-            default:
-                pm_error ("unknown PNG color type: %d", info_ptr->color_type);
-            }
-        }
-        pnm_writepnmrow(ofP, xelrow, info_ptr->width, maxval, pnm_type, FALSE);
+        pnm_writepnmrow(ofP, xelrow, pngxP->info_ptr->width, maxval,
+                        pnmType, plainFalse);
     }
     pnm_freerow (xelrow);
 }
@@ -961,154 +1164,86 @@ writePnm(FILE *              const ofP,
 
 
 static void 
-convertpng(FILE *             const ifp, 
-           FILE *             const tfp, 
+convertpng(FILE *             const ifP, 
+           FILE *             const tfP, 
            struct cmdlineInfo const cmdline,
-           int *              const errorlevelP) {
-
-    png_struct *png_ptr;
-    png_info *info_ptr;
-    png_byte **png_image;
-    int x, y;
-    int linesize;
-    int pnm_type;
+           int *              const errorLevelP) {
+
+    png_byte ** pngRaster;
+    int pnmType;
     pngcolor bgColor;
     float totalgamma;
+    jmp_buf jmpbuf;
+    struct pngx * pngxP;
 
-    *errorlevelP = 0;
-
-    read_sig_buf(ifp);
-
-    png_ptr = png_create_read_struct(
-        PNG_LIBPNG_VER_STRING,
-        &pngtopnm_jmpbuf_struct, pngtopnm_error_handler, NULL);
-    if (png_ptr == NULL)
-        pm_error("cannot allocate main libpng structure (png_ptr)");
-
-    info_ptr = png_create_info_struct (png_ptr);
-    if (info_ptr == NULL)
-        pm_error("cannot allocate LIBPNG structures");
+    *errorLevelP = 0;
 
-    if (setjmp(pngtopnm_jmpbuf_struct.jmpbuf))
+    if (setjmp(jmpbuf))
         pm_error ("setjmp returns error condition");
 
-    png_init_io (png_ptr, ifp);
-    png_set_sig_bytes (png_ptr, SIG_CHECK_SIZE);
-    png_read_info (png_ptr, info_ptr);
+    pngx_createRead(&pngxP, &jmpbuf);
 
-    MALLOCARRAY(png_image, info_ptr->height);
-    if (png_image == NULL) {
-        png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL);
-        pm_closer (ifp);
-        pm_error ("couldn't allocate space for image");
-    }
+    readPng(pngxP, ifP, &pngRaster);
 
-    if (info_ptr->bit_depth == 16)
-        linesize = 2 * info_ptr->width;
-    else
-        linesize = info_ptr->width;
+    if (verbose)
+        dumpPngInfo(pngxP);
 
-    if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
-        linesize *= 2;
-    else
-        if (info_ptr->color_type == PNG_COLOR_TYPE_RGB)
-            linesize *= 3;
-        else
-            if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
-                linesize *= 4;
-
-    for (y = 0 ; y < info_ptr->height ; y++) {
-        png_image[y] = malloc (linesize);
-        if (png_image[y] == NULL) {
-            for (x = 0 ; x < y ; x++)
-                free (png_image[x]);
-            free (png_image);
-            png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL);
-            pm_closer (ifp);
-            pm_error ("couldn't allocate space for image");
-        }
-    }
+    if (cmdline.time)
+        showTime(pngxP);
+    if (tfP)
+        saveText(pngxP, tfP);
 
-    if (info_ptr->bit_depth < 8)
-        png_set_packing (png_ptr);
+    warnNonsquarePixels(pngxP, errorLevelP);
 
-    setupGammaCorrection(png_ptr, info_ptr, cmdline.gamma, &totalgamma);
+    setupGammaCorrection(pngxP, cmdline.gamma, &totalgamma);
 
-    setupSignificantBits(png_ptr, info_ptr, cmdline.alpha,
-                         &maxval, errorlevelP);
+    setupSignificantBits(pngxP, cmdline.alpha, &maxval, errorLevelP);
 
-    getBackgroundColor(info_ptr, cmdline.background, totalgamma, maxval,
+    getBackgroundColor(pngxP, cmdline.background, totalgamma, maxval,
                        &bgColor);
 
-    png_read_image (png_ptr, png_image);
-    png_read_end (png_ptr, info_ptr);
+    determineOutputType(pngxP, cmdline.alpha, bgColor, maxval, &pnmType);
 
-    if (verbose)
-        /* Note that some of info_ptr is not defined until png_read_end() 
-       completes.  That's because it comes from chunks that are at the
-       end of the stream.
-    */
-        dump_png_info(info_ptr);
-
-    if (mtime)
-        show_time (info_ptr);
-    if (tfp)
-        save_text (info_ptr, tfp);
-
-    if (info_ptr->valid & PNG_INFO_pHYs) {
-        float r;
-        r = (float)info_ptr->x_pixels_per_unit / info_ptr->y_pixels_per_unit;
-        if (r != 1.0) {
-            pm_message ("warning - non-square pixels; "
-                        "to fix do a 'pamscale -%cscale %g'",
-                        r < 1.0 ? 'x' : 'y',
-                        r < 1.0 ? 1.0 / r : r );
-            *errorlevelP = PNMTOPNG_WARNING_LEVEL;
-        }
-    }
-
-    determineOutputType(info_ptr, cmdline.alpha, bgColor, maxval, &pnm_type);
-
-    writePnm(stdout, maxval, pnm_type, info_ptr, png_image, bgColor, 
+    writePnm(stdout, maxval, pnmType, pngxP, pngRaster, bgColor, 
              cmdline.alpha, totalgamma);
 
     fflush(stdout);
-    for (y = 0 ; y < info_ptr->height ; y++)
-        free (png_image[y]);
-    free (png_image);
-    png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL);
+
+    freePngRaster(pngRaster, pngxP);
+
+    pngx_destroy(pngxP);
 }
 
 
 
 int 
-main(int argc, char *argv[]) {
+main(int argc, const char *argv[]) {
 
     struct cmdlineInfo cmdline;
-    FILE *ifp, *tfp;
-    int errorlevel;
+    FILE * ifP;
+    FILE * tfP;
+    int errorLevel;
 
-    pnm_init (&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
     verbose = cmdline.verbose;
-    mtime = cmdline.time;
 
-    ifp = pm_openr(cmdline.inputFilespec);
+    ifP = pm_openr(cmdline.inputFilespec);
 
     if (cmdline.text)
-        tfp = pm_openw(cmdline.text);
+        tfP = pm_openw(cmdline.text);
     else
-        tfp = NULL;
+        tfP = NULL;
 
-    convertpng (ifp, tfp, cmdline, &errorlevel);
+    convertpng(ifP, tfP, cmdline, &errorLevel);
 
-    if (tfp)
-        pm_close(tfp);
+    if (tfP)
+        pm_close(tfP);
 
-    pm_close(ifp);
+    pm_close(ifP);
     pm_close(stdout);
 
-    return errorlevel;
+    return errorLevel;
 }
diff --git a/converter/other/pnmtoddif.c b/converter/other/pnmtoddif.c
index 962487f2..ae8c8524 100644
--- a/converter/other/pnmtoddif.c
+++ b/converter/other/pnmtoddif.c
@@ -1,14 +1,4 @@
 /*
- * $Log: pnmtoddif.c,v $
- * Revision 1.6  1993/01/25  08:14:06  neideck
- * Placed into public use form.
- *
- * Revision 1.5  1992/12/02  08:15:18  neideck
- *  Added RCS id.
- *
- */
-
-/*
  * Author:      Burkhard Neidecker-Lutz
  *              Digital CEC Karlsruhe
  *      neideck@nestvx.enet.dec.com 
@@ -31,6 +21,8 @@
 */
 
 #include <string.h>
+
+#include "mallocvar.h"
 #include "pnm.h"
 
 /* The structure we use to convey all sorts of "magic" data to the DDIF */
@@ -166,11 +158,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;
@@ -418,21 +406,181 @@ write_trailer(FILE * file)
 
 
 
-int main(int argc, char *argv[])
-{
+
+static void
+convertPbmRaster(FILE *          const ifP,
+                 int             const format,
+                 unsigned int    const cols,
+                 unsigned int    const rows,
+                 FILE *          const ofP,
+                 unsigned int    const bytesPerLine,
+                 unsigned char * const data) {
+                 
+    bit * const pixels = pbm_allocrow(cols);
+
+    unsigned int row;
+
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+        unsigned int k;
+        unsigned int mask;
+        unsigned char * p;
+        size_t bytesWritten;
+
+        pbm_readpbmrow(ifP, pixels, cols, format);
+
+        mask = 0x00;
+        p = &data[0];
+        for (col = 0, k = 0; col < cols; ++col) {
+            if (pixels[col] == PBM_BLACK)
+                mask |= 1 << k;
+            if (k == 7) {
+                *p++ = mask;
+                mask = 0x00;
+                k = 0;
+            } else
+                ++k;
+        }
+        if (k != 7)
+            /* Flush the rest of the column */
+            *p = mask;
+
+        bytesWritten =  fwrite(data, 1, bytesPerLine, ofP);
+        if (bytesWritten != bytesPerLine)
+            pm_error("File write error on Row %u", row);
+    }
+
+    pbm_freerow(pixels);
+}
+
+
+
+static void
+convertPgmRaster(FILE *          const ifP,
+                 int             const format,
+                 xelval          const maxval,
+                 unsigned int    const cols,
+                 unsigned int    const rows,
+                 FILE *          const ofP,
+                 unsigned int    const bytesPerLine,
+                 unsigned char * const data) {
+
+    gray * const pixels = pgm_allocrow(cols);
+
+    unsigned int row;
+
+    for (row = 0; row < rows; ++row) {
+        unsigned char * p;
+        unsigned int col;
+        size_t bytesWritten;
+
+        p = &data[0];
+
+        pgm_readpgmrow(ifP, pixels, cols, maxval, format);
+
+        for (col = 0; col < cols; ++col)
+            *p++ = (unsigned char) pixels[col];
+
+        bytesWritten = fwrite(data, 1, bytesPerLine, ofP);
+        if (bytesWritten != bytesPerLine)
+            pm_error("File write error on Row %u", row);
+    }
+    pgm_freerow(pixels);
+}
+
+
+
+
+static void
+convertPpmRaster(FILE *          const ifP,
+                 int             const format,
+                 xelval          const maxval,
+                 unsigned int    const cols,
+                 unsigned int    const rows,
+                 FILE *          const ofP,
+                 unsigned int    const bytesPerLine,
+                 unsigned char * const data) {
+
+    pixel * const pixels = ppm_allocrow(cols);
+
+    unsigned int row;
+
+    for (row = 0; row < rows; ++row) {
+        unsigned char * p;
+        unsigned int col;
+        size_t bytesWritten;
+
+        p = &data[0];
+
+        ppm_readppmrow(ifP, pixels, cols, maxval, format);
+
+        for (col = 0; col < cols; ++col) {
+            *p++ = PPM_GETR(pixels[col]);
+            *p++ = PPM_GETG(pixels[col]);
+            *p++ = PPM_GETB(pixels[col]);
+        }
+        bytesWritten =  fwrite(data, 1, bytesPerLine, ofP);
+        if (bytesWritten != bytesPerLine)
+            pm_error("File write error on Row %u", row);
+    }
+    ppm_freerow(pixels);
+}
+
+
+
+static void
+convertRaster(FILE *       const ifP,
+              int          const format,
+              xelval       const maxval,
+              unsigned int const cols,
+              unsigned int const rows,
+              FILE *       const ofP,
+              unsigned int const bytesPerLine) {
+
+    unsigned char * data;
+    unsigned char * p;
+
+    MALLOCARRAY(data, bytesPerLine);
+
+    if (data == NULL)
+        pm_error("Couldn't allocate %u-byte line buffer", bytesPerLine);
+
+    p = data;  /* initial value */
+
+    switch (PNM_FORMAT_TYPE(format)) {
+    case PBM_TYPE:
+        convertPbmRaster(ifP, format, cols, rows, ofP, bytesPerLine, data);
+        break;
+    case PGM_TYPE:
+        convertPgmRaster(ifP, format, maxval, cols, rows, ofP, bytesPerLine,
+                         data);
+        break;
+    case PPM_TYPE:
+        convertPpmRaster(ifP, format, maxval, cols, rows, ofP, bytesPerLine,
+                         data);
+        break;
+    default:
+        pm_error("INTERNAL ERROR: impossible format value");
+    }
+
+    free(data);
+}
+
+
+
+int
+main(int argc, char *argv[]) {
     FILE           *ifd;
-    FILE       *ofd;
+    FILE           *ofd;
     int             rows, cols;
     xelval          maxval;
     int             format;
     const char     * const usage = "[-resolution x y] [pnmfile [ddiffile]]";
-    int             i, j;
     char           *outfile;
     int       argn;
     int hor_resolution = 75;
     int ver_resolution = 75;
     imageparams ip;
-    unsigned char  *data, *p;
 
     pnm_init(&argc, argv);
 
@@ -516,90 +664,10 @@ int main(int argc, char *argv[])
         exit(1);
     }
 
-    if (!(p = data = (unsigned char*)  malloc(ip.bytes_per_line))) {
-        perror("allocating line buffer");
-        exit(1);
-    }
-
-    switch (PNM_FORMAT_TYPE(format)) {
-    case PBM_TYPE:
-    {
-        bit            *pixels;
-        int             mask;
-        int             k;
-
-        pixels = pbm_allocrow(cols);
-
-        for (i = 0; i < rows; i++) {
-            pbm_readpbmrow(ifd, pixels, cols, format);
-            mask = 0;
-            p = data;
-            for (j = 0, k = 0; j < cols; j++) {
-                if (pixels[j] == PBM_BLACK) {
-                    mask |= 1 << k;
-                }
-                if (k == 7) {
-                    *p++ = mask;
-                    mask = 0;
-                    k = 0;
-                } else {
-                    k++;
-                }
-            }
-            if (k != 7) {       /* Flush the rest of the column */
-                *p = mask;
-            }
-            if (fwrite(data,1,ip.bytes_per_line,ofd) != ip.bytes_per_line) {
-                perror("Writing image data\n");
-                exit(1);
-            }
-        }
-    }
-    break;
-    case PGM_TYPE:
-    {
-        gray          *pixels = pgm_allocrow(cols);
-
-        for (i = 0; i < rows; i++) {
-            p = data;
-            pgm_readpgmrow(ifd, pixels, cols, maxval, format);
-            for (j = 0; j < cols; j++) {
-                *p++ = (unsigned char) pixels[j];
-            }
-            if (fwrite(data,1,ip.bytes_per_line,ofd) != ip.bytes_per_line) {
-                perror("Writing image data\n");
-                exit(1);
-            }
-        }
-        pgm_freerow(pixels);
-    }
-    break;
-    case PPM_TYPE:
-    {
-        pixel          *pixels = ppm_allocrow(cols);
-
-        for (i = 0; i < rows; i++) {
-            p = data;
-            ppm_readppmrow(ifd, pixels, cols, maxval, format);
-            for (j = 0; j < cols; j++) {
-                *p++ = PPM_GETR(pixels[j]);
-                *p++ = PPM_GETG(pixels[j]);
-                *p++ = PPM_GETB(pixels[j]);
-            }
-            if (fwrite(data,1,ip.bytes_per_line,ofd) != ip.bytes_per_line) {
-                perror("Writing image data\n");
-                exit(1);
-            }
-        }
-        ppm_freerow(pixels);
-    }
-    break;
-    }
+    convertRaster(ifd, format, maxval, cols, rows, ofd, ip.bytes_per_line);
 
     pm_close(ifd);
 
-    free(data);
-
     if (!write_trailer(ofd)) {
         perror("Writing trailer");
         exit(1);
diff --git a/converter/other/pnmtojpeg.c b/converter/other/pnmtojpeg.c
index 9a247633..198aa156 100644
--- a/converter/other/pnmtojpeg.c
+++ b/converter/other/pnmtojpeg.c
@@ -29,6 +29,8 @@
    itself, but doesn't.
 */
 #include <jpeglib.h>
+
+#include "pm_c_util.h"
 #include "pnm.h"
 #include "shhopt.h"
 #include "mallocvar.h"
@@ -330,23 +332,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 +408,370 @@ 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
+readTextInteger(FILE * const fileP,
+                long * const resultP,
+                int *  const termcharP) {
+/*----------------------------------------------------------------------------
+   Read the next unsigned decimal integer from file 'fileP', skipping
+   white space as necessary.  Return it as *resultP.
+
+   Also read one character after the integer and return it as *termcharP.
+
+   If there is no character after the integer, return *termcharP == EOF.
+
+   Iff the next thing in the file is not a valid unsigned decimal integer,
+   return FALSE.
+-----------------------------------------------------------------------------*/
+    int ch;
+    boolean retval;
+  
+    /* Skip any leading whitespace, detect EOF */
+    do {
+        ch = text_getc(fileP);
+    } while (isspace(ch));
+  
+    if (!isdigit(ch))
+        retval = FALSE;
+    else {
+        long val;
+        val = ch - '0';  /* initial value */
+        while ((ch = text_getc(fileP)) != EOF) {
+            if (! isdigit(ch))
+                break;
+            val *= 10;
+            val += ch - '0';
+        }
+        *resultP = val;
+        retval = TRUE;
+    }
+    *termcharP = ch;
+    return retval;
+}
+
+
+static boolean
+read_scan_integer (FILE * file, long * result, int * termchar)
+/* Variant of readTextInteger that always looks for a non-space termchar;
+ * this simplifies parsing of punctuation in scan scripts.
+ */
+{
+    register int ch;
+
+    if (! readTextInteger(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;
+    boolean retval;
+
+    fp = fopen(filename, "rb");
+    if (fp == NULL) {
+        pm_message("Can't open table file %s", filename);
+        retval = FALSE;
+    } else {
+        boolean eof, error;
+        unsigned int tblno;
+
+        for (tblno = 0, eof = FALSE, error = FALSE; !eof && !error; ++tblno) {
+            long val;
+            int termchar;
+            boolean gotOne;
+
+            gotOne = readTextInteger(fp, &val, &termchar);
+            if (gotOne) {
+                /* read 1st element of table */
+                if (tblno >= NUM_QUANT_TBLS) {
+                    pm_message("Too many tables in file %s", filename);
+                    error = TRUE;
+                } else { 
+                    unsigned int table[DCTSIZE2];
+                    unsigned int i;
+
+                    table[0] = (unsigned int) val;
+                    for (i = 1; i < DCTSIZE2 && !error; ++i) {
+                        if (! readTextInteger(fp, &val, &termchar)) {
+                            pm_message("Invalid table data in file %s",
+                                       filename);
+                            error = TRUE;
+                        } else
+                            table[i] = (unsigned int) val;
+                    }
+                    if (!error)
+                        jpeg_add_quant_table(
+                            cinfo, tblno, table, scale_factor, force_baseline);
+                }
+            } else {
+                if (termchar == EOF)
+                    eof = TRUE;
+                else {
+                    pm_message("Non-numeric data in file %s", filename);
+                    error = TRUE;
+                }
+            }
+        }
+
+        fclose(fp);
+        retval = !error;
+    }
+        
+    return retval;
+}
+
+
+
+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,
@@ -686,354 +1035,21 @@ convert_scanlines(struct jpeg_compress_struct * const cinfo_p,
   }
 
   pnm_freerow(pnm_buffer);
-  /* Dont' worry about the compressor input buffer; it gets freed 
+  /* Don't worry about the compressor input buffer; it gets freed 
      automatically
   */
-
-}
-
-/*----------------------------------------------------------------------------
-   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 */
@@ -1089,7 +1105,7 @@ main(int argc, char ** argv) {
 
     /* Close files, if we opened them */
     if (input_file != stdin)
-        fclose(input_file);
+        pm_close(input_file);
 
     /* Program may have exited with non-zero completion code via
        various function calls above. 
diff --git a/converter/other/pnmtopalm/Makefile b/converter/other/pnmtopalm/Makefile
index 4a8fa02a..7f99f95a 100644
--- a/converter/other/pnmtopalm/Makefile
+++ b/converter/other/pnmtopalm/Makefile
@@ -5,7 +5,7 @@ endif
 SUBDIR = converter/other/pnmtopalm
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
 BINARIES = palmtopnm pnmtopalm
 SCRIPTS =
@@ -16,7 +16,7 @@ DATAFILES = palmcolor8.map palmgray1.map palmgray2.map palmgray4.map
 
 all: $(BINARIES)
 
-include $(SRCDIR)/Makefile.common
+include $(SRCDIR)/common.mk
 
 LIBOPTS = $(shell $(LIBOPT) $(NETPBMLIB))
 
@@ -24,8 +24,9 @@ $(BINARIES): %: %.o palmcolormap.o $(NETPBMLIB) $(LIBOPT)
 	$(LD) -o $@ $< palmcolormap.o $(LIBOPTS) \
 	  $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
 
-gen_palm_colormap : $(SUBDIR)/gen_palm_colormap.c palmcolormap.o
-	$(CC) $(INCLUDES) $(CFLAGS) -o $@ $< palmcolormap.o \
+gen_palm_colormap : % : %.c palmcolormap.o
+	$(CC) -I importinc $(CPPFLAGS) $(CFLAGS) -o $@ \
+	  $< palmcolormap.o \
 	  $(LIBOPTS) $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(LADD)
 
 
diff --git a/converter/other/pnmtopalm/gen_palm_colormap.c b/converter/other/pnmtopalm/gen_palm_colormap.c
index 4b65e631..c7172c6b 100644
--- a/converter/other/pnmtopalm/gen_palm_colormap.c
+++ b/converter/other/pnmtopalm/gen_palm_colormap.c
@@ -1,24 +1,46 @@
 /* gen_palm_colormap.c - generate a ppm file containing the default Palm colormap
  *
- * Bill Janssen  <bill@janssen.org>
+ * Based on an earlier version by Bill Janssen  <bill@janssen.org>
  */
 
-#include "pnm.h"
+#include "ppm.h"
+#include "pm_c_util.h"
 
 #include "palm.h"
 
-int main( int argc, char **argv ) {
+int
+main(int     argc,
+     char ** argv) {
 
-  int i;
-  Color_s current;
-  Colormap default_map = palmcolor_build_default_8bit_colormap ();
+    Colormap defaultMap;
+    unsigned int i;
+    pixel pix;
+    
+    defaultMap = palmcolor_build_default_8bit_colormap();
+    qsort (defaultMap->color_entries, defaultMap->ncolors,
+           sizeof(Color_s), palmcolor_compare_indices);
 
-  printf("P3\n%d 1\n255\n", default_map->ncolors);
-  for (i = 0;  i < default_map->ncolors;  i++) {
-    current = default_map->color_entries[i];
-    printf ("%d %d %d\n", (current & 0xFF0000) >> 16, (current & 0xFF00) >> 8, (current & 0xFF));
-    /* printf ("%x:  %d %d %d\n", (current & 0xFF000000) >> 24, (current & 0xFF0000) >> 16, (current & 0xFF00) >> 8, (current & 0xFF)); */
-  };
-  return 0;
+    ppm_writeppminit(stdout, 256, 1, 255, TRUE);
+
+    for (i = 0; i < defaultMap->ncolors; ++i) {
+        Color_s const current = defaultMap->color_entries[i];
+
+        PPM_ASSIGN(pix,
+                   (current >> 16) & 0xff,
+                   (current >>  8) & 0xff,
+                   (current >>  0) & 0xff);
+
+        ppm_writeppmrow(stdout, &pix, 1, 255, TRUE);
+    }
+
+    /* palmcolor_build_default_8bit_colormap() builds a map of the 231 default
+     * palm colors and 1 extra black pixel. Add another 24 extra black pixels
+     * as per spec. */
+    PPM_ASSIGN(pix, 0, 0, 0);
+    for (i = 0; i < 256 - defaultMap->ncolors; ++i) {
+        ppm_writeppmrow(stdout, &pix, 1, 255, TRUE);
+    }
+
+    return 0;
 }
 
diff --git a/converter/other/pnmtopalm/palmcolor8.map b/converter/other/pnmtopalm/palmcolor8.map
index 2e054616..a4840118 100644
--- a/converter/other/pnmtopalm/palmcolor8.map
+++ b/converter/other/pnmtopalm/palmcolor8.map
@@ -1,235 +1,259 @@
 P3
-232 1
+256 1
 255
-0 0 0
-0 0 0
-0 0 51
-0 0 102
-0 0 153
-0 0 204
+255 255 255
+255 204 255
+255 153 255
+255 102 255
+255 51 255
+255 0 255
+255 255 204
+255 204 204
+255 153 204
+255 102 204
+255 51 204
+255 0 204
+255 255 153
+255 204 153
+255 153 153
+255 102 153
+255 51 153
+255 0 153
+204 255 255
+204 204 255
+204 153 255
+204 102 255
+204 51 255
+204 0 255
+204 255 204
+204 204 204
+204 153 204
+204 102 204
+204 51 204
+204 0 204
+204 255 153
+204 204 153
+204 153 153
+204 102 153
+204 51 153
+204 0 153
+153 255 255
+153 204 255
+153 153 255
+153 102 255
+153 51 255
+153 0 255
+153 255 204
+153 204 204
+153 153 204
+153 102 204
+153 51 204
+153 0 204
+153 255 153
+153 204 153
+153 153 153
+153 102 153
+153 51 153
+153 0 153
+102 255 255
+102 204 255
+102 153 255
+102 102 255
+102 51 255
+102 0 255
+102 255 204
+102 204 204
+102 153 204
+102 102 204
+102 51 204
+102 0 204
+102 255 153
+102 204 153
+102 153 153
+102 102 153
+102 51 153
+102 0 153
+51 255 255
+51 204 255
+51 153 255
+51 102 255
+51 51 255
+51 0 255
+51 255 204
+51 204 204
+51 153 204
+51 102 204
+51 51 204
+51 0 204
+51 255 153
+51 204 153
+51 153 153
+51 102 153
+51 51 153
+51 0 153
+0 255 255
+0 204 255
+0 153 255
+0 102 255
+0 51 255
 0 0 255
-0 51 0
-0 51 51
-0 51 102
-0 51 153
+0 255 204
+0 204 204
+0 153 204
+0 102 204
 0 51 204
-0 51 255
-0 102 0
-0 102 51
-0 102 102
+0 0 204
+0 255 153
+0 204 153
+0 153 153
 0 102 153
-0 102 204
-0 102 255
-0 128 0
-0 128 128
-0 153 0
-0 153 51
+0 51 153
+0 0 153
+255 255 102
+255 204 102
+255 153 102
+255 102 102
+255 51 102
+255 0 102
+255 255 51
+255 204 51
+255 153 51
+255 102 51
+255 51 51
+255 0 51
+255 255 0
+255 204 0
+255 153 0
+255 102 0
+255 51 0
+255 0 0
+204 255 102
+204 204 102
+204 153 102
+204 102 102
+204 51 102
+204 0 102
+204 255 51
+204 204 51
+204 153 51
+204 102 51
+204 51 51
+204 0 51
+204 255 0
+204 204 0
+204 153 0
+204 102 0
+204 51 0
+204 0 0
+153 255 102
+153 204 102
+153 153 102
+153 102 102
+153 51 102
+153 0 102
+153 255 51
+153 204 51
+153 153 51
+153 102 51
+153 51 51
+153 0 51
+153 255 0
+153 204 0
+153 153 0
+153 102 0
+153 51 0
+153 0 0
+102 255 102
+102 204 102
+102 153 102
+102 102 102
+102 51 102
+102 0 102
+102 255 51
+102 204 51
+102 153 51
+102 102 51
+102 51 51
+102 0 51
+102 255 0
+102 204 0
+102 153 0
+102 102 0
+102 51 0
+102 0 0
+51 255 102
+51 204 102
+51 153 102
+51 102 102
+51 51 102
+51 0 102
+51 255 51
+51 204 51
+51 153 51
+51 102 51
+51 51 51
+51 0 51
+51 255 0
+51 204 0
+51 153 0
+51 102 0
+51 51 0
+51 0 0
+0 255 102
+0 204 102
 0 153 102
-0 153 153
-0 153 204
-0 153 255
-0 204 0
+0 102 102
+0 51 102
+0 0 102
+0 255 51
 0 204 51
-0 204 102
-0 204 153
-0 204 204
-0 204 255
+0 153 51
+0 102 51
+0 51 51
+0 0 51
 0 255 0
-0 255 51
-0 255 102
-0 255 153
-0 255 204
-0 255 255
+0 204 0
+0 153 0
+0 102 0
+0 51 0
 17 17 17
 34 34 34
-51 0 0
-51 0 51
-51 0 102
-51 0 153
-51 0 204
-51 0 255
-51 51 0
-51 51 51
-51 51 102
-51 51 153
-51 51 204
-51 51 255
-51 102 0
-51 102 51
-51 102 102
-51 102 153
-51 102 204
-51 102 255
-51 153 0
-51 153 51
-51 153 102
-51 153 153
-51 153 204
-51 153 255
-51 204 0
-51 204 51
-51 204 102
-51 204 153
-51 204 204
-51 204 255
-51 255 0
-51 255 51
-51 255 102
-51 255 153
-51 255 204
-51 255 255
 68 68 68
 85 85 85
-102 0 0
-102 0 51
-102 0 102
-102 0 153
-102 0 204
-102 0 255
-102 51 0
-102 51 51
-102 51 102
-102 51 153
-102 51 204
-102 51 255
-102 102 0
-102 102 51
-102 102 102
-102 102 153
-102 102 204
-102 102 255
-102 153 0
-102 153 51
-102 153 102
-102 153 153
-102 153 204
-102 153 255
-102 204 0
-102 204 51
-102 204 102
-102 204 153
-102 204 204
-102 204 255
-102 255 0
-102 255 51
-102 255 102
-102 255 153
-102 255 204
-102 255 255
 119 119 119
-128 0 0
-128 0 128
 136 136 136
-153 0 0
-153 0 51
-153 0 102
-153 0 153
-153 0 204
-153 0 255
-153 51 0
-153 51 51
-153 51 102
-153 51 153
-153 51 204
-153 51 255
-153 102 0
-153 102 51
-153 102 102
-153 102 153
-153 102 204
-153 102 255
-153 153 0
-153 153 51
-153 153 102
-153 153 153
-153 153 204
-153 153 255
-153 204 0
-153 204 51
-153 204 102
-153 204 153
-153 204 204
-153 204 255
-153 255 0
-153 255 51
-153 255 102
-153 255 153
-153 255 204
-153 255 255
 170 170 170
 187 187 187
-192 192 192
-204 0 0
-204 0 51
-204 0 102
-204 0 153
-204 0 204
-204 0 255
-204 51 0
-204 51 51
-204 51 102
-204 51 153
-204 51 204
-204 51 255
-204 102 0
-204 102 51
-204 102 102
-204 102 153
-204 102 204
-204 102 255
-204 153 0
-204 153 51
-204 153 102
-204 153 153
-204 153 204
-204 153 255
-204 204 0
-204 204 51
-204 204 102
-204 204 153
-204 204 204
-204 204 255
-204 255 0
-204 255 51
-204 255 102
-204 255 153
-204 255 204
-204 255 255
 221 221 221
 238 238 238
-255 0 0
-255 0 51
-255 0 102
-255 0 153
-255 0 204
-255 0 255
-255 51 0
-255 51 51
-255 51 102
-255 51 153
-255 51 204
-255 51 255
-255 102 0
-255 102 51
-255 102 102
-255 102 153
-255 102 204
-255 102 255
-255 153 0
-255 153 51
-255 153 102
-255 153 153
-255 153 204
-255 153 255
-255 204 0
-255 204 51
-255 204 102
-255 204 153
-255 204 204
-255 204 255
-255 255 0
-255 255 51
-255 255 102
-255 255 153
-255 255 204
-255 255 255
+192 192 192
+128 0 0
+128 0 128
+0 128 0
+0 128 128
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
diff --git a/converter/other/pnmtopalm/palmtopnm.c b/converter/other/pnmtopalm/palmtopnm.c
index ee43be7a..88088817 100644
--- a/converter/other/pnmtopalm/palmtopnm.c
+++ b/converter/other/pnmtopalm/palmtopnm.c
@@ -15,6 +15,7 @@
 #include <string.h>
 #include <assert.h>
 
+#include "pm_c_util.h"
 #include "pnm.h"
 #include "shhopt.h"
 #include "mallocvar.h"
diff --git a/converter/other/pnmtopalm/pnmtopalm.c b/converter/other/pnmtopalm/pnmtopalm.c
index d5f79619..90737b78 100644
--- a/converter/other/pnmtopalm/pnmtopalm.c
+++ b/converter/other/pnmtopalm/pnmtopalm.c
@@ -21,6 +21,7 @@
 #include <assert.h>
 #include <limits.h>
 
+#include "pm_c_util.h"
 #include "pnm.h"
 #include "palm.h"
 #include "shhopt.h"
diff --git a/converter/other/pnmtopclxl.c b/converter/other/pnmtopclxl.c
index 23c7bd3a..e16afb14 100644
--- a/converter/other/pnmtopclxl.c
+++ b/converter/other/pnmtopclxl.c
@@ -29,6 +29,7 @@
 #include <sys/types.h>
 #include <ctype.h>
 
+#include "pm_c_util.h"
 #include "pam.h"
 #include "shhopt.h"
 #include "mallocvar.h"
@@ -153,7 +154,7 @@ parseCommandLine(int argc, char ** argv,
         bool found;
         int i;
         for (i = 0, found=FALSE; xlPaperFormats[i].name && !found; ++i) {
-            if (STREQ(xlPaperFormats[i].name, formatOpt)) {
+            if (streq(xlPaperFormats[i].name, formatOpt)) {
                 found = TRUE;
                 cmdlineP->format = xlPaperFormats[i].xl_nr;
             }
@@ -178,7 +179,7 @@ parseCommandLine(int argc, char ** argv,
         cmdlineP->sourceP->name = "-";
         cmdlineP->sourceP->next = NULL;
     } else {
-        int i;
+        unsigned int i;
         InputSource ** nextLinkP;
 
         nextLinkP = &cmdlineP->sourceP;
diff --git a/converter/other/pnmtopng.c b/converter/other/pnmtopng.c
index 92c38a2a..52f69423 100644
--- a/converter/other/pnmtopng.c
+++ b/converter/other/pnmtopng.c
@@ -52,8 +52,6 @@
    because xels were only 24 bits.  Now they're 96.
 */
    
-#define GRR_GRAY_PALETTE_FIX
-
 #ifndef PNMTOPNG_WARNING_LEVEL
 #  define PNMTOPNG_WARNING_LEVEL 0   /* use 0 for backward compatibility, */
 #endif                               /*  2 for warnings (1 == error) */
@@ -62,6 +60,8 @@
 #include <string.h> /* strcat() */
 #include <limits.h>
 #include <png.h>    /* includes zlib.h and setjmp.h */
+
+#include "pm_c_util.h"
 #include "pnm.h"
 #include "pngtxt.h"
 #include "shhopt.h"
@@ -69,10 +69,12 @@
 #include "nstring.h"
 #include "version.h"
 
+/* A hack until we can remove direct access to png_info from the program */
 #if PNG_LIBPNG_VER >= 10400
-#error Your PNG library (<png.h>) is incompatible with this Netpbm source code.
-#error You need either an older PNG library (older than 1.4)
-#error newer Netpbm source code (at least 10.47.04)
+#define trans_values trans_color
+#define TRANS_ALPHA trans_alpha
+#else
+#define TRANS_ALPHA trans
 #endif
 
 
@@ -390,7 +392,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. */
 
 
@@ -471,7 +473,7 @@ parseCommandLine(int argc, char ** argv,
     }
 
     if (cmdlineP->zlibCompression.methodSpec) {
-        if (STREQ(compMethod, "deflated"))
+        if (streq(compMethod, "deflated"))
             cmdlineP->zlibCompression.method = Z_DEFLATED;
         else
             pm_error("The only valid value for -method is 'deflated'.  "
@@ -479,9 +481,9 @@ parseCommandLine(int argc, char ** argv,
     }
 
     if (cmdlineP->zlibCompression.strategySpec) {
-        if (STREQ(compStrategy, "huffman_only"))
+        if (streq(compStrategy, "huffman_only"))
             cmdlineP->zlibCompression.strategy = Z_HUFFMAN_ONLY;
-        else if (STREQ(compStrategy, "filtered"))
+        else if (streq(compStrategy, "filtered"))
             cmdlineP->zlibCompression.strategy = Z_FILTERED;
         else
             pm_error("Valid values for -strategy are 'huffman_only' and "
@@ -1060,7 +1062,7 @@ findRedundantBits(FILE *         const ifp,
 /*----------------------------------------------------------------------------
    Find out if we can use just a subset of the bits from each input
    sample.  Often, people create an image with e.g. 8 bit samples from
-   one that has e.g. only 4 bit samples by scaling by 256/16, which is
+   one that has e.g. only 4 bit samples by scaling by 255/15, which is
    the same as repeating the bits.  E.g.  1011 becomes 10111011.  We
    detect this case.  We return as *meaningfulBitsP the minimum number
    of bits, starting from the least significant end, that contain
@@ -1352,9 +1354,9 @@ computeUnsortedAlphaPalette(FILE *           const ifP,
 
 
 static void
-sortAlphaPalette(gray *         const alphas_of_color[],
-                 unsigned int   const alphas_first_index[],
-                 unsigned int   const alphas_of_color_cnt[],
+sortAlphaPalette(gray *         const alphasOfColor[],
+                 unsigned int   const alphasFirstIndex[],
+                 unsigned int   const alphasOfColorCnt[],
                  unsigned int   const colors,
                  gray           const alphaMaxval,
                  unsigned int         mapping[],
@@ -1370,40 +1372,56 @@ sortAlphaPalette(gray *         const alphas_of_color[],
    palette of the alpha/color pair whose index is x in the unsorted
    PNG palette.  This mapping sorts the palette so that opaque entries
    are last.
+
+   The unsorted PNG palette is sorted enough that all entries for a particular
+   color (with varying transparencies) are contiguous.  alphasFirstIndex[x] is
+   the index in the unsorted PNG palette of the first entry with color x
+   (where x is an index into some other palette).  alphasOfColorCnt[x] is the
+   number of non-opaque entries in the unsorted PNG palette with color x.
+
+   alphasOfColor[x][y] is the y'th alpha value for color x, in no particular
+   order.
+
+   Return as *transSizeP the number of non-opaque entries in the palette
+   (i.e. the index in the palette of the first opaque entry).
 -----------------------------------------------------------------------------*/
-    unsigned int bot_idx;
-    unsigned int top_idx;
-    unsigned int colorIndex;
+    if (colors == 0)
+        *transSizeP = 0;
+    else {
+        unsigned int bot_idx;
+        unsigned int top_idx;
+        unsigned int colorIndex;
     
-    /* We start one index at the bottom of the palette index range
-       and another at the top.  We run through the unsorted palette,
-       and when we see an opaque entry, we map it to the current top
-       cursor and bump it down.  When we see a non-opaque entry, we map 
-       it to the current bottom cursor and bump it up.  Because the input
-       and output palettes are the same size, the two cursors should meet
-       right when we process the last entry of the unsorted palette.
-    */    
-    bot_idx = 0;
-    top_idx = alphas_first_index[colors-1] + alphas_of_color_cnt[colors-1] - 1;
+        /* We start one index at the bottom of the palette index range
+           and another at the top.  We run through the unsorted palette,
+           and when we see an opaque entry, we map it to the current top
+           cursor and bump it down.  When we see a non-opaque entry, we map 
+           it to the current bottom cursor and bump it up.  Because the input
+           and output palettes are the same size, the two cursors should meet
+           right when we process the last entry of the unsorted palette.
+        */    
+        bot_idx = 0;
+        top_idx = alphasFirstIndex[colors-1] + alphasOfColorCnt[colors-1] - 1;
     
-    for (colorIndex = 0;  colorIndex < colors;  ++colorIndex) {
-        unsigned int j;
-        for (j = 0; j < alphas_of_color_cnt[colorIndex]; ++j) {
-            unsigned int const paletteIndex = 
-                alphas_first_index[colorIndex] + j;
-            if (alphas_of_color[colorIndex][j] == alphaMaxval)
-                mapping[paletteIndex] = top_idx--;
-            else
-                mapping[paletteIndex] = bot_idx++;
+        for (colorIndex = 0;  colorIndex < colors;  ++colorIndex) {
+            unsigned int j;
+            for (j = 0; j < alphasOfColorCnt[colorIndex]; ++j) {
+                unsigned int const paletteIndex = 
+                    alphasFirstIndex[colorIndex] + j;
+                if (alphasOfColor[colorIndex][j] == alphaMaxval)
+                    mapping[paletteIndex] = top_idx--;
+                else
+                    mapping[paletteIndex] = bot_idx++;
+            }
         }
+        /* indices should have just crossed paths */
+        if (bot_idx != top_idx + 1) {
+            pm_error ("internal inconsistency: "
+                      "remapped bot_idx = %u, top_idx = %u",
+                      bot_idx, top_idx);
+        }
+        *transSizeP = bot_idx;
     }
-    /* indices should have just crossed paths */
-    if (bot_idx != top_idx + 1) {
-        pm_error ("internal inconsistency: "
-                  "remapped bot_idx = %u, top_idx = %u",
-                  bot_idx, top_idx);
-    }
-    *transSizeP = bot_idx;
 }
 
 
@@ -1453,7 +1471,7 @@ compute_alpha_palette(FILE *         const ifP,
     getChv(ifP, rasterPos, cols, rows, maxval, format, MAXCOLORS, 
            &chv, &colors);
 
-    assert(colors < ARRAY_SIZE(alphas_of_color));
+    assert(colors <= ARRAY_SIZE(alphas_of_color));
 
     computeUnsortedAlphaPalette(ifP, cols, rows, maxval, format, rasterPos,
                                 alpha_mask, chv, colors,
@@ -1817,6 +1835,7 @@ computeColorMap(FILE *         const ifP,
                 int            const cols,
                 int            const rows,
                 xelval         const maxval,
+                int            const pnmType,
                 int            const format,
                 bool           const force,
                 FILE *         const pfP,
@@ -1864,7 +1883,7 @@ computeColorMap(FILE *         const ifP,
                   maxval, PALETTEMAXVAL);
     else {
         unsigned int bitsPerPixel;
-        computePixelWidth(PNM_FORMAT_TYPE(format), pnm_meaningful_bits, alpha,
+        computePixelWidth(pnmType, pnm_meaningful_bits, alpha,
                           NULL, &bitsPerPixel);
 
         if (!pfP && bitsPerPixel == 1)
@@ -2042,7 +2061,7 @@ createPngPalette(pixel              palette_pnm[],
     for (i = 0; i < transSize; ++i) {
         unsigned int const newmv = PALETTEMAXVAL;
         unsigned int const oldmv = alpha_maxval;
-        trans[i] = (trans_pnm[i] * newmv + (oldmv/2)) / oldmv;
+        trans[i] = ROUNDDIV(trans_pnm[i] * newmv, oldmv);
     }
 }
 
@@ -2347,12 +2366,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
@@ -2397,7 +2416,7 @@ convertpnm(struct cmdlineInfo const cmdline,
       */
   unsigned int fulldepth;
       /* The total number of bits per pixel in the (uncompressed) png
-         raster, including all channels 
+         raster, including all channels.
       */
   pm_filepos rasterPos;  
       /* file position in input image file of start of image (i.e. after
@@ -2470,8 +2489,8 @@ convertpnm(struct cmdlineInfo const cmdline,
          to ppm_parsecolor() because ppm_parsecolor() does a cheap maxval
          scaling, and this is more precise.
       */
-      PPM_DEPTH (transcolor, ppm_parsecolor(transstring2, maxmaxval),
-                 maxmaxval, maxval);
+      PPM_DEPTH(transcolor, ppm_parsecolor(transstring2, maxmaxval),
+                maxmaxval, maxval);
   }
   if (cmdline.alpha) {
     pixel alpha_transcolor;
@@ -2550,7 +2569,7 @@ convertpnm(struct cmdlineInfo const cmdline,
   findRedundantBits(ifp, rasterPos, cols, rows, maxval, format, alpha,
                     cmdline.force, &pnm_meaningful_bits);
   
-  computeColorMap(ifp, rasterPos, cols, rows, maxval, format,
+  computeColorMap(ifp, rasterPos, cols, rows, maxval, pnm_type, format,
                   cmdline.force, pfp,
                   alpha, transparent >= 0, transcolor, transexact, 
                   !!cmdline.background, backcolor,
@@ -2630,7 +2649,7 @@ convertpnm(struct cmdlineInfo const cmdline,
     info_ptr->num_palette = palette_size;
     if (trans_size > 0) {
         info_ptr->valid |= PNG_INFO_tRNS;
-        info_ptr->trans = trans;
+        info_ptr->TRANS_ALPHA = trans;
         info_ptr->num_trans = trans_size;   /* omit opaque values */
     }
     /* creating hIST chunk */
@@ -2809,7 +2828,7 @@ main(int argc, char *argv[]) {
 
     int errorlevel;
     
-    pnm_init (&argc, argv);
+    pnm_init(&argc, argv);
     
     parseCommandLine(argc, argv, &cmdline);
     
@@ -2852,3 +2871,6 @@ main(int argc, char *argv[]) {
 
     return errorlevel;
 }
+
+
+
diff --git a/converter/other/pnmtops.c b/converter/other/pnmtops.c
index fb4d7648..20395952 100644
--- a/converter/other/pnmtops.c
+++ b/converter/other/pnmtops.c
@@ -34,6 +34,8 @@
 
 #include <string.h>
 #include <assert.h>
+
+#include "pm_c_util.h"
 #include "pam.h"
 #include "mallocvar.h"
 #include "shhopt.h"
@@ -275,6 +277,7 @@ putitem(void) {
         putchar('\n');
         itemsinline = 0;
     }
+    assert(item >> 8 == 0);
     putchar(hexits[item >> 4]);
     putchar(hexits[item & 15]);
     ++itemsinline;
@@ -496,7 +499,7 @@ destroyBmepsOutputEncoder(struct bmepsoe * const bmepsoeP) {
 static void
 outputBmepsSample(struct bmepsoe * const bmepsoeP,
                   unsigned int     const sampleValue,
-          unsigned int     const bitsPerSample) {
+                  unsigned int     const bitsPerSample) {
 
     if (bitsPerSample == 8)
         oe_byte_add(bmepsoeP->oeP, sampleValue);
@@ -954,8 +957,35 @@ putEnd(bool         const showpage,
 
 
 static void
+warnUserAboutReducedDepth(unsigned int const bitsGot,
+                          unsigned int const bitsWanted,
+                          unsigned int const postscriptLevel,
+                          bool         const psFilter) {
+
+    if (bitsGot < bitsWanted) {
+        pm_message("Postscript will have %u bits of color resolution, "
+                   "though the input has %u bits.",
+                   bitsGot, bitsWanted);
+
+        if (postscriptLevel < 2)
+            pm_message("Postscript level %u has a maximum depth of 8 bits.  "
+                       "You could get up to 12 with -level=2 and -psfilter.",
+                       postscriptLevel);
+        else {
+            if (!psFilter)
+                pm_message("You can get up to 12 bits with -psfilter");
+            else
+                pm_message("The Postscript maximum is 12.");
+        }
+    }
+}
+
+
+
+static void
 computeDepth(xelval         const inputMaxval,
              unsigned int   const postscriptLevel, 
+             bool           const psFilter,
              unsigned int * const bitspersampleP,
              unsigned int * const psMaxvalP) {
 /*----------------------------------------------------------------------------
@@ -971,30 +1001,24 @@ computeDepth(xelval         const inputMaxval,
         *bitspersampleP = 2;
     else if (bitsRequiredByMaxval <= 4)
         *bitspersampleP = 4;
-    else        
+    else if (bitsRequiredByMaxval <= 8)
         *bitspersampleP = 8;
-
-    /* There is supposedly a 12 bits per pixel Postscript format, but
-       what?  We produce a raster that is composed of bytes, each
-       coded as a pair of hexadecimal characters and representing 8,
-       4, 2, or 1 pixels.  We also have the RLE format, where some of
-       those bytes are run lengths.
-    */
-
-    if (*bitspersampleP < bitsRequiredByMaxval) {
-        if (bitsRequiredByMaxval <= 12 && postscriptLevel >= 2)
-            pm_message("Maxval of input requires %u bit samples for full "
-                       "resolution, and Postscript level %u is capable "
-                       "of representing that many, but this program "
-                       "doesn't know how.  So we are using %u",
-                       bitsRequiredByMaxval, postscriptLevel, *bitspersampleP);
+    else {
+        /* Post script level 2 defines a format with 12 bits per sample,
+           but I don't know the details of that format (both RLE and
+           non-RLE variations) and existing native raster generation code
+           simply can't handle bps > 8.  But the built-in filters know
+           how to do 12 bps.
+        */
+        if (postscriptLevel >= 2 && psFilter)
+            *bitspersampleP = 12;
         else
-            pm_message("Maxval of input requires %u bit samples for full "
-                       "resolution, but we are using the Postscript level %u "
-                       "maximum of %u",
-                       bitsRequiredByMaxval, postscriptLevel, *bitspersampleP);
+            *bitspersampleP = 8;
     }
 
+    warnUserAboutReducedDepth(*bitspersampleP, bitsRequiredByMaxval,
+                              postscriptLevel, psFilter);
+
     *psMaxvalP = pm_bitstomaxval(*bitspersampleP);
 
     if (verbose)
@@ -1047,8 +1071,7 @@ convertRowPsFilter(struct pam *     const pamP,
     unsigned int const stragglers =
         (((bitsPerSample * pamP->depth) % 8) * pamP->width) % 8;
         /* Number of bits at the right edge that don't fill out a
-           whole byte
-        */
+           whole byte */
 
     unsigned int col;
     tuple scaledTuple;
@@ -1183,7 +1206,8 @@ convertPage(FILE * const ifP,
     if (color)
         pm_message("generating color Postscript program.");
 
-    computeDepth(inpam.maxval, postscriptLevel, &bitspersample, &psMaxval);
+    computeDepth(inpam.maxval, postscriptLevel, psFilter,
+                 &bitspersample, &psMaxval);
     {
         unsigned int const realBitsPerLine = inpam.width * bitspersample;
         unsigned int const paddedBitsPerLine = ((realBitsPerLine + 7) / 8) * 8;
@@ -1275,7 +1299,7 @@ main(int argc, char * argv[]) {
 
     ifp = pm_openr(cmdline.inputFileName);
 
-    if (STREQ(cmdline.inputFileName, "-"))
+    if (streq(cmdline.inputFileName, "-"))
         name = strdup("noname");
     else
         name = basebasename(cmdline.inputFileName);
@@ -1313,7 +1337,7 @@ main(int argc, char * argv[]) {
     strfree(name);
 
     pm_close(ifp);
-    
+
     return 0;
 }
 
diff --git a/converter/other/pnmtorast.c b/converter/other/pnmtorast.c
index 7d1ae05a..605e815c 100644
--- a/converter/other/pnmtorast.c
+++ b/converter/other/pnmtorast.c
@@ -15,15 +15,79 @@
 #include "mallocvar.h"
 
 #define MAXCOLORS 256
-static colormap_t* make_pr_colormap ARGS(( colorhist_vector chv, int colors ));
-static colormap_t* make_gray_pr_colormap ARGS(( void ));
-static colormap_t* alloc_pr_colormap ARGS(( void ));
+
+
+
+static colormap_t *
+alloc_pr_colormap(void) {
+
+    colormap_t* pr_colormapP;
+
+    MALLOCVAR(pr_colormapP);
+    if ( pr_colormapP == NULL )
+        pm_error( "out of memory" );
+    pr_colormapP->type = RMT_EQUAL_RGB;
+    pr_colormapP->length = MAXCOLORS;
+    MALLOCARRAY(pr_colormapP->map[0], MAXCOLORS);
+    MALLOCARRAY(pr_colormapP->map[1], MAXCOLORS);
+    MALLOCARRAY(pr_colormapP->map[2], MAXCOLORS);
+    if ( pr_colormapP->map[0] == NULL || 
+         pr_colormapP->map[1] == NULL ||
+         pr_colormapP->map[2] == NULL )
+        pm_error( "out of memory" );
+
+    return pr_colormapP;
+}
+
+
+
+static colormap_t*
+make_pr_colormap(colorhist_vector const chv,
+                 int              const colors) {
+
+    colormap_t* pr_colormapP;
+    int i;
+
+    pr_colormapP = alloc_pr_colormap( );
+
+    for ( i = 0; i < colors; ++i )
+    {
+        pr_colormapP->map[0][i] = PPM_GETR( chv[i].color );
+        pr_colormapP->map[1][i] = PPM_GETG( chv[i].color );
+        pr_colormapP->map[2][i] = PPM_GETB( chv[i].color );
+    }
+    for ( ; i < MAXCOLORS; ++i )
+        pr_colormapP->map[0][i] = pr_colormapP->map[1][i] =
+            pr_colormapP->map[2][i] = 0;
+
+    return pr_colormapP;
+}
+
+
+
+static colormap_t *
+make_gray_pr_colormap(void) {
+
+    colormap_t* pr_colormapP;
+    int i;
+
+    pr_colormapP = alloc_pr_colormap( );
+
+    for ( i = 0; i < MAXCOLORS; ++i )
+    {
+        pr_colormapP->map[0][i] = i;
+        pr_colormapP->map[1][i] = i;
+        pr_colormapP->map[2][i] = i;
+    }
+
+    return pr_colormapP;
+}
+
+
 
 int
-main( argc, argv )
-    int argc;
-    char* argv[];
-{
+main(int argc, char ** argv) {
+
     FILE* ifp;
     xel** xels;
     xel* xelrow;
@@ -247,64 +311,3 @@ main( argc, argv )
     exit( 0 );
 }
 
-static colormap_t*
-make_pr_colormap( chv, colors )
-    colorhist_vector chv;
-    int colors;
-{
-    colormap_t* pr_colormapP;
-    int i;
-
-    pr_colormapP = alloc_pr_colormap( );
-
-    for ( i = 0; i < colors; ++i )
-    {
-        pr_colormapP->map[0][i] = PPM_GETR( chv[i].color );
-        pr_colormapP->map[1][i] = PPM_GETG( chv[i].color );
-        pr_colormapP->map[2][i] = PPM_GETB( chv[i].color );
-    }
-    for ( ; i < MAXCOLORS; ++i )
-        pr_colormapP->map[0][i] = pr_colormapP->map[1][i] =
-            pr_colormapP->map[2][i] = 0;
-
-    return pr_colormapP;
-}
-
-static colormap_t*
-make_gray_pr_colormap( )
-{
-    colormap_t* pr_colormapP;
-    int i;
-
-    pr_colormapP = alloc_pr_colormap( );
-
-    for ( i = 0; i < MAXCOLORS; ++i )
-    {
-        pr_colormapP->map[0][i] = i;
-        pr_colormapP->map[1][i] = i;
-        pr_colormapP->map[2][i] = i;
-    }
-
-    return pr_colormapP;
-}
-
-static colormap_t*
-alloc_pr_colormap( )
-{
-    colormap_t* pr_colormapP;
-
-    MALLOCVAR(pr_colormapP);
-    if ( pr_colormapP == NULL )
-        pm_error( "out of memory" );
-    pr_colormapP->type = RMT_EQUAL_RGB;
-    pr_colormapP->length = MAXCOLORS;
-    MALLOCARRAY(pr_colormapP->map[0], MAXCOLORS);
-    MALLOCARRAY(pr_colormapP->map[1], MAXCOLORS);
-    MALLOCARRAY(pr_colormapP->map[2], MAXCOLORS);
-    if ( pr_colormapP->map[0] == NULL || 
-         pr_colormapP->map[1] == NULL ||
-         pr_colormapP->map[2] == NULL )
-        pm_error( "out of memory" );
-
-    return pr_colormapP;
-}
diff --git a/converter/other/pnmtorle.c b/converter/other/pnmtorle.c
index b7834e89..8908c356 100644
--- a/converter/other/pnmtorle.c
+++ b/converter/other/pnmtorle.c
@@ -59,8 +59,8 @@ static gray    maxval;
  *                                        Read the pnm image file header.
  */
 static void 
-read_pnm_header()
-{
+read_pnm_header(void) {
+
     pnm_readpnminit(fp, &width, &height, &maxval, &format);
     switch (format) {
     case PBM_FORMAT:
@@ -87,12 +87,12 @@ read_pnm_header()
     if (do_alpha)
         VPRINTF(stderr, "Computing alpha channel...\n");
 }
-/*-----------------------------------------------------------------------------
- *                                             Write the rle image file header.
- */
+
+
+
 static void 
-write_rle_header()
-{
+write_rle_header(void) {
+
     hdr.xmin    = 0;
     hdr.xmax    = width-1;
     hdr.ymin    = 0;
@@ -120,101 +120,106 @@ write_rle_header()
     }
     rle_put_setup(&hdr);
 }
-/*-----------------------------------------------------------------------------
- *                                      Write the rle data portion of the file.
- */
+
+
+
 static void 
-write_rle_data()
-{
-    register int     x;
-    register int     scan;
-    register xel     *xelrow, *pP;
-    rle_pixel        ***scanlines, **scanline;
-/*
- * Allocate some memory.
- */
-    /*xelrow = pnm_allowcrow(width);*/
-    xelrow = (xel*) pm_allocrow( width, sizeof(xel) );
+write_rle_data(void) {
+
+    unsigned int scan;
+    xel * xelrow;
+    rle_pixel *** scanlines;
+
+    MALLOCARRAY(xelrow, width);
     MALLOCARRAY(scanlines, height);
-    RLE_CHECK_ALLOC( hdr.cmd, scanlines, "scanline pointers" );
 
-    for ( scan = 0; scan < height; scan++ )
-        RLE_CHECK_ALLOC( hdr.cmd, (rle_row_alloc(&hdr, &scanlines[scan]) >= 0),
-                         "pixel memory" );
-/*
- * Loop through the pnm files image window, read data and flip vertically.
- */
+    RLE_CHECK_ALLOC(hdr.cmd, scanlines, "scanline pointers");
+
+    for (scan = 0; scan < height; ++scan) {
+        int rc;
+        rc = rle_row_alloc(&hdr, &scanlines[scan]);
+        RLE_CHECK_ALLOC(hdr.cmd, rc >= 0, "pixel memory");
+    }
+    /* Loop through the pnm files image window, read data and flip vertically.
+     */
     switch (format) {
     case PBM_FORMAT:
-    case RPBM_FORMAT:
-        for (scan = 0; scan < height; scan++) {
-            scanline = scanlines[height - scan - 1];
+    case RPBM_FORMAT: {
+        unsigned int scan;
+        for (scan = 0; scan < height; ++scan) {
+            rle_pixel ** const scanline = scanlines[height - scan - 1];
+            unsigned int col;
             pnm_readpnmrow(fp, xelrow, width, maxval, format);
-            for (x = 0, pP = xelrow; x < width; x++, pP++) {
-                scanline[RLE_RED][x]   = (PNM_GET1(*pP) ? 255 : 0);
-                if (do_alpha) {
-                    scanline[RLE_ALPHA][x] = scanline[RLE_RED][x];
-                }
+            for (col = 0; col < width; ++col) {
+                scanline[RLE_RED][col] = PNM_GET1(xelrow[col]) ? 255 : 0;
+                if (do_alpha)
+                    scanline[RLE_ALPHA][col] = scanline[RLE_RED][col];
             }
         }
-        break;
+    } break;
     case PGM_FORMAT:
-    case RPGM_FORMAT:
-        for (scan = 0; scan < height; scan++) {
-            scanline = scanlines[height - scan - 1];
+    case RPGM_FORMAT: {
+        unsigned int scan;
+        for (scan = 0; scan < height; ++scan) {
+            rle_pixel ** const scanline = scanlines[height - scan - 1];
+            unsigned int col;
             pnm_readpnmrow(fp, xelrow, width, maxval, format);
-            for (x = 0, pP = xelrow; x < width; x++, pP++) {
-                scanline[RLE_RED][x]   = PNM_GET1(*pP);
-                if (do_alpha) {
-                    scanline[RLE_ALPHA][x] = (scanline[RLE_RED][x] ? 255 : 0);
-                }
+            for (col = 0; col < width; ++col) {
+                scanline[RLE_RED][col] = PNM_GET1(xelrow[col]);
+                if (do_alpha)
+                    scanline[RLE_ALPHA][col] =
+                        scanline[RLE_RED][col] ? 255 : 0;
             }
         }
-        break;
+    } break;
     case PPM_FORMAT:
-    case RPPM_FORMAT:
+    case RPPM_FORMAT: {
+        unsigned int scan;
         for (scan = 0; scan < height; scan++) {
-            scanline = scanlines[height - scan - 1];
+            rle_pixel ** const scanline = scanlines[height - scan - 1];
+            unsigned int col;
             pnm_readpnmrow(fp, xelrow, width, maxval, format);
-            for (x = 0, pP = xelrow; x < width; x++, pP++) {
-                scanline[RLE_RED][x]   = PPM_GETR(*pP);
-                scanline[RLE_GREEN][x] = PPM_GETG(*pP);
-                scanline[RLE_BLUE][x]  = PPM_GETB(*pP);
-                if (do_alpha) {
-                    scanline[RLE_ALPHA][x] = (scanline[RLE_RED][x] ||
-                                              scanline[RLE_GREEN][x] ||
-                                              scanline[RLE_BLUE][x] ? 255 : 0);
-                }
+            for (col = 0; col < width; ++col) {
+                scanline[RLE_RED][col]   = PPM_GETR(xelrow[col]);
+                scanline[RLE_GREEN][col] = PPM_GETG(xelrow[col]);
+                scanline[RLE_BLUE][col]  = PPM_GETB(xelrow[col]);
+                if (do_alpha)
+                    scanline[RLE_ALPHA][col] =
+                        (scanline[RLE_RED][col] ||
+                         scanline[RLE_GREEN][col] ||
+                         scanline[RLE_BLUE][col] ? 255 : 0);
             }
         }
-        break;
+        } break;
     }
-/*
- * Write out data in URT order (bottom to top).
- */
-    for ( scan = 0; scan < height; scan++ ) {
+    /* Write out data in URT order (bottom to top). */
+    for (scan = 0; scan < height; ++scan)
         rle_putrow(scanlines[scan], width, &hdr);
-        rle_row_free( &hdr, scanlines[scan] );
-    }
-    free( scanlines );
+
+    for (scan = 0; scan < height; ++scan)
+        rle_row_free(&hdr, scanlines[scan]);
+    free(scanlines);
+    free(xelrow);
 
     VPRINTF(stderr, "Done -- write eof to RLE data.\n");
     rle_puteof(&hdr);
 }
 
+
+
 int
-main(argc, argv)
-    int argc;
-    char **argv;
-{
-    char     *pnmname = NULL, *outname = NULL;
-    int      oflag, c;
+main(int argc, char **  argv) {
+
+    const char * pnmname;
+    const char * outname;
+    int oflag;
 
     pnm_init(&argc, argv);
 
-/*
- * Get those options.
- */
+    pnmname = NULL;  /* initial value */
+    outname = NULL;  /* initial value */
+
+    /* Get those options. */
     if (!scanargs(argc,argv,
                   "% v%- h%- a%- o%-outfile!s pnmfile%s\n(\
 \tConvert a PNM file to URT RLE format.\n\
@@ -228,37 +233,32 @@ main(argc, argv)
                   &pnmname))
         exit(-1);
 
-    hdr = *rle_hdr_init( (rle_hdr *)NULL );
-    rle_names( &hdr, cmd_name( argv ), outname, 0 );
-/*
- * Open the file.
- */
+    hdr = *rle_hdr_init(NULL);
+    rle_names(&hdr, cmd_name(argv), outname, 0);
+
+    /* Open the file. */
     if (pnmname == NULL) {
-        fp = stdin;
-    }
-    else {
+        fp = pm_openr("-");
+    } else {
         fp = pm_openr(pnmname);
     }
 
     hdr.rle_file = rle_open_f( hdr.cmd, outname, "wb" );
-    while ( (c = getc( fp )) != EOF ) {
-        ungetc( c, fp );
-/*
- * Read the PPM file header.
- */
+
+    if (header)
         read_pnm_header();
-        if (header)
-            break;
-/*
- * Write the rle file header.
- */
-        rle_addhist(argv, (rle_hdr *)NULL, &hdr);
-        write_rle_header();
-/*
- * Write the rle file data.
- */
-        write_rle_data();
+    else {
+        int eof;
+        for (eof = 0; !eof; ) {
+            read_pnm_header();
+            rle_addhist(argv, NULL, &hdr);
+            write_rle_header();
+            write_rle_data();
+            
+            pnm_nextimage(fp, &eof);
+        }
     }
-    fclose(fp);
+    pm_close(fp);
+
     return 0;
 }
diff --git a/converter/other/pnmtotiffcmyk.c b/converter/other/pnmtotiffcmyk.c
index 0fda6b08..2e6ae935 100644
--- a/converter/other/pnmtotiffcmyk.c
+++ b/converter/other/pnmtotiffcmyk.c
@@ -542,10 +542,6 @@ tiffOpen( Out* out, Root *r ) {
   short photometric = PHOTOMETRIC_SEPARATED ; /* ie cmyk */
   int bytesperrow = r->nCols ;
 
-  /* if i don't set stdout non-blocking on my machine then the read
-     that is called inside TIFFFdOpen hangs until the users types ^D.
-     this is also true for pnmtotiff */
-  fcntl( 1, F_SETFL, O_NONBLOCK ) ;
   t->tiff = TIFFFdOpen( 1, "Standard Output", "w" ) ;
   if ( ! t->tiff ) {
     fprintf( stderr, "cannot open tiff stream to standard output\n" ) ;
@@ -794,7 +790,7 @@ standardOpt( Conv *conv, Root *r, int *argn, int argc, char **argv ) {
   }
   /* handle the special case of -1 (no removal) */
   if ( oldn == *argn && pm_keymatch( argv[*argn], "-gammap", 7 ) &&
-       *argn + 1 < argc && STREQ(argv[*argn + 1], "-1") ) {
+       *argn + 1 < argc && streq(argv[*argn + 1], "-1") ) {
     p->remove = 0 ;
     *argn = (*argn) + 2 ;
   } 
diff --git a/converter/other/pnmtoxwd.c b/converter/other/pnmtoxwd.c
index 32fb8a7b..b6439d28 100644
--- a/converter/other/pnmtoxwd.c
+++ b/converter/other/pnmtoxwd.c
@@ -11,6 +11,8 @@
 */
 
 #include <string.h>
+
+#include "pm_c_util.h"
 #include "pnm.h"
 #include "shhopt.h"
 #include "mallocvar.h"
@@ -471,7 +473,7 @@ main(int argc, char * argv[]) {
         }
     }
 
-    if (STREQ(cmdline.inputFilespec, "-"))
+    if (streq(cmdline.inputFilespec, "-"))
         dumpname = "stdin";
     else {
         if (strlen(cmdline.inputFilespec) > XWDVAL_MAX - sizeof(h11) - 1)
diff --git a/converter/other/pstopnm.c b/converter/other/pstopnm.c
index a31c3f64..ba1470b0 100644
--- a/converter/other/pstopnm.c
+++ b/converter/other/pstopnm.c
@@ -26,6 +26,7 @@
 #include <sys/wait.h>  
 #include <sys/stat.h>
 
+#include "pm_c_util.h"
 #include "pnm.h"
 #include "shhopt.h"
 #include "nstring.h"
@@ -196,8 +197,9 @@ parseCommandLine(int argc, char ** argv,
 
 
 static void
-add_ps_to_filespec(const char orig_filespec[], char ** const new_filespec_p,
-                   const int verbose) {
+addPsToFilespec(char          const orig_filespec[],
+                const char ** const new_filespec_p,
+                bool          const verbose) {
 /*----------------------------------------------------------------------------
    If orig_filespec[] does not name an existing file, but the same
    name with ".ps" added to the end does, return the name with the .ps
@@ -288,13 +290,13 @@ computeSizeResBlind(unsigned int   const xmax,
 
 
 static void
-compute_size_res(struct cmdlineInfo const cmdline, 
-                 enum orientation   const orientation, 
-                 struct box         const bordered_box,
-                 unsigned int *     const xsizeP, 
-                 unsigned int *     const ysizeP,
-                 unsigned int *     const xresP, 
-                 unsigned int *     const yresP) {
+computeSizeRes(struct cmdlineInfo const cmdline, 
+               enum orientation   const orientation, 
+               struct box         const bordered_box,
+               unsigned int *     const xsizeP, 
+               unsigned int *     const ysizeP,
+               unsigned int *     const xresP, 
+               unsigned int *     const yresP) {
 /*----------------------------------------------------------------------------
   Figure out how big the output image should be (return as
   *xsizeP and *ysizeP) and what output device resolution Ghostscript
@@ -353,7 +355,8 @@ compute_size_res(struct cmdlineInfo const cmdline,
 enum postscript_language {COMMON_POSTSCRIPT, ENCAPSULATED_POSTSCRIPT};
 
 static enum postscript_language
-language_declaration(const char input_filespec[], int const verbose) {
+languageDeclaration(char const input_filespec[],
+                    bool const verbose) {
 /*----------------------------------------------------------------------------
   Return the Postscript language in which the file declares it is written.
   (Except that if the file is on Standard Input or doesn't validly declare
@@ -361,7 +364,7 @@ language_declaration(const char input_filespec[], int const verbose) {
 -----------------------------------------------------------------------------*/
     enum postscript_language language;
 
-    if (STREQ(input_filespec, "-"))
+    if (streq(input_filespec, "-"))
         /* Can't read stdin, because we need it to remain positioned for the 
            Ghostscript interpreter to read it.
         */
@@ -395,9 +398,9 @@ language_declaration(const char input_filespec[], int const verbose) {
 
 
 static struct box
-compute_box_to_extract(struct box const cmdline_extract_box,
-                       char       const input_filespec[],
-                       bool       const verbose) {
+computeBoxToExtract(struct box const cmdline_extract_box,
+                    char       const input_filespec[],
+                    bool       const verbose) {
 
     struct box retval;
 
@@ -410,7 +413,7 @@ compute_box_to_extract(struct box const cmdline_extract_box,
         */
         struct box ps_bb;  /* Box described by %%BoundingBox stmt in input */
 
-        if (STREQ(input_filespec, "-"))
+        if (streq(input_filespec, "-"))
             /* Can't read stdin, because we need it to remain
                positioned for the Ghostscript interpreter to read it.  
             */
@@ -466,8 +469,8 @@ compute_box_to_extract(struct box const cmdline_extract_box,
 
 
 static enum orientation
-compute_orientation(struct cmdlineInfo const cmdline, 
-                    struct box         const extract_box) {
+computeOrientation(struct cmdlineInfo const cmdline, 
+                   struct box         const extract_box) {
 
     enum orientation retval;
     unsigned int const input_width  = extract_box.urx - extract_box.llx;
@@ -511,9 +514,10 @@ compute_orientation(struct cmdlineInfo const cmdline,
 
 
 static struct box
-add_borders(const struct box input_box, 
-            const float xborder_scale, float yborder_scale,
-            const int verbose) {
+addBorders(struct box const input_box, 
+           float      const xborder_scale,
+           float      const yborder_scale,
+           bool       const verbose) {
 /*----------------------------------------------------------------------------
    Return a box which is 'input_box' plus some borders.
 
@@ -543,9 +547,12 @@ add_borders(const struct box input_box,
 
 
 static const char *
-compute_pstrans(const struct box box, const enum orientation orientation,
-                const int xsize, const int ysize, 
-                const int xres, const int yres) {
+computePstrans(struct box       const box,
+               enum orientation const orientation,
+               int              const xsize,
+               int              const ysize, 
+               int              const xres,
+               int              const yres) {
 
     const char * retval;
 
@@ -570,13 +577,13 @@ compute_pstrans(const struct box box, const enum orientation orientation,
 
 
 static const char *
-compute_outfile_arg(const struct cmdlineInfo cmdline) {
+computeOutfileArg(struct cmdlineInfo const cmdline) {
 
     const char *retval;  /* malloc'ed */
 
     if (cmdline.goto_stdout)
         retval = strdup("-");
-    else if (STREQ(cmdline.input_filespec, "-"))
+    else if (streq(cmdline.input_filespec, "-"))
         retval = strdup("-");
     else {
         char * basename;
@@ -584,7 +591,7 @@ compute_outfile_arg(const struct cmdlineInfo cmdline) {
         
         basename  = strdup(cmdline.input_filespec);
         if (strlen(basename) > 3 && 
-            STREQ(basename+strlen(basename)-3, ".ps")) 
+            streq(basename+strlen(basename)-3, ".ps")) 
             /* The input filespec ends in ".ps".  Chop it off. */
             basename[strlen(basename)-3] = '\0';
 
@@ -605,7 +612,8 @@ compute_outfile_arg(const struct cmdlineInfo cmdline) {
 
 
 static const char *
-compute_gs_device(const int format_type, const int forceplain) {
+computeGsDevice(int  const format_type,
+                bool const forceplain) {
 
     const char * basetype;
     const char * retval;
@@ -673,19 +681,22 @@ findGhostscriptProg(const char ** const retvalP) {
 
 
 static void
-execGhostscript(int const inputPipeFd,
-                const char ghostscript_device[],
-                const char outfile_arg[], 
-                int const xsize, int const ysize, 
-                int const xres, int const yres,
-                const char input_filespec[], int const verbose) {
+execGhostscript(int  const inputPipeFd,
+                char const ghostscript_device[],
+                char const outfile_arg[], 
+                int  const xsize,
+                int  const ysize, 
+                int  const xres,
+                int  const yres,
+                char const input_filespec[],
+                bool const verbose) {
     
-    const char *arg0;
-    const char *ghostscriptProg;
-    const char *deviceopt;
-    const char *outfileopt;
-    const char *gopt;
-    const char *ropt;
+    const char * arg0;
+    const char * ghostscriptProg;
+    const char * deviceopt;
+    const char * outfileopt;
+    const char * gopt;
+    const char * ropt;
     int rc;
 
     findGhostscriptProg(&ghostscriptProg);
@@ -723,15 +734,17 @@ execGhostscript(int const inputPipeFd,
 
 
 
-
 static void
-execute_ghostscript(const char pstrans[], const char ghostscript_device[],
-                    const char outfile_arg[], 
-                    const int xsize, const int ysize, 
-                    const int xres, const int yres,
-                    const char input_filespec[], 
-                    const enum postscript_language language,
-                    const int verbose) {
+executeGhostscript(char                     const pstrans[],
+                   char                     const ghostscript_device[],
+                   char                     const outfile_arg[], 
+                   int                      const xsize,
+                   int                      const ysize, 
+                   int                      const xres,
+                   int                      const yres,
+                   char                     const input_filespec[], 
+                   enum postscript_language const language,
+                   bool                     const verbose) {
 
     int gs_exit;  /* wait4 exit code from Ghostscript */
     FILE *gs;  /* Pipe to Ghostscript's standard input */
@@ -835,10 +848,10 @@ execute_ghostscript(const char pstrans[], const char ghostscript_device[],
 
 
 int
-main(int argc, char **argv) {
+main(int argc, char ** argv) {
 
     struct cmdlineInfo cmdline;
-    char *input_filespec;  /* malloc'ed */
+    const char * input_filespec;  /* malloc'ed */
         /* The file specification of our Postscript input file */
     unsigned int xres, yres;    /* Resolution in pixels per inch */
     unsigned int xsize, ysize;  /* output image size in pixels */
@@ -851,43 +864,42 @@ main(int argc, char **argv) {
 
     enum postscript_language language;
     enum orientation orientation;
-    const char *ghostscript_device;
-    const char *outfile_arg;
-    const char *pstrans;
+    const char * ghostscript_device;
+    const char * outfile_arg;
+    const char * pstrans;
 
     pnm_init(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
-    add_ps_to_filespec(cmdline.input_filespec, &input_filespec,
-                       cmdline.verbose);
+    addPsToFilespec(cmdline.input_filespec, &input_filespec, cmdline.verbose);
 
-    extract_box = compute_box_to_extract(cmdline.extract_box, input_filespec, 
-                                         cmdline.verbose);
+    extract_box = computeBoxToExtract(cmdline.extract_box, input_filespec, 
+                                      cmdline.verbose);
 
-    language = language_declaration(input_filespec, cmdline.verbose);
+    language = languageDeclaration(input_filespec, cmdline.verbose);
     
-    orientation = compute_orientation(cmdline, extract_box);
+    orientation = computeOrientation(cmdline, extract_box);
 
-    bordered_box = add_borders(extract_box, cmdline.xborder, cmdline.yborder,
-                               cmdline.verbose);
+    bordered_box = addBorders(extract_box, cmdline.xborder, cmdline.yborder,
+                              cmdline.verbose);
 
-    compute_size_res(cmdline, orientation, bordered_box, 
-                     &xsize, &ysize, &xres, &yres);
+    computeSizeRes(cmdline, orientation, bordered_box, 
+                   &xsize, &ysize, &xres, &yres);
     
-    pstrans = compute_pstrans(bordered_box, orientation,
-                              xsize, ysize, xres, yres);
+    pstrans = computePstrans(bordered_box, orientation,
+                             xsize, ysize, xres, yres);
 
-    outfile_arg = compute_outfile_arg(cmdline);
+    outfile_arg = computeOutfileArg(cmdline);
 
     ghostscript_device = 
-        compute_gs_device(cmdline.format_type, cmdline.forceplain);
+        computeGsDevice(cmdline.format_type, cmdline.forceplain);
     
     pm_message("Writing %s file", ghostscript_device);
     
-    execute_ghostscript(pstrans, ghostscript_device, outfile_arg, 
-                        xsize, ysize, xres, yres, input_filespec,
-                        language, cmdline.verbose);
+    executeGhostscript(pstrans, ghostscript_device, outfile_arg, 
+                       xsize, ysize, xres, yres, input_filespec,
+                       language, cmdline.verbose);
 
     strfree(ghostscript_device);
     strfree(outfile_arg);
diff --git a/converter/other/rast.h b/converter/other/rast.h
index 1854e495..e79896ea 100644
--- a/converter/other/rast.h
+++ b/converter/other/rast.h
@@ -97,15 +97,33 @@ typedef struct {
 
 /* And the routine definitions. */
 
-struct pixrect* mem_create ARGS(( int w, int h, int depth ));
-void mem_free ARGS(( struct pixrect* p ));
+struct pixrect *
+mem_create(int const w,
+           int const h,
+           int const depth);
 
-int pr_dump ARGS(( struct pixrect* p, FILE* out, colormap_t* colormap, int type, int copy_flag ));
+void
+mem_free(struct pixrect * const p);
 
-int pr_load_header ARGS(( FILE* in, struct rasterfile* hP ));
+int
+pr_dump(struct pixrect * const p,
+        FILE *           const out,
+        colormap_t *     const colormap,
+        int              const type,
+        int              const copy_flag);
 
-int pr_load_colormap ARGS(( FILE* in, struct rasterfile* hP, colormap_t* colormap ));
+int
+pr_load_header(FILE *              const in,
+               struct rasterfile * const hP);
 
-struct pixrect* pr_load_image ARGS(( FILE* in, struct rasterfile* hP, colormap_t* colormap ));
+int
+pr_load_colormap(FILE *              const in,
+                 struct rasterfile * const hP,
+                 colormap_t *        const colormap);
+
+struct pixrect *
+pr_load_image(FILE *              const in,
+              struct rasterfile * const hP,
+              colormap_t *        const colormap);
 
 #endif
diff --git a/converter/other/rlatopam.c b/converter/other/rlatopam.c
index ae1326ca..703c4820 100644
--- a/converter/other/rlatopam.c
+++ b/converter/other/rlatopam.c
@@ -16,6 +16,7 @@
 #include <string.h>
 #include <errno.h>
 
+#include "pm_c_util.h"
 #include "shhopt.h"
 #include "mallocvar.h"
 #include "pam.h"
diff --git a/converter/other/rletopnm.c b/converter/other/rletopnm.c
index aaa86388..83ada51b 100644
--- a/converter/other/rletopnm.c
+++ b/converter/other/rletopnm.c
@@ -46,6 +46,7 @@
 #define NO_DECLARE_MALLOC
 #include <rle.h>
 
+#include "pm_c_util.h"
 #include "pnm.h"
 #include "shhopt.h"
 #include "mallocvar.h"
@@ -124,7 +125,7 @@ parseCommandLine(int argc, char ** argv,
     if (argc - 1 == 0)
         cmdlineP->input_filename = NULL;  /* he wants stdin */
     else if (argc - 1 == 1) {
-        if (STREQ(argv[1], "-"))
+        if (streq(argv[1], "-"))
             cmdlineP->input_filename = NULL;  /* he wants stdin */
         else 
             cmdlineP->input_filename = strdup(argv[1]);
@@ -133,7 +134,7 @@ parseCommandLine(int argc, char ** argv,
                  "is the input file specification");
 
     if (cmdlineP->alpha_filename && 
-        STREQ(cmdlineP->alpha_filename, "-"))
+        streq(cmdlineP->alpha_filename, "-"))
         cmdlineP->alpha_stdout = TRUE;
     else 
         cmdlineP->alpha_stdout = FALSE;
diff --git a/converter/other/svgtopam.c b/converter/other/svgtopam.c
index 76e122db..c7eac8e6 100644
--- a/converter/other/svgtopam.c
+++ b/converter/other/svgtopam.c
@@ -13,6 +13,17 @@
   By Bryan Henderson, San Jose, California.  May 2006
 
   Contributed to the public domain.
+
+==============================================================================
+
+  Implementation notes:
+
+   A look at Libxml2 Subversion source code change history says the type
+   'xmlReaderTypes' was added (in <libxml/xmlreader.h>) in 2.5.9.  But a MacOS
+   10.3.9 user reports in April 2007 that he has 2.6.16 installed and it
+   doesn't have xmlReaderTypes.  Another MacOS user reported that in December
+   2008.  Apparently that OS has a broken libxml2 installation.
+   
 ============================================================================*/
 
 #define _BSD_SOURCE  /* Make sure strdup() is in <string.h> */
@@ -205,7 +216,16 @@ makePoint(unsigned int const x,
     return p;
 }
 
+static ppmd_point
+makePpmdPoint(point const arg) {
+
+    ppmd_point p;
 
+    p.x = arg.x;
+    p.y = arg.y;
+
+    return p;
+}
 
 typedef enum {
     PATH_MOVETO,
@@ -437,12 +457,12 @@ outlineObject(path *           const pathP,
                     pm_message("Doing cubic spline to (%u, %u)",
                                dest.x, dest.y);
                 /* We need to write ppmd_spline4() */
-                ppmd_spline4(NULL, 0, 0, 0,
-                             currentPos.x, currentPos.y,
-                             ctl1.x, ctl1.y,
-                             ctl2.x, ctl2.y,
-                             dest.x, dest.y,
-                             ppmd_fill_drawproc, fillObjP);
+                ppmd_spline4p(NULL, 0, 0, 0,
+                              makePpmdPoint(currentPos),
+                              makePpmdPoint(dest),
+                              makePpmdPoint(ctl1),
+                              makePpmdPoint(ctl2),
+                              ppmd_fill_drawprocp, fillObjP);
                 currentPos = dest;
             } break;
             }
@@ -562,6 +582,8 @@ static void
 processSubPathNode(xmlTextReaderPtr const xmlReaderP,
                    bool *           const endOfPathP) {
 
+    /* See comment above about xmlReaderTypes not being defined */
+
     xmlReaderTypes const nodeType  = xmlTextReaderNodeType(xmlReaderP);
 
     *endOfPathP = FALSE;  /* initial assumption */
diff --git a/converter/other/tiff.c b/converter/other/tiff.c
index a498571b..90d50710 100644
--- a/converter/other/tiff.c
+++ b/converter/other/tiff.c
@@ -6,6 +6,8 @@
 
 ============================================================================*/
 
+#define _BSD_SOURCE    /* Make sure strcaseeq() is in nstring.h */
+
 #include <string.h>
 
 #ifdef VMS
@@ -40,7 +42,7 @@ number(const char * const value,
         /* It's not a numeric string, so it must be an enumerated value name */
         unsigned int i;
         for (i = 0; tagvallist[i].name; ++i) {
-            if (STRCASEEQ(value, tagvallist[i].name))
+            if (strcaseeq(value, tagvallist[i].name))
                 return tagvallist[i].value;
         }
         pm_error("'%s' is neither a number nor a valid value name", value);
@@ -460,7 +462,7 @@ tagDefFind(const char * const name) {
     for (i = 0;
          i < ARRAY_SIZE(tagDefinitions) && tagDefinitions[i].name;
          ++i) {
-        if (STRCASEEQ(tagDefinitions[i].name, name))
+        if (strcaseeq(tagDefinitions[i].name, name))
             return &tagDefinitions[i];
     }
 
diff --git a/converter/other/tifftopnm.c b/converter/other/tifftopnm.c
index 5969a49a..6665c7fd 100644
--- a/converter/other/tifftopnm.c
+++ b/converter/other/tifftopnm.c
@@ -49,11 +49,16 @@
 #define _BSD_SOURCE 1      /* Make sure strdup() is in string.h */
 #define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
 
+#include <assert.h>
 #include <string.h>
-#include "pnm.h"
+#include <stdio.h>
+#include <sys/wait.h>
+
+#include "pm_c_util.h"
 #include "shhopt.h"
 #include "mallocvar.h"
 #include "nstring.h"
+#include "pnm.h"
 
 #ifdef VMS
 #ifdef SYSV
@@ -90,13 +95,14 @@ struct cmdlineInfo {
     bool alphaStdout;
     unsigned int respectfillorder;   /* -respectfillorder option */
     unsigned int byrow;
+    unsigned int orientraw;
     unsigned int verbose;
 };
 
 
 
 static void
-parseCommandLine(int argc, char ** argv,
+parseCommandLine(int argc, const char ** const argv,
                  struct cmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that many of the strings that this function returns in the
@@ -122,12 +128,14 @@ parseCommandLine(int argc, char ** argv,
             OPT_FLAG,   NULL, &cmdlineP->respectfillorder,     0);
     OPTENT3(0,   "byrow",   
             OPT_FLAG,   NULL, &cmdlineP->byrow,                0);
+    OPTENT3(0,   "orientraw",   
+            OPT_FLAG,   NULL, &cmdlineP->orientraw,            0);
     OPTENT3('h', "headerdump", 
             OPT_FLAG,   NULL, &cmdlineP->headerdump,           0);
     OPTENT3(0,   "alphaout",   
             OPT_STRING, &cmdlineP->alphaFilename, &alphaSpec,  0);
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
 
     if (argc - 1 == 0)
         cmdlineP->inputFilename = strdup("-");  /* he wants stdin */
@@ -138,7 +146,7 @@ parseCommandLine(int argc, char ** argv,
                  "is the input file name");
 
     if (alphaSpec) {
-        if (STREQ(cmdlineP->alphaFilename, "-"))
+        if (streq(cmdlineP->alphaFilename, "-"))
             cmdlineP->alphaStdout = TRUE;
         else
             cmdlineP->alphaStdout = FALSE;
@@ -150,16 +158,109 @@ parseCommandLine(int argc, char ** argv,
 
 
 
+static void
+getBps(TIFF *           const tif,
+       unsigned short * const bpsP) {
+
+    unsigned short tiffBps;
+    unsigned short bps;
+    int rc;
+
+    rc = TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &tiffBps);
+    bps = (rc == 0) ? 1 : tiffBps;
+
+    if (bps < 1 || (bps > 8 && bps != 16 && bps != 32))
+        pm_error("This program can process Tiff images with only "
+                 "1-8 or 16 bits per sample.  The input Tiff image "
+                 "has %hu bits per sample.", bps);
+    else
+        *bpsP = bps;
+}
+
+
+
+struct tiffDirInfo {
+    /* 'width' and 'height' are the dimensions of the raster matrix in
+       the TIFF stream -- what the TIFF spec calls the image.  The
+       dimensions of the actual visual image represented may be the
+       reverse, because the raster can represent the visual image in
+       various orientations, as described by 'orientation'.
+    */
+    unsigned int   width;
+    unsigned int   height;
+    unsigned short bps;
+    unsigned short spp;
+    unsigned short photomet;
+    unsigned short planarconfig;
+    unsigned short fillorder;
+    unsigned short orientation;
+};
+
+
+
+static void
+tiffToImageDim(unsigned int   const tiffCols,
+               unsigned int   const tiffRows,
+               unsigned short const orientation,
+               unsigned int * const imageColsP,
+               unsigned int * const imageRowsP) {
+
+    switch (orientation) {
+    case ORIENTATION_TOPLEFT:
+    case ORIENTATION_TOPRIGHT:
+    case ORIENTATION_BOTRIGHT:
+    case ORIENTATION_BOTLEFT:
+        *imageColsP = tiffCols;
+        *imageRowsP = tiffRows;
+        break;
+    case ORIENTATION_LEFTTOP:
+    case ORIENTATION_RIGHTTOP:
+    case ORIENTATION_RIGHTBOT:
+    case ORIENTATION_LEFTBOT:
+        *imageColsP = tiffRows;
+        *imageRowsP = tiffCols;
+        break;
+    default:
+        pm_error("Invalid value for orientation tag in TIFF directory: %u",
+                 orientation);
+    }
+}
+
+static void
+getTiffDimensions(TIFF *         const tiffP,
+                  unsigned int * const colsP,
+                  unsigned int * const rowsP) {
+/*----------------------------------------------------------------------------
+   Return the dimensions of the image represented by *tiffP.  Not the
+   dimensions of the internal raster matrix -- the dimensions of the
+   actual visual image.
+-----------------------------------------------------------------------------*/
+    int ok;
+
+    unsigned int width, length;
+    unsigned short tiffOrientation;
+    unsigned short orientation;
+    int present;
+
+    ok = TIFFGetField(tiffP, TIFFTAG_IMAGEWIDTH, &width);
+    if (!ok)
+        pm_error("Input Tiff file is invalid.  It has no IMAGEWIDTH tag.");
+    ok = TIFFGetField(tiffP, TIFFTAG_IMAGELENGTH, &length);
+    if (!ok)
+        pm_error("Input Tiff file is invalid.  It has no IMAGELENGTH tag.");
+
+    present = TIFFGetField(tiffP, TIFFTAG_ORIENTATION, &tiffOrientation);
+    orientation = present ? tiffOrientation : ORIENTATION_TOPLEFT;
+
+    tiffToImageDim(width, length, orientation, colsP, rowsP);
+}
+
+
+
 static void 
-read_directory(TIFF * const tif,
-               unsigned short * const bps_p,
-               unsigned short * const spp_p,
-               unsigned short * const photomet_p,
-               unsigned short * const planarconfig_p,
-               unsigned short * const fillorder_p,
-               unsigned int *   const cols_p,
-               unsigned int *   const rows_p,
-               bool             const headerdump) {
+readDirectory(TIFF *               const tiffP,
+              bool                 const headerdump,
+              struct tiffDirInfo * const headerP) {
 /*----------------------------------------------------------------------------
    Read various values of TIFF tags from the TIFF directory, and
    default them if not in there and make guesses where values are
@@ -173,68 +274,71 @@ read_directory(TIFF * const tif,
    invalid values to our caller.
 -----------------------------------------------------------------------------*/
     int rc;
-    unsigned short tiff_bps;
-    unsigned short tiff_spp;
+    unsigned short tiffSpp;
 
     if (headerdump)
-        TIFFPrintDirectory(tif, stderr, TIFFPRINT_NONE);
+        TIFFPrintDirectory(tiffP, stderr, TIFFPRINT_NONE);
 
-    rc = TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &tiff_bps);
-    *bps_p = (rc == 0) ? 1 : tiff_bps;
+    getBps(tiffP, &headerP->bps);
 
-    if (*bps_p < 1 || (*bps_p > 8 && *bps_p != 16 && *bps_p != 32))
-        pm_error("This program can process Tiff images with only "
-                 "1-8 or 16 bits per sample.  The input Tiff image "
-                 "has %d bits per sample.", *bps_p);
+    rc = TIFFGetFieldDefaulted(tiffP, TIFFTAG_FILLORDER, &headerP->fillorder);
+    rc = TIFFGetField(tiffP, TIFFTAG_SAMPLESPERPIXEL, &tiffSpp);
+    headerP->spp = (rc == 0) ? 1 : tiffSpp;
 
-    rc = TIFFGetFieldDefaulted(tif, TIFFTAG_FILLORDER, fillorder_p);
-    rc = TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &tiff_spp);
-    *spp_p = (rc == 0) ? 1: tiff_spp;
-
-    rc = TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, photomet_p);
+    rc = TIFFGetField(tiffP, TIFFTAG_PHOTOMETRIC, &headerP->photomet);
     if (rc == 0)
         pm_error("PHOTOMETRIC tag is not in Tiff file.  "
                  "TIFFGetField() of it failed.\n"
                  "This means the input is not valid Tiff.");
 
-    if (*spp_p > 1) {
-        rc = TIFFGetField(tif, TIFFTAG_PLANARCONFIG, planarconfig_p);
+    if (headerP->spp > 1) {
+        rc = TIFFGetField(tiffP, TIFFTAG_PLANARCONFIG, &headerP->planarconfig);
         if (rc == 0)
             pm_error("PLANARCONFIG tag is not in Tiff file, though it "
                      "has more than one sample per pixel.  "
                      "TIFFGetField() of it failed.  This means the input "
                      "is not valid Tiff.");
-    } else {
-        *planarconfig_p = PLANARCONFIG_CONTIG;
-    }
+    } else
+        headerP->planarconfig = PLANARCONFIG_CONTIG;
 
-    switch(*planarconfig_p) {
+    switch (headerP->planarconfig) {
     case PLANARCONFIG_CONTIG:
         break;
     case PLANARCONFIG_SEPARATE:
-        if (*photomet_p != PHOTOMETRIC_RGB && 
-            *photomet_p != PHOTOMETRIC_SEPARATED)
+        if (headerP->photomet != PHOTOMETRIC_RGB && 
+            headerP->photomet != PHOTOMETRIC_SEPARATED)
             pm_error("This program can handle separate planes only "
-                     "with RGB (PHOTOMETRIC tag = %d) or SEPARATED "
-                     "(PHOTOMETRIC tag = %d) data.  The input Tiff file " 
-                     "has PHOTOMETRIC tag = %d.",
-                     PHOTOMETRIC_RGB, PHOTOMETRIC_SEPARATED, *photomet_p);
+                     "with RGB (PHOTOMETRIC tag = %u) or SEPARATED "
+                     "(PHOTOMETRIC tag = %u) data.  The input Tiff file " 
+                     "has PHOTOMETRIC tag = %hu.",
+                     PHOTOMETRIC_RGB, PHOTOMETRIC_SEPARATED,
+                     headerP->photomet);
         break;
     default:
-        pm_error("Unrecognized PLANARCONFIG tag value in Tiff input: %d.\n",
-                 *planarconfig_p);
+        pm_error("Unrecognized PLANARCONFIG tag value in Tiff input: %u.\n",
+                 headerP->planarconfig);
     }
 
-    rc = TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, cols_p);
+    rc = TIFFGetField(tiffP, TIFFTAG_IMAGEWIDTH, &headerP->width);
     if (rc == 0)
         pm_error("Input Tiff file is invalid.  It has no IMAGEWIDTH tag.");
-    rc = TIFFGetField( tif, TIFFTAG_IMAGELENGTH, rows_p );
+    rc = TIFFGetField(tiffP, TIFFTAG_IMAGELENGTH, &headerP->height);
     if (rc == 0)
         pm_error("Input Tiff file is invalid.  It has no IMAGELENGTH tag.");
 
+    {
+        unsigned short tiffOrientation;
+        int present;
+        present = TIFFGetField(tiffP, TIFFTAG_ORIENTATION, &tiffOrientation);
+        headerP->orientation =
+            present ? tiffOrientation : ORIENTATION_TOPLEFT;
+    }
     if (headerdump) {
-        pm_message( "%dx%dx%d image", *cols_p, *rows_p, *bps_p * *spp_p );
-        pm_message( "%d bits/sample, %d samples/pixel", *bps_p, *spp_p );
+        pm_message("%ux%ux%u raster matrix, oriented %u",
+                   headerP->width, headerP->height,
+                   headerP->bps * headerP->spp, headerP->orientation);
+        pm_message("%hu bits/sample, %hu samples/pixel",
+                   headerP->bps, headerP->spp);
     }
 }
 
@@ -260,17 +364,18 @@ readscanline(TIFF *         const tif,
    a Tiff scanline.
 -----------------------------------------------------------------------------*/
     int rc;
-    const unsigned int bpsmask = (1 << bps) - 1;
+    unsigned int const bpsmask = (1 << bps) - 1;
       /* A mask for taking the lowest 'bps' bits of a number */
 
     /* The TIFFReadScanline man page doesn't tell the format of its
        'buf' return value, but it is exactly the same format as the 'buf'
        input to TIFFWriteScanline.  The man page for that doesn't say 
-       anything either, but the source code for Pnmtotiff contains a
+       anything either, but the source code for Pamtotiff contains a
        specification.
     */
 
     rc = TIFFReadScanline(tif, scanbuf, row, plane);
+
     if (rc < 0)
         pm_error( "Unable to read row %d, plane %d of input Tiff image.  "
                   "TIFFReadScanline() failed.",
@@ -291,7 +396,7 @@ readscanline(TIFF *         const tif,
 
         for (sample = 0, bitsleft=8, inP=scanbuf; 
              sample < cols*spp; 
-             sample++) {
+             ++sample) {
             if (bitsleft == 0) {
                 ++inP; 
                 bitsleft = 8;
@@ -322,7 +427,7 @@ readscanline(TIFF *         const tif,
            bytes of each sample appear in a TIFF file, which is
            contrary to the TIFF spec.  
         */
-        uint16 * const scanbuf16 = (uint16 *) scanbuf;
+        const uint16 * const scanbuf16 = (const uint16 *) scanbuf;
         unsigned int sample;
 
         for (sample = 0; sample < cols*spp; ++sample)
@@ -547,6 +652,442 @@ analyzeImageType(TIFF *             const tif,
 
 
 
+typedef struct {
+    FILE *       imageoutFileP;
+        /* The stream to which we write the PNM image.  Null for none. */
+    FILE *       alphaFileP;
+        /* The stream to which we write the alpha channel.  Null for none. */
+    unsigned int inCols;
+        /* Width of each row that gets passed to this object */
+    unsigned int inRows;
+        /* Number of rows that get passed to this object */
+    unsigned int outCols;
+        /* Width of each row this object writes out to the file */
+    unsigned int outRows;
+        /* Number of rows this object writes out */
+    xelval       maxval;
+        /* Maxval of the output image */
+    int          format;
+        /* Format of the output image */
+    gray         alphaMaxval;
+        /* Maxval of the alpha channel */
+    bool         flipping;
+        /* We're passing rows through a Pamflip process, rather than writing
+           them directly to *imageoutFileP, *alphaFileP.
+        */
+    FILE *       imagePipeP;
+        /* Stream hooked up to pipe that goes to a Pamflip process.
+           Meaningful only when 'flipping' is true.
+        */
+    FILE *       alphaPipeP;
+        /* Stream hooked up to pipe that goes to a Pamflip process.
+           Meaningful only when 'flipping' is true.
+        */
+    pid_t        imageFlipPid;
+        /* Process ID of the Pamflip process.
+           Meaningful only when 'flipping' is true.
+        */
+    pid_t        alphaFlipPid;
+        /* Process ID of the Pamflip process.
+           Meaningful only when 'flipping' is true.
+        */
+} pnmOut;
+
+
+
+static const char *
+xformNeeded(unsigned short const tiffOrientation) {
+/*----------------------------------------------------------------------------
+   Return the value of the Pamflip -xform option that causes Pamflip
+   to change a raster from orienation 'tiffOrientation' to Row 0 top,
+   Column 0 left.
+-----------------------------------------------------------------------------*/
+    switch (tiffOrientation) {
+    case ORIENTATION_TOPLEFT:  return "";
+    case ORIENTATION_TOPRIGHT: return "leftright";
+    case ORIENTATION_BOTRIGHT: return "topbottom,leftright";
+    case ORIENTATION_BOTLEFT:  return "topbottom";
+    case ORIENTATION_LEFTTOP:  return "transpose";
+    case ORIENTATION_RIGHTTOP: return "transpose,leftright";
+    case ORIENTATION_RIGHTBOT: return "transpose,topbottom,leftright";
+    case ORIENTATION_LEFTBOT:  return "transpose,topbottom";
+    default:
+        pm_error("Invalid value for orientation tag in TIFF directory: %u",
+                 tiffOrientation);
+        return "";
+    }
+}
+
+
+
+/* File descriptors array indices for use with pipe() */
+#define PIPE_READ 0
+#define PIPE_WRITE 1
+
+static void
+spawnWithInputPipe(const char *  const shellCmd,
+                   FILE **       const pipePP,
+                   pid_t *       const pidP,
+                   const char ** const errorP) {
+
+    int fd[2];
+    int rc;
+
+    rc = pipe(fd);
+
+    if (rc != 0)
+        asprintfN(errorP, "Failed to create pipe for process input.  "
+                  "Errno=%d (%s)", errno, strerror(errno));
+    else {
+        int rc;
+
+        rc = fork();
+
+        if (rc < 0) {
+            asprintfN(errorP, "Failed to fork a process.  errno=%d (%s)",
+                      errno, strerror(errno));
+        } else if (rc == 0) {
+            /* This is the child */
+            int rc;
+            close(fd[PIPE_WRITE]);
+            close(STDIN_FILENO);
+            dup2(fd[PIPE_READ], STDIN_FILENO);
+
+            rc = system(shellCmd);
+
+            exit(rc);
+        } else {
+            /* Parent */
+            pid_t const childPid = rc;
+
+            close(fd[PIPE_READ]);
+
+            *pidP   = childPid;
+            *pipePP = fdopen(fd[PIPE_WRITE], "w");
+
+            if (*pipePP == NULL)
+                asprintfN(errorP,"Unable to create stream from pipe.  "
+                          "fdopen() fails with errno=%d (%s)",
+                          errno, strerror(errno));
+            else
+                *errorP = NULL;
+        }
+    }
+}
+
+                  
+
+static void
+createFlipProcess(FILE *         const outFileP,
+                  unsigned short const orientation,
+                  bool           const verbose,
+                  FILE **        const inPipePP,
+                  pid_t *        const pidP) {
+/*----------------------------------------------------------------------------
+   Create a process that runs the program Pamflip and writes its output
+   to *imageoutFileP.
+
+   The process takes it input from a pipe that we create.  We return as
+   *inPipePP a file stream connected to the other end of that pipe.
+
+   I.e. Caller will write a Netpbm file stream to **inPipePP and a flipped
+   version of it will go to *outFileP.
+
+   The flipping it does turns the input from orientation 'orientation'
+   to Netpbm orientation, i.e. raster row 0 top, raster column 0 left,
+   where the raster stream is divided into rows, with row 0 being first
+   in the stream, and column 0 being first within each row.
+
+   Caller must close *inPipePP when he is done.
+-----------------------------------------------------------------------------*/
+    const char * pamflipCmd;
+    const char * error;
+
+    /* Hooking up the process to the output stream is kind of tricky
+       because the stream (FILE *) is an entity local to this process.
+       We just assume that nothing in this process actually touches
+       the stream so that having the process write to the underlying
+       file descriptor is equivalent to writing to the stream.
+    */
+
+    asprintfN(&pamflipCmd, "pamflip -xform=%s >&%u",
+              xformNeeded(orientation), fileno(outFileP));
+
+    if (verbose)
+        pm_message("Reorienting raster with shell command '%s'", pamflipCmd);
+
+    spawnWithInputPipe(pamflipCmd, inPipePP, pidP, &error);
+
+    if (error) {
+        pm_error("Shell command '%s', to reorient the TIFF "
+                 "raster, failed.  %s.  To work around this, you can use "
+                 "the -orientraw option.", pamflipCmd, error);
+
+        strfree(error);
+    }
+}
+
+
+
+static void
+setupFlipper(pnmOut *       const pnmOutP,
+             unsigned short const orientation,
+             bool           const flipIfNeeded,
+             bool           const orientraw,
+             bool           const verbose,
+             bool *         const flipOkP,
+             bool *         const noflipOkP) {
+/*----------------------------------------------------------------------------
+   Set up the Pamflip processes to flip the raster, where needed.
+
+   Whether we need a Pamflip process is a complex decision.  For
+   reasons of efficiency and robustness, we don't want one unless
+   flipping is actually required.  Flipping is not required if the
+   TIFF image is already oriented like a PNM.  It also isn't required
+   if the user explicitly asks for raw orientation.  Finally, it's not
+   required when the user is using the TIFF library whole-image
+   conversion services, because they do the flipping and thus the
+   'pnmOut' object will see properly oriented pixels as input.
+
+   'flipIfNeeded' says to set up the flipping pipe if 'orientation'
+   indicates something other than standard PNM orientation.
+
+   'orientation' is the orientation of the TIFF raster.
+
+   'orientraw' says the final output should be in the same
+   orientation, 'orientation', not the proper PNM orientation.
+
+   *flipOkP means that as we set up the pnmOut object,
+   it is OK if Caller flips the raster on his own.  *noflipOk means
+   is is OK if Caller does not flip the raster on his own.  Note
+   that they are both true if the raster is already in the PNM
+   orientation, because then flipping is idempotent.
+-----------------------------------------------------------------------------*/
+
+    if (orientation == ORIENTATION_TOPLEFT) {
+        /* Ah, the easy case.  Flipping and not flipping are identical,
+           so none of the other parameters matter.  Just write directly
+           to the output file and let Caller flip or not flip as he
+           wishes.
+        */
+        pnmOutP->flipping = FALSE;
+        *flipOkP   = TRUE;
+        *noflipOkP = TRUE;
+    } else {
+        if (orientraw) {
+            /* Raster is not to be flipped, so go directly to file,
+               and tell Caller not to flip it either.
+            */
+            pnmOutP->flipping = FALSE;
+            *flipOkP   = FALSE;
+            *noflipOkP = TRUE;
+        } else {            
+            if (flipIfNeeded) {
+                if (verbose)
+                    pm_message("Transforming raster with Pamflip");
+
+                if (pnmOutP->alphaFileP)
+                    createFlipProcess(pnmOutP->alphaFileP, orientation,
+                                      verbose,
+                                      &pnmOutP->alphaPipeP,
+                                      &pnmOutP->alphaFlipPid);
+                if (pnmOutP->imageoutFileP)
+                    createFlipProcess(pnmOutP->imageoutFileP, orientation,
+                                      verbose,
+                                      &pnmOutP->imagePipeP,
+                                      &pnmOutP->imageFlipPid);
+                
+                /* The stream will flip it, so Caller must not: */
+                pnmOutP->flipping = TRUE;
+                *flipOkP   = FALSE;
+                *noflipOkP = TRUE;
+            } else {
+                /* It needs flipping, but Caller doesn't want us to do it.
+                   So Caller must do it:
+                */
+                pnmOutP->flipping = FALSE;
+                *flipOkP   = TRUE;
+                *noflipOkP = FALSE;
+            }
+        }
+    }
+}
+
+
+
+static void
+computeOutputDimensions(unsigned int       const tiffCols,
+                        unsigned int       const tiffRows,
+                        unsigned short     const orientation,
+                        bool               const orientraw,
+                        unsigned int *     const colsP,
+                        unsigned int *     const rowsP,
+                        bool               const verbose) {
+/*----------------------------------------------------------------------------
+   Compute the dimensions of the image.  We're talking about the
+   actual image, not what the TIFF spec calls the image.  What the
+   TIFF spec calls the image is matrix of pixels within the TIFF file.
+   That matrix can represent the actual image in various ways.
+   E.g. the first row of the matrix might be the right edge of the
+   image.
+
+   'tiffCols' and 'tiffRows' are the images of the TIFF matrix and
+   'orientation' is the orientation of that matrix.
+
+   'orientraw' says we want to output the matrix in its natural
+   orientation, not the true image.
+-----------------------------------------------------------------------------*/
+    if (orientraw) {
+        *colsP = tiffCols;
+        *rowsP = tiffRows;
+    } else
+        tiffToImageDim(tiffCols, tiffRows, orientation, colsP, rowsP);
+
+    if (verbose)
+        pm_message("Generating %uw x %uh PNM image", *colsP, *rowsP);
+}
+
+
+
+static void
+pnmOut_init(FILE *         const imageoutFileP,
+            FILE *         const alphaFileP,
+            unsigned int   const cols,
+            unsigned int   const rows,
+            unsigned short const orientation,
+            xelval         const maxval,
+            int            const format,
+            gray           const alphaMaxval,
+            bool           const flipIfNeeded,
+            bool           const orientraw,
+            bool           const verbose,
+            bool *         const flipOkP,
+            bool *         const noflipOkP,
+            pnmOut *       const pnmOutP) {
+/*----------------------------------------------------------------------------
+   'cols' and 'rows' are the dimensions of the raster matrix which is
+   oriented according to 'orientation' with respect to the image.
+
+   If the user flips the data before giving it to the pnmOut object,
+   pnmOut may see the inverse dimensions; if the pnmOut object flips the
+   data, pnmOut get 'cols' x 'rows' data, but its output file may be
+   'rows x cols'.
+
+   Because the pnmOut object must be set up to receive flipped or not
+   flipped input, we have *flipOkP and *noflipOkP outputs that tell
+   Caller whether he has to flip or not.  In the unique case that
+   the TIFF matrix is already oriented the way the output PNM file needs
+   to be, flipping is idempotent, so both *flipOkP and *noflipOkP are
+   true.
+-----------------------------------------------------------------------------*/
+    pnmOutP->imageoutFileP = imageoutFileP;
+    pnmOutP->alphaFileP    = alphaFileP;
+    pnmOutP->maxval        = maxval;
+    pnmOutP->format        = format;
+    pnmOutP->alphaMaxval   = alphaMaxval;
+
+    setupFlipper(pnmOutP, orientation, flipIfNeeded, orientraw, verbose,
+                 flipOkP, noflipOkP);
+
+    computeOutputDimensions(cols, rows, orientation, orientraw,
+                            &pnmOutP->outCols, &pnmOutP->outRows, verbose);
+
+    if (pnmOutP->flipping) {
+        pnmOutP->inCols = cols;         /* Caller won't flip */
+        pnmOutP->inRows = rows;
+    } else {
+        pnmOutP->inCols = pnmOutP->outCols;  /* Caller will flip */
+        pnmOutP->inRows = pnmOutP->outRows;
+    }    
+    if (pnmOutP->flipping) {
+        if (pnmOutP->imagePipeP != NULL) 
+            pnm_writepnminit(pnmOutP->imagePipeP,
+                             pnmOutP->inCols, pnmOutP->inRows,
+                             pnmOutP->maxval, pnmOutP->format, 0);
+        if (pnmOutP->alphaPipeP != NULL) 
+            pgm_writepgminit(pnmOutP->alphaPipeP,
+                             pnmOutP->inCols, pnmOutP->inRows,
+                             pnmOutP->alphaMaxval, 0);
+    } else {
+        if (imageoutFileP != NULL) 
+            pnm_writepnminit(pnmOutP->imageoutFileP,
+                             pnmOutP->outCols, pnmOutP->outRows,
+                             pnmOutP->maxval, pnmOutP->format, 0);
+        if (alphaFileP != NULL) 
+            pgm_writepgminit(pnmOutP->alphaFileP,
+                             pnmOutP->outCols, pnmOutP->outRows,
+                             pnmOutP->alphaMaxval, 0);
+    }
+}
+
+
+
+static void
+pnmOut_term(pnmOut * const pnmOutP,
+            bool     const verbose) {
+
+    if (pnmOutP->flipping) {
+        /* Closing the pipes also causes the Pamflip processes to terminate
+           and they consequently flush their output to pnmOutP->imageoutFileP
+           and pnmOutP->alphaFileP and close those file descriptors.
+
+           We wait for the processes to exit before returning so that we
+           know everything is flushed, so the invoker of Tifftopnm is free
+           to use its output.
+        */
+        if (verbose)
+            pm_message("Flushing data through Pamflip process, "
+                       "waiting for Pamflip to terminate");
+
+        if (pnmOutP->imagePipeP) {
+            int status;
+            fclose(pnmOutP->imagePipeP);
+            waitpid(pnmOutP->imageFlipPid, &status, 0);
+        }
+        if (pnmOutP->alphaPipeP) {
+            int status;
+            fclose(pnmOutP->alphaPipeP);
+            waitpid(pnmOutP->alphaFlipPid, &status, 0);
+        }
+    } else {
+        if (pnmOutP->imageoutFileP)
+            fflush(pnmOutP->imageoutFileP);
+        if (pnmOutP->alphaFileP)
+            fflush(pnmOutP->alphaFileP);
+    }
+}
+
+
+
+static void
+pnmOut_writeRow(pnmOut *     const pnmOutP,
+                unsigned int const cols,
+                const xel *  const imageRow,
+                const gray * const alphaRow) {
+
+    assert(cols == pnmOutP->inCols);
+
+    if (pnmOutP->flipping) {
+        if (pnmOutP->imagePipeP != NULL) 
+            pnm_writepnmrow(pnmOutP->imagePipeP, (xel *)imageRow,
+                            pnmOutP->inCols, pnmOutP->maxval,
+                            pnmOutP->format, 0);
+        if (pnmOutP->alphaPipeP != NULL) 
+            pgm_writepgmrow(pnmOutP->alphaPipeP, alphaRow,
+                            pnmOutP->inCols, pnmOutP->alphaMaxval, 0);
+    } else {
+        if (pnmOutP->imageoutFileP != NULL) 
+            pnm_writepnmrow(pnmOutP->imageoutFileP, (xel *)imageRow,
+                            pnmOutP->outCols, pnmOutP->maxval,
+                            pnmOutP->format, 0);
+        if (pnmOutP->alphaFileP != NULL) 
+            pgm_writepgmrow(pnmOutP->alphaFileP, alphaRow,
+                            pnmOutP->outCols, pnmOutP->alphaMaxval, 0);
+    }
+}
+
+
+
 static void
 convertRow(unsigned int   const samplebuf[], 
            xel                  xelrow[], 
@@ -706,19 +1247,18 @@ convertMultiPlaneRow(TIFF *         const tif,
 
 
 static void
-convertRasterByRows(FILE *         const imageoutFile, 
-                    FILE *         const alphaFile,
+convertRasterByRows(pnmOut *       const pnmOutP,
                     unsigned int   const cols, 
                     unsigned int   const rows,
                     xelval         const maxval,
-                    int            const format, 
                     TIFF *         const tif,
                     unsigned short const photomet, 
                     unsigned short const planarconfig,
                     unsigned short const bps,
                     unsigned short const spp,
                     unsigned short const fillorder,
-                    xel                  colormap[]) {
+                    xel            const colormap[],
+                    bool           const verbose) {
 /*----------------------------------------------------------------------------
    With the TIFF header all processed (and relevant information from it in 
    our arguments), write out the TIFF raster to the file images *imageoutFile
@@ -735,27 +1275,30 @@ convertRasterByRows(FILE *         const imageoutFile,
         /* Same info as 'scanbuf' above, but with each raster column (sample)
            represented as single array element, so it's easy to work with.
         */
-    xel* xelrow;
+    xel * xelrow;
         /* The ppm-format row of the image row we are presently converting */
-    gray* alpharow;
+    gray * alpharow;
         /* The pgm-format row representing the alpha values for the image 
            row we are presently converting.
         */
 
     int row;
 
+    if (verbose)
+        pm_message("Converting row by row ...");
+
     scanbuf = (unsigned char *) malloc(TIFFScanlineSize(tif));
     if (scanbuf == NULL)
         pm_error("can't allocate memory for scanline buffer");
 
     MALLOCARRAY(samplebuf, cols * spp);
     if (samplebuf == NULL)
-        pm_error ("can't allocate memory for row buffer");
+        pm_error("can't allocate memory for row buffer");
 
     xelrow = pnm_allocrow(cols);
     alpharow = pgm_allocrow(cols);
 
-    for ( row = 0; row < rows; ++row ) {
+    for (row = 0; row < rows; ++row) {
         /* Read one row of samples into samplebuf[] */
 
         if (planarconfig == PLANARCONFIG_CONTIG) {
@@ -769,12 +1312,8 @@ convertRasterByRows(FILE *         const imageoutFile,
             convertMultiPlaneRow(tif, xelrow, alpharow, cols, maxval, row,
                                  photomet, bps, spp, fillorder,
                                  scanbuf, samplebuf);
-            
-        if (imageoutFile != NULL) 
-            pnm_writepnmrow( imageoutFile, 
-                             xelrow, cols, (xelval) maxval, format, 0 );
-        if (alphaFile != NULL) 
-            pgm_writepgmrow( alphaFile, alpharow, cols, (gray) maxval, 0);
+
+        pnmOut_writeRow(pnmOutP, cols, xelrow, alpharow);
     }
     pgm_freerow(alpharow);
     pnm_freerow(xelrow);
@@ -785,38 +1324,81 @@ convertRasterByRows(FILE *         const imageoutFile,
 
 
 
+static void
+warnBrokenTiffLibrary(TIFF * const tiffP) {
+
+/* TIFF library bug:
+
+   In every version of the TIFF library we've seen, TIFFRGBAImageGet()
+   fails when the raster orientation (per the TIFF_ORIENTATION tag)
+   requires a transposition, e.g. ORIENTATION_LEFTBOT.  It simply omits
+   the transposition part, so e.g. it treats ORIENTATION_LEFTBOT as
+   ORIENTATION_BOTLEFT.  And because we provide a raster buffer dimensioned
+   for the properly transposed image, the result is somewhat of a mess.
+   
+   We have found no documentation of the TIFF library that suggests
+   this behavior is as designed, so it's probably not a good idea to
+   work around it; it might be fixed somewhere.
+
+   The user can of course work around just by using -byrow and therefore
+   not using TIFFRGBAImageGet().
+
+   There is some evidence of an interface in the TIFF library that
+   lets you request that TIFFRGBAImageGet() produce a raster in the
+   same orientation as the one in the TIFF image.
+   (tiff.req_orientation).  We could conceivably use that and then do
+   a Pamflip to get the proper orientation, but that somewhat defeats
+   the philosophy of using TIFFRGBAImageGet(), so I would like to wait
+   until there's a good practical reason to do it.
+*/
+
+    unsigned short tiffOrientation;
+    int present;
+    present = TIFFGetField(tiffP, TIFFTAG_ORIENTATION, &tiffOrientation);
+    if (present) {
+        switch (tiffOrientation) {
+        case ORIENTATION_LEFTTOP:
+        case ORIENTATION_RIGHTTOP:
+        case ORIENTATION_RIGHTBOT:
+        case ORIENTATION_LEFTBOT:
+            pm_message("WARNING: This TIFF image has an orientation that "
+                       "most TIFF libraries converts incorrectly.  "
+                       "Use -byrow to circumvent.");
+            break;
+        }
+    }
+}
+
+
 
 static void 
 convertTiffRaster(uint32 *        const raster, 
                   unsigned int    const cols,
                   unsigned int    const rows,
                   xelval          const maxval,
-                  int             const format,
-                  FILE *          const imageoutFile,
-                  FILE *          const alphaFile) {
+                  pnmOut *        const pnmOutP) {
 /*----------------------------------------------------------------------------
    Convert the raster 'raster' from the format generated by the TIFF library
    to PPM (plus PGM alpha mask where applicable) and output it to
-   the files *imageoutFile and *alphaFile in format 'format' with maxval
-   'maxval'.  The raster is 'cols' wide by 'rows' high.
+   the object *pnmOutP.  The raster is 'cols' wide by 'rows' high.
 -----------------------------------------------------------------------------*/
-    xel* xelrow;
+    xel * xelrow;
         /* The ppm-format row of the image row we are
            presently converting 
         */
-    gray* alpharow;
+    gray * alpharow;
         /* The pgm-format row representing the alpha values
            for the image row we are presently converting.  
         */
-    int row;
+    unsigned int row;
 
     xelrow = pnm_allocrow(cols);
     alpharow = pgm_allocrow(cols);
 
     for (row = 0; row < rows; ++row) {
-        uint32* rp;  
+        uint32 * rp;  
             /* Address of pixel in 'raster' we are presently converting */
-        int col;
+        unsigned int col;
 
         /* Start at beginning of row: */
         rp = raster + (rows - row - 1) * cols;
@@ -830,11 +1412,7 @@ convertTiffRaster(uint32 *        const raster,
                        TIFFGetB(tiffPixel) * maxval / 255);
             alpharow[col] = TIFFGetA(tiffPixel) * maxval / 255 ;
         }
-        
-        if (imageoutFile != NULL) 
-            pnm_writepnmrow(imageoutFile, xelrow, cols, maxval, format, 0);
-        if (alphaFile != NULL) 
-            pgm_writepgmrow(alphaFile, alpharow, cols, maxval, 0);
+        pnmOut_writeRow(pnmOutP, cols, xelrow, alpharow);
     }
     
     pgm_freerow(alpharow);
@@ -847,45 +1425,54 @@ enum convertDisp {CONV_DONE, CONV_OOM, CONV_UNABLE, CONV_FAILED,
                   CONV_NOTATTEMPTED};
 
 static void
-convertRasterInMemory(FILE *         const imageoutFile, 
-                      FILE *         const alphaFile,
-                      unsigned int   const cols, 
-                      unsigned int   const rows,
+convertRasterInMemory(pnmOut *       const pnmOutP,
                       xelval         const maxval,
-                      int            const format, 
                       TIFF *         const tif,
                       unsigned short const photomet, 
                       unsigned short const planarconfig,
                       unsigned short const bps,
                       unsigned short const spp,
                       unsigned short const fillorder,
-                      xel                  colormap[],
+                      xel            const colormap[],
+                      bool           const verbose,
                       enum convertDisp * const statusP) {
 /*----------------------------------------------------------------------------
-   With the TIFF header all processed (and relevant information from it in 
-   our arguments), write out the TIFF raster to the file images *imageoutFile
-   and *alphaFile.
+   With the TIFF header all processed (and relevant information from
+   it in our arguments), write out the TIFF raster to the file images
+   *imageoutFileP and *alphaFileP.
 
    Do this by reading the entire TIFF image into memory at once and formatting
    it with the TIFF library's TIFFRGBAImageGet().
 
+   'cols' and 'rows' are the dimensions of the actual image, not of the
+   TIFF raster matrix; ('tif' knows the TIFF raster matrix dimensions).
+
    Return *statusP == CONV_OOM iff we are unable to proceed because we cannot
    get memory to store the entire raster.  This means Caller may still be able
    to do the conversion using a row-by-row strategy.  Like typical Netpbm
    programs, we simply abort the program if we are unable to allocate
    memory for other things.
 -----------------------------------------------------------------------------*/
+    unsigned int cols, rows;  /* Dimensions of output image */
+
+    if (verbose)
+        pm_message("Converting in memory ...");
+
+    warnBrokenTiffLibrary(tif);
+
+    getTiffDimensions(tif, &cols, &rows);
+
     if (rows == 0 || cols == 0) 
         *statusP = CONV_DONE;
     else {
-        char emsg[1024] ;
+        char emsg[1024];
         int ok;
         ok = TIFFRGBAImageOK(tif, emsg);
         if (!ok) {
             pm_message(emsg);
             *statusP = CONV_UNABLE;
         } else {
-            uint32* raster ;
+            uint32 * raster;
 
             /* Note that TIFFRGBAImageGet() converts any bits per sample
                to 8.  Maxval of the raster it returns is always 255.
@@ -897,10 +1484,10 @@ convertRasterInMemory(FILE *         const imageoutFile,
                 *statusP = CONV_OOM;
             } else {
                 int const stopOnErrorFalse = FALSE;
-                TIFFRGBAImage img ;
+                TIFFRGBAImage img;
                 int ok;
                 
-                ok = TIFFRGBAImageBegin(&img, tif, stopOnErrorFalse, emsg) ;
+                ok = TIFFRGBAImageBegin(&img, tif, stopOnErrorFalse, emsg);
                 if (!ok) {
                     pm_message(emsg);
                     *statusP = CONV_FAILED;
@@ -913,8 +1500,7 @@ convertRasterInMemory(FILE *         const imageoutFile,
                         *statusP = CONV_FAILED;
                     } else {
                         *statusP = CONV_DONE;
-                        convertTiffRaster(raster, cols, rows, maxval, format, 
-                                          imageoutFile, alphaFile);
+                        convertTiffRaster(raster, cols, rows, maxval, pnmOutP);
                     }
                 } 
                 free(raster);
@@ -926,62 +1512,86 @@ convertRasterInMemory(FILE *         const imageoutFile,
 
 
 static void
+convertRaster(pnmOut *           const pnmOutP,
+              TIFF *             const tifP,
+              struct tiffDirInfo const tiffDir,
+              xelval             const maxval,
+              unsigned short     const fillorder,
+              const xel *        const colormap,
+              bool               const byrow,
+              bool               const flipOk,
+              bool               const noflipOk,
+              bool               const verbose) {
+
+    enum convertDisp status;
+    if (byrow || !flipOk)
+        status = CONV_NOTATTEMPTED;
+    else {
+        convertRasterInMemory(
+            pnmOutP, maxval,
+            tifP, tiffDir.photomet, tiffDir.planarconfig, 
+            tiffDir.bps, tiffDir.spp, fillorder,
+            colormap, verbose, &status);
+    }
+    if (status == CONV_DONE) {
+        if (tiffDir.bps > 8)
+            pm_message("actual resolution has been reduced to 24 bits "
+                       "per pixel in the conversion.  You can get the "
+                       "full %u bits that are in the TIFF with the "
+                       "-byrow option.", tiffDir.bps);
+    } else {
+        if (status != CONV_NOTATTEMPTED) {
+            pm_message("In-memory conversion failed; "
+                       "using more primitive row-by-row conversion.");
+
+            if (!noflipOk)
+                pm_error("TIFF raster is in nonstandard orientation, "
+                         "and we already committed to in-memory "
+                         "conversion.  To avoid this failure, "
+                         "use -byrow .");
+        }            
+        convertRasterByRows(
+            pnmOutP, tiffDir.width, tiffDir.height, maxval,
+            tifP, tiffDir.photomet, tiffDir.planarconfig,
+            tiffDir.bps, tiffDir.spp, fillorder, colormap, verbose);
+    }
+}
+
+
+
+static void
 convertImage(TIFF *             const tifP,
-             FILE *             const alphaFile, 
-             FILE *             const imageoutFile,
+             FILE *             const alphaFileP,
+             FILE *             const imageoutFileP,
              struct cmdlineInfo const cmdline) {
 
-    unsigned int cols, rows;
+    struct tiffDirInfo tiffDir;
     int format;
     xelval maxval;
-    unsigned short bps, spp;
-
     xel colormap[MAXCOLORS];
-    unsigned short photomet, planarconfig, fillorderTag;
     unsigned short fillorder;
+    bool flipOk, noflipOk;
+    pnmOut pnmOut;
 
-    read_directory(tifP, &bps, &spp, &photomet, &planarconfig, &fillorderTag,
-                   &cols, &rows, 
-                   cmdline.headerdump);
-
+    readDirectory(tifP, cmdline.headerdump, &tiffDir);
 
-    computeFillorder(fillorderTag, &fillorder, cmdline.respectfillorder);
+    computeFillorder(tiffDir.fillorder, &fillorder, cmdline.respectfillorder);
 
-    analyzeImageType(tifP, bps, spp, photomet, 
+    analyzeImageType(tifP, tiffDir.bps, tiffDir.spp, tiffDir.photomet, 
                      &maxval, &format, colormap, cmdline.headerdump, cmdline);
 
-    if (imageoutFile != NULL) 
-        pnm_writepnminit( imageoutFile, 
-                          cols, rows, (xelval) maxval, format, 0 );
-    if (alphaFile != NULL) 
-        pgm_writepgminit( alphaFile, cols, rows, (gray) maxval, 0 );
+    pnmOut_init(imageoutFileP, alphaFileP, tiffDir.width, tiffDir.height,
+                tiffDir.orientation, maxval, format, maxval,
+                cmdline.byrow, cmdline.orientraw,
+                cmdline.verbose,
+                &flipOk, &noflipOk,
+                &pnmOut);
 
-    {
-        enum convertDisp status;
-        if (cmdline.byrow)
-            status = CONV_NOTATTEMPTED;
-        else {
-            convertRasterInMemory(
-                imageoutFile, alphaFile, cols, rows, maxval, format, 
-                tifP, photomet, planarconfig, bps, spp, fillorder,
-                colormap, &status);
-        }
-        if (status == CONV_DONE) {
-            if (bps > 8)
-                pm_message("actual resolution has been reduced to 24 bits "
-                           "per pixel in the conversion.  You can get the "
-                           "full %u bits that are in the TIFF with the "
-                           "-byrow option.", bps);
-        } else {
-            if (status != CONV_NOTATTEMPTED)
-                pm_message("In-memory conversion failed; "
-                           "using more primitive row-by-row conversion.");
-            
-            convertRasterByRows(
-                imageoutFile, alphaFile, cols, rows, maxval, format, 
-                tifP, photomet, planarconfig, bps, spp, fillorder, colormap);
-        }
-    }
+    convertRaster(&pnmOut, tifP, tiffDir, maxval,
+                  fillorder, colormap, cmdline.byrow, flipOk, noflipOk,
+                  cmdline.verbose);
+
+    pnmOut_term(&pnmOut, cmdline.verbose);
 }
 
 
@@ -1013,18 +1623,18 @@ convertIt(TIFF *             const tifP,
 
 
 int
-main(int argc, char * argv[]) {
+main(int argc, const char * argv[]) {
 
     struct cmdlineInfo cmdline;
     TIFF * tif;
     FILE * alphaFile;
     FILE * imageoutFile;
 
-    pnm_init( &argc, argv );
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
-    if (!STREQ(cmdline.inputFilename, "-")) {
+    if (!streq(cmdline.inputFilename, "-")) {
         tif = TIFFOpen(cmdline.inputFilename, "r");
         if (tif == NULL)
             pm_error("error opening TIFF file %s", cmdline.inputFilename);
@@ -1056,7 +1666,6 @@ main(int argc, char * argv[]) {
     strfree(cmdline.inputFilename);
 
     /* If the program failed, it previously aborted with nonzero completion
-       code, via various function calls.
-    */
+       code, via various function calls.  */
     return 0;
 }
diff --git a/converter/other/x11wd.h b/converter/other/x11wd.h
index 711248f5..7161260b 100644
--- a/converter/other/x11wd.h
+++ b/converter/other/x11wd.h
@@ -27,7 +27,7 @@ enum visualclass {StaticGray=0,GrayScale=1,StaticColor=2,PseudoColor=3,
 #define DirectColor 5
 */
 
-typedef uint32n xwdval;
+typedef uint32_t xwdval;
 #define XWDVAL_MAX ((xwdval)(-1))
 #define X11WD_FILE_VERSION 7
 typedef struct {
@@ -67,13 +67,13 @@ typedef struct {
         */
     xwdval window_width;    /* Window width */
     xwdval window_height;   /* Window height */
-    int32n window_x;        /* Window upper left X coordinate */
-    int32n window_y;        /* Window upper left Y coordinate */
+    int32_t window_x;        /* Window upper left X coordinate */
+    int32_t window_y;        /* Window upper left Y coordinate */
     xwdval window_bdrwidth; /* Window border width */
     } X11WDFileHeader;
 
 typedef struct {
-    uint32n num;
+    uint32_t num;
     unsigned short red, green, blue;
     char flags;         /* do_red, do_green, do_blue */
     char pad;
diff --git a/converter/other/xwdtopnm.c b/converter/other/xwdtopnm.c
index 284d0204..2cf1d39b 100644
--- a/converter/other/xwdtopnm.c
+++ b/converter/other/xwdtopnm.c
@@ -14,6 +14,12 @@
 
    The file X11/XWDFile.h from the X Window System is an authority for the
    format of an XWD file.  Netpbm uses its own declaration, though.
+
+   It has been a real challenge trying to reverse engineer the XWD
+   format.  This program is almost always broken as people find XWD images
+   with which it does not work and we update the program in response.
+
+   We consider an XWD file correct if Xwud displays it properly.
 */
 
 
@@ -32,14 +38,22 @@
 #include "x10wd.h"
 #include "x11wd.h"
 
+struct compMask {
+    unsigned long red;
+    unsigned long grn;
+    unsigned long blu;
+};
+
+
 struct cmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    char *input_filename;
+    const char * inputFilename;
     unsigned int verbose;
     unsigned int debug;
     unsigned int headerdump;
+    unsigned int cmapdump;
 };
 
 
@@ -70,23 +84,6 @@ zero_bits(const unsigned long mask) {
 
 
 
-static int
-one_bits(const unsigned long input) {
-/*----------------------------------------------------------------------------
-   Return the number of one bits in the binary representation of 'input'.
------------------------------------------------------------------------------*/
-    int one_bits;
-    unsigned long mask;
-
-    one_bits = 0;   /* initial value */
-    for (mask = 0x00000001; mask != 0x00000000; mask <<= 1)
-        if (input & mask) one_bits++;
-
-    return(one_bits);
-}
-
-
-
 static void
 parseCommandLine(int argc, char ** argv,
                  struct cmdlineInfo * const cmdlineP) {
@@ -110,6 +107,7 @@ parseCommandLine(int argc, char ** argv,
     OPTENT3(0,   "verbose",    OPT_FLAG,   NULL, &cmdlineP->verbose,       0);
     OPTENT3(0,   "debug",      OPT_FLAG,   NULL, &cmdlineP->debug,         0);
     OPTENT3(0,   "headerdump", OPT_FLAG,   NULL, &cmdlineP->headerdump,    0);
+    OPTENT3(0,   "cmapdump",   OPT_FLAG,   NULL, &cmdlineP->cmapdump,      0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
@@ -119,12 +117,12 @@ parseCommandLine(int argc, char ** argv,
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (argc - 1 == 0)
-        cmdlineP->input_filename = NULL;  /* he wants stdin */
+        cmdlineP->inputFilename = NULL;  /* he wants stdin */
     else if (argc - 1 == 1) {
-        if (STREQ(argv[1], "-"))
-            cmdlineP->input_filename = NULL;  /* he wants stdin */
+        if (streq(argv[1], "-"))
+            cmdlineP->inputFilename = NULL;  /* he wants stdin */
         else 
-            cmdlineP->input_filename = strdup(argv[1]);
+            cmdlineP->inputFilename = strdup(argv[1]);
     } else 
         pm_error("Too many arguments.  The only argument accepted\n"
                  "is the input file specification");
@@ -137,16 +135,14 @@ processX10Header(X10WDFileHeader *  const h10P,
                  FILE *             const file,
                  int *              const colsP, 
                  int *              const rowsP, 
-                 int *              const padrightP, 
+                 unsigned int *     const padrightP, 
                  xelval *           const maxvalP, 
                  enum visualclass * const visualclassP, 
                  int *              const formatP, 
                  xel **             const colorsP, 
                  int *              const bits_per_pixelP, 
                  int *              const bits_per_itemP, 
-                 unsigned long *    const red_maskP, 
-                 unsigned long *    const green_maskP, 
-                 unsigned long *    const blue_maskP,
+                 struct compMask *  const compMaskP,
                  enum byteorder *   const byte_orderP,
                  enum byteorder *   const bit_orderP) {
 
@@ -155,9 +151,7 @@ processX10Header(X10WDFileHeader *  const h10P,
     bool grayscale;
     bool byte_swap;
 
-    *maxvalP = 65535;   /* Initial assumption */
-
-    if ( h10P->file_version != X10WD_FILE_VERSION ) {
+    if (h10P->file_version != X10WD_FILE_VERSION) {
         byte_swap = TRUE;
         h10P->header_size     = pm_bs_long(h10P->header_size);
         h10P->file_version    = pm_bs_long(h10P->file_version);
@@ -175,51 +169,53 @@ processX10Header(X10WDFileHeader *  const h10P,
     } else
         byte_swap = FALSE;
 
-    for ( i = 0; i < h10P->header_size - sizeof(*h10P); ++i )
-        if ( getc( file ) == EOF )
-            pm_error( "couldn't read rest of X10 XWD file header" );
+    for (i = 0; i < h10P->header_size - sizeof(*h10P); ++i)
+        if (getc(file) == EOF)
+            pm_error("couldn't read rest of X10 XWD file header");
 
     /* Check whether we can handle this dump. */
-    if ( h10P->window_ncolors > 256 )
-        pm_error( "can't handle X10 window_ncolors > %d", 256 );
-    if ( h10P->pixmap_format != ZFormat && h10P->display_planes != 1 )
-        pm_error(
-            "can't handle X10 pixmap_format %d with planes != 1",
-            h10P->pixmap_format );
+    if (h10P->window_ncolors > 256)
+        pm_error("can't handle X10 window_ncolors > %d", 256);
+    if (h10P->pixmap_format != ZFormat && h10P->display_planes != 1)
+        pm_error("can't handle X10 pixmap_format %d with planes != 1",
+                 h10P->pixmap_format);
 
     grayscale = TRUE;  /* initial assumption */
-    if ( h10P->window_ncolors != 0 ) {
+    if (h10P->window_ncolors != 0) {
         /* Read X10 colormap. */
-        MALLOCARRAY( x10colors, h10P->window_ncolors );
-        if ( x10colors == NULL )
-            pm_error( "out of memory" );
-        for ( i = 0; i < h10P->window_ncolors; ++i ) {
-            if ( fread( &x10colors[i], sizeof(X10Color), 1, file ) != 1 )
-                pm_error( "couldn't read X10 XWD colormap" );
-            if ( byte_swap ) {
+        MALLOCARRAY(x10colors, h10P->window_ncolors);
+        if (x10colors == NULL)
+            pm_error("out of memory");
+        for (i = 0; i < h10P->window_ncolors; ++i) {
+            size_t bytesRead;
+            bytesRead = fread(&x10colors[i], sizeof(X10Color), 1, file);
+            if (bytesRead != 1)
+                pm_error("couldn't read X10 XWD colormap");
+            if (byte_swap) {
                 x10colors[i].red   = pm_bs_short(x10colors[i].red);
                 x10colors[i].green = pm_bs_short(x10colors[i].green);
                 x10colors[i].blue  = pm_bs_short(x10colors[i].blue);
             }
-            if ( x10colors[i].red != x10colors[i].green ||
-                 x10colors[i].green != x10colors[i].blue )
+            if (x10colors[i].red != x10colors[i].green ||
+                x10colors[i].green != x10colors[i].blue)
                 grayscale = FALSE;
         }
     }
 
-    if ( h10P->display_planes == 1 ) {
+    if (h10P->display_planes == 1) {
         *formatP = PBM_TYPE;
         *visualclassP = StaticGray;
         *maxvalP = 1;
-        *colorsP = pnm_allocrow( 2 );
-        PNM_ASSIGN1( (*colorsP)[0], 0 );
-        PNM_ASSIGN1( (*colorsP)[1], *maxvalP );
+        *colorsP = pnm_allocrow(2);
+        PNM_ASSIGN1((*colorsP)[0], 0);
+        PNM_ASSIGN1((*colorsP)[1], *maxvalP);
         *padrightP =
             (((h10P->pixmap_width + 15) / 16) * 16 - h10P->pixmap_width) * 8;
         *bits_per_itemP = 16;
         *bits_per_pixelP = 1;
-    } else if ( h10P->window_ncolors == 0 ) { 
+    } else if (h10P->window_ncolors == 0) { 
         /* Must be grayscale. */
+        unsigned int i;
         *formatP = PGM_TYPE;
         *visualclassP = StaticGray;
         if (h10P->display_planes > sizeof(*maxvalP) * 8 - 1)
@@ -231,23 +227,27 @@ processX10Header(X10WDFileHeader *  const h10P,
             pm_error("XWD header says display_planes = %u, which is too "
                      "large for maximum maxval of %u",
                      h10P->display_planes, PNM_OVERALLMAXVAL);
-        *colorsP = pnm_allocrow( *maxvalP + 1 );
-        for ( i = 0; i <= *maxvalP; ++i )
-            PNM_ASSIGN1( (*colorsP)[i], i );
+        *colorsP = pnm_allocrow(*maxvalP + 1);
+        for (i = 0; i <= *maxvalP; ++i)
+            PNM_ASSIGN1((*colorsP)[i], i);
         *padrightP =
             (((h10P->pixmap_width + 15) / 16) * 16 - h10P->pixmap_width) * 8;
         *bits_per_itemP = 16;
         *bits_per_pixelP = 1;
     } else {
-        *colorsP = pnm_allocrow( h10P->window_ncolors );
+        *maxvalP = 65535;
+
+        *colorsP = pnm_allocrow(h10P->window_ncolors);
         *visualclassP = PseudoColor;
-        if ( grayscale ) {
+        if (grayscale) {
+            unsigned int i;
             *formatP = PGM_TYPE;
-            for ( i = 0; i < h10P->window_ncolors; ++i )
-                PNM_ASSIGN1( (*colorsP)[i], x10colors[i].red );
+            for (i = 0; i < h10P->window_ncolors; ++i)
+                PNM_ASSIGN1((*colorsP)[i], x10colors[i].red);
         } else {
+            unsigned int i;
             *formatP = PPM_TYPE;
-            for ( i = 0; i < h10P->window_ncolors; ++i )
+            for (i = 0; i < h10P->window_ncolors; ++i)
                 PPM_ASSIGN(
                     (*colorsP)[i], x10colors[i].red, x10colors[i].green,
                     x10colors[i].blue);
@@ -308,36 +308,46 @@ fixH11ByteOrder(X11WDFileHeader *  const h11P,
 
 
 static void
-readX11Colormap(FILE *      const file,
-                int         const ncolors, 
-                bool        const byteSwap,
-                X11XColor** const x11colorsP) {
+dumpX11Cmap(unsigned int       const nColors,
+            const X11XColor *  const x11colors) {
+
+    unsigned int i;
+    for (i = 0; i < nColors; ++i)
+        pm_message("Color %u r/g/b = %u/%u/%u", i, 
+                   x11colors[i].red, x11colors[i].green, 
+                   x11colors[i].blue);
+}
+
+
+
+static void
+readX11Colormap(FILE *       const file,
+                unsigned int const nColors, 
+                bool         const byteSwap,
+                bool         const cmapDump,
+                X11XColor**  const x11colorsP) {
                 
     X11XColor * x11colors;
     int rc;
 
     /* Read X11 colormap. */
-    MALLOCARRAY(x11colors, ncolors);
+    MALLOCARRAY(x11colors, nColors);
     if (x11colors == NULL)
         pm_error("out of memory");
-    rc = fread(x11colors, sizeof(x11colors[0]), ncolors, file);
-    if (rc != ncolors)
+    rc = fread(x11colors, sizeof(x11colors[0]), nColors, file);
+    if (rc != nColors)
         pm_error("couldn't read X11 XWD colormap");
     if (byteSwap) {
         unsigned int i;
-        for (i = 0; i < ncolors; ++i) {
+        for (i = 0; i < nColors; ++i) {
             x11colors[i].red   = pm_bs_short(x11colors[i].red);
             x11colors[i].green = pm_bs_short(x11colors[i].green);
             x11colors[i].blue  = pm_bs_short(x11colors[i].blue);
         }
     }
-    if (debug) {
-        unsigned int i;
-        for (i = 0; i < ncolors && i < 8; ++i)
-            pm_message("Color %d r/g/b = %d/%d/%d", i, 
-                       x11colors[i].red, x11colors[i].green, 
-                       x11colors[i].blue);
-    }
+    if (cmapDump)
+        dumpX11Cmap(nColors, x11colors);
+
     *x11colorsP = x11colors;
 }
 
@@ -456,9 +466,7 @@ reverseBits(unsigned long arg,
 
 static void
 computeComponentMasks(X11WDFileHeader * const h11P,
-                      unsigned long *   const redMaskP,
-                      unsigned long *   const grnMaskP,
-                      unsigned long *   const bluMaskP) {
+                      struct compMask * const compMaskP) {
 /*----------------------------------------------------------------------------
    You'd think the component (red, green, blue) masks in the header
    would just be right.  But we've seen a direct color image which has
@@ -470,33 +478,57 @@ computeComponentMasks(X11WDFileHeader * const h11P,
 -----------------------------------------------------------------------------*/
     if (h11P->visual_class == DirectColor &&
         h11P->bits_per_pixel == 24 && h11P->bitmap_bit_order == LSBFirst) {
-        *redMaskP = reverseBits(h11P->red_mask, 24);
-        *grnMaskP = reverseBits(h11P->green_mask, 24);
-        *bluMaskP = reverseBits(h11P->blue_mask, 24);
+        compMaskP->red = reverseBits(h11P->red_mask, 24);
+        compMaskP->grn = reverseBits(h11P->green_mask, 24);
+        compMaskP->blu = reverseBits(h11P->blue_mask, 24);
     } else {
-        *redMaskP = h11P->red_mask;
-        *grnMaskP = h11P->green_mask;
-        *bluMaskP = h11P->blue_mask;
+        compMaskP->red = h11P->red_mask;
+        compMaskP->grn = h11P->green_mask;
+        compMaskP->blu = h11P->blue_mask;
     }
 }
 
 
+/* About TrueColor maxval:
+
+   The X11 spec says that in TrueColor, you use the bits in the raster for a
+   particular color component of a particular pixel to index the server's
+   colormap for that component, which contains 'bits_per_rgb' significant bits
+   of intensity information.  'bits_per_rgb' is in the XWD header, and in
+   practice is normally 8 or 16, usually 8.
+
+   We don't have the server's colormap, so we assume the most ordinary
+   one, a linear-as-possible distribution over the indices.
+
+   That means the maxval is that implied by 'bits_per_rgb' bits and we get
+   the proper sample value by scaling the value from the raster to that
+   maxval.
+
+   We (mostly Julian Bradfield <jcb@inf.ed.ac.uk>) figured this out in Netpbm
+   10.46 (March 2009).  Between ca. 2000 and 10.46, we instead assumed the
+   value in the XWD raster to be the exact brightness value, and chose a
+   maxval that would best allow us to represent that exact value for all
+   three components (e.g. if the XWD had 5 bits for blue, 5 for red, and
+   6 for red, we'd use maxval 31*63=1953).  Before that, the maxval was
+   31 if bits per pixel was 16 and 255 otherwise.
+*/
+
+
 
 static void
 processX11Header(X11WDFileHeader *  const h11P, 
-                 FILE *             const file,
+                 FILE *             const fileP,
+                 bool               const cmapDump,
                  int *              const colsP, 
                  int *              const rowsP, 
-                 int *              const padrightP, 
+                 unsigned int *     const padrightP, 
                  xelval *           const maxvalP, 
                  enum visualclass * const visualclassP, 
                  int *              const formatP, 
                  xel **             const colorsP, 
                  int *              const bits_per_pixelP, 
                  int *              const bits_per_itemP, 
-                 unsigned long *    const red_maskP, 
-                 unsigned long *    const green_maskP, 
-                 unsigned long *    const blue_maskP,
+                 struct compMask *  const compMaskP,
                  enum byteorder *   const byte_orderP,
                  enum byteorder *   const bit_orderP) {
 
@@ -512,38 +544,36 @@ processX11Header(X11WDFileHeader *  const h11P,
         pm_message("Header is different endianness from this machine.");
     
     for (i = 0; i < h11FixedP->header_size - sizeof(*h11FixedP); ++i)
-        if (getc(file) == EOF)
+        if (getc(fileP) == EOF)
             pm_error("couldn't read rest of X11 XWD file header");
 
     /* Check whether we can handle this dump. */
-    if ( h11FixedP->pixmap_depth > 24 )
-        pm_error( "can't handle X11 pixmap_depth > 24" );
-    if ( h11FixedP->bits_per_rgb > 24 )
-        pm_error( "can't handle X11 bits_per_rgb > 24" );
-    if ( h11FixedP->pixmap_format != ZPixmap && h11FixedP->pixmap_depth != 1 )
-        pm_error(
-            "can't handle X11 pixmap_format %d with depth != 1",
-            h11FixedP->pixmap_format );
-    if ( h11FixedP->bitmap_unit != 8 && h11FixedP->bitmap_unit != 16 &&
-         h11FixedP->bitmap_unit != 32 )
-        pm_error(
-            "X11 bitmap_unit (%d) is non-standard - can't handle",
-            h11FixedP->bitmap_unit );
+    if (h11FixedP->pixmap_depth > 24)
+        pm_error( "can't handle X11 pixmap_depth > 24");
+    if (h11FixedP->bits_per_rgb > 24)
+        pm_error("can't handle X11 bits_per_rgb > 24");
+    if (h11FixedP->pixmap_format != ZPixmap && h11FixedP->pixmap_depth != 1)
+        pm_error("can't handle X11 pixmap_format %d with depth != 1",
+                 h11FixedP->pixmap_format);
+    if (h11FixedP->bitmap_unit != 8 && h11FixedP->bitmap_unit != 16 &&
+        h11FixedP->bitmap_unit != 32)
+        pm_error("X11 bitmap_unit (%d) is non-standard - can't handle",
+                 h11FixedP->bitmap_unit);
     /* The following check was added in 10.19 (November 2003) */
-    if ( h11FixedP->bitmap_pad != 8 && h11FixedP->bitmap_pad != 16 &&
-         h11FixedP->bitmap_pad != 32 )
-        pm_error(
-            "X11 bitmap_pad (%d) is non-standard - can't handle",
-            h11FixedP->bitmap_unit );
-
-    if ( h11FixedP->ncolors > 0 ) {
-        readX11Colormap( file, h11FixedP->ncolors, byte_swap, &x11colors );
-        grayscale = colormapAllGray( x11colors, h11FixedP->ncolors );
+    if (h11FixedP->bitmap_pad != 8 && h11FixedP->bitmap_pad != 16 &&
+        h11FixedP->bitmap_pad != 32)
+        pm_error("X11 bitmap_pad (%d) is non-standard - can't handle",
+                 h11FixedP->bitmap_unit);
+
+    if (h11FixedP->ncolors > 0) {
+        readX11Colormap(fileP, h11FixedP->ncolors, byte_swap, cmapDump,
+                        &x11colors);
+        grayscale = colormapAllGray(x11colors, h11FixedP->ncolors);
     } else
         grayscale = TRUE;
 
     *visualclassP = (enum visualclass) h11FixedP->visual_class;
-    if ( *visualclassP == DirectColor ) {
+    if (*visualclassP == DirectColor) {
         unsigned int i;
         *formatP = PPM_TYPE;
         *maxvalP = 65535;
@@ -553,27 +583,23 @@ processX11Header(X11WDFileHeader *  const h11P,
           is composed of 3 separate indices.
         */
 
-        *colorsP = pnm_allocrow( h11FixedP->ncolors );
-        for ( i = 0; i < h11FixedP->ncolors; ++i )
+        *colorsP = pnm_allocrow(h11FixedP->ncolors);
+        for (i = 0; i < h11FixedP->ncolors; ++i)
             PPM_ASSIGN(
                 (*colorsP)[i], x11colors[i].red, x11colors[i].green,
                 x11colors[i].blue);
-    } else if ( *visualclassP == TrueColor ) {
+    } else if (*visualclassP == TrueColor) {
         *formatP = PPM_TYPE;
 
-        *maxvalP = pm_lcm(pm_bitstomaxval(one_bits(h11FixedP->red_mask)),
-                          pm_bitstomaxval(one_bits(h11FixedP->green_mask)),
-                          pm_bitstomaxval(one_bits(h11FixedP->blue_mask)),
-                          PPM_OVERALLMAXVAL
-            );
-    }
-    else if ( *visualclassP == StaticGray && h11FixedP->bits_per_pixel == 1 ) {
+        /* See discussion above about this maxval */
+        *maxvalP = pm_bitstomaxval(h11FixedP->bits_per_rgb);
+    } else if (*visualclassP == StaticGray && h11FixedP->bits_per_pixel == 1) {
         *formatP = PBM_TYPE;
         *maxvalP = 1;
         *colorsP = pnm_allocrow( 2 );
-        PNM_ASSIGN1( (*colorsP)[0], *maxvalP );
-        PNM_ASSIGN1( (*colorsP)[1], 0 );
-    } else if ( *visualclassP == StaticGray ) {
+        PNM_ASSIGN1((*colorsP)[0], *maxvalP);
+        PNM_ASSIGN1((*colorsP)[1], 0);
+    } else if (*visualclassP == StaticGray) {
         unsigned int i;
         *formatP = PGM_TYPE;
         if (h11FixedP->bits_per_pixel > sizeof(*maxvalP) * 8 - 1)
@@ -585,20 +611,20 @@ processX11Header(X11WDFileHeader *  const h11P,
             pm_error("XWD header says bits_per_pixel = %u, which is too "
                      "large for maximum maxval of %u",
                      h11FixedP->bits_per_pixel, PNM_OVERALLMAXVAL);
-        *colorsP = pnm_allocrow( *maxvalP + 1 );
-        for ( i = 0; i <= *maxvalP; ++i )
-            PNM_ASSIGN1( (*colorsP)[i], i );
+        *colorsP = pnm_allocrow(*maxvalP + 1);
+        for (i = 0; i <= *maxvalP; ++i)
+            PNM_ASSIGN1((*colorsP)[i], i);
     } else {
-        *colorsP = pnm_allocrow( h11FixedP->ncolors );
-        if ( grayscale ) {
+        *colorsP = pnm_allocrow(h11FixedP->ncolors);
+        if (grayscale) {
             unsigned int i;
             *formatP = PGM_TYPE;
-            for ( i = 0; i < h11FixedP->ncolors; ++i )
-                PNM_ASSIGN1( (*colorsP)[i], x11colors[i].red );
+            for (i = 0; i < h11FixedP->ncolors; ++i)
+                PNM_ASSIGN1((*colorsP)[i], x11colors[i].red);
         } else {
             unsigned int i;
             *formatP = PPM_TYPE;
-            for ( i = 0; i < h11FixedP->ncolors; ++i )
+            for (i = 0; i < h11FixedP->ncolors; ++i)
                 PPM_ASSIGN(
                     (*colorsP)[i], x11colors[i].red, x11colors[i].green,
                     x11colors[i].blue);
@@ -611,11 +637,12 @@ processX11Header(X11WDFileHeader *  const h11P,
     *padrightP =
         h11FixedP->bytes_per_line * 8 -
         h11FixedP->pixmap_width * h11FixedP->bits_per_pixel;
+
     /* According to X11/XWDFile.h, the item size is 'bitmap_pad' for some
        images and 'bitmap_unit' for others.  This is strange, so there may
        be some subtlety of their definitions that we're missing.
 
-       See comments in getpix() about what an item is.
+       See comments in pixelReader_getpix() about what an item is.
 
        Ben Kelley in January 2002 had a 32 bits-per-pixel xwd file
        from a truecolor 32 bit window on a Hummingbird Exceed X server
@@ -625,25 +652,25 @@ processX11Header(X11WDFileHeader *  const h11P,
        bit-per-pixel direct color window that had bitmap_unit = 32 and
        bitmap_pad = 8.  This was made by Xwd in Red Hat Xfree86 4.3.0-2.
 
-       In March 2007, Darren Frith present an xwd file like this:
+       In March 2007, Darren Frith presented an xwd file like this:
        Header says direct color, bits_per_pixel = 24, bitmap_unit =
        32, bitmap_pad = 8, byte order and bit order LSB first.  The
        bytes in each item are in fact MSB first and the pixels spread
        across the items MSB first.  The raster is consecutive 24 bit
        pixel units, but each row is padded on the right with enough
        bits to make the total line size 32 x width.  Really strange.
-       Xwud, ImageMagick, and Gimp render this image
-       correctly, so it's not broken.
+       The header says the bits within each pixel are one byte red,
+       one byte green, one byte blue.  But they are actually blue,
+       green, red.  Xwud, ImageMagick, and Gimp render this image
+       correctly, so it's not broken.  Created by Xwd of X.org 7.1.1.
 
        Before Netpbm 9.23 (January 2002), we used bitmap_unit as the
        item size always.  Then, until 10.19 (November 2003), we used
        bitmap_pad when pixmap_depth > 1 and pixmap_format == ZPixmap.
        We still don't see any logic in these fields at all, but we
        figure whichever one is greater (assuming both are meaningful)
-       has to be the item size.  
-    */
-    *bits_per_itemP = MAX(h11FixedP->bitmap_pad, h11FixedP->bitmap_unit);
-
+       has to be the item size.  */
+    *bits_per_itemP  = MAX(h11FixedP->bitmap_pad, h11FixedP->bitmap_unit);
     *bits_per_pixelP = h11FixedP->bits_per_pixel;
 
     if (*visualclassP == DirectColor) {
@@ -656,7 +683,7 @@ processX11Header(X11WDFileHeader *  const h11P,
         *byte_orderP = (enum byteorder) h11FixedP->byte_order;
         *bit_orderP  = (enum byteorder) h11FixedP->bitmap_bit_order;
     }
-    computeComponentMasks(h11FixedP, red_maskP, green_maskP, blue_maskP);
+    computeComponentMasks(h11FixedP, compMaskP);
 
     free(h11FixedP);
 } 
@@ -667,29 +694,28 @@ static void
 getinit(FILE *             const ifP, 
         int *              const colsP, 
         int *              const rowsP, 
-        int *              const padrightP, 
+        unsigned int *     const padrightP, 
         xelval *           const maxvalP, 
         enum visualclass * const visualclassP, 
         int *              const formatP, 
         xel **             const colorsP,
         int *              const bits_per_pixelP, 
         int *              const bits_per_itemP, 
-        unsigned long *    const red_maskP, 
-        unsigned long *    const green_maskP,
-        unsigned long *    const blue_maskP,
+        struct compMask *  const compMaskP,
         enum byteorder *   const byte_orderP,
         enum byteorder *   const bit_orderP,
-        bool               const headerDump) {
+        bool               const headerDump,
+        bool               const cmapDump) {
 /*----------------------------------------------------------------------------
    Read the header from the XWD image in input stream 'ifP'.  Leave
    the stream positioned to the beginning of the raster.
 
    Return various fields from the header.
 
-   Return as *padrightP the number of additional pixels of padding are
+   Return as *padrightP the number of additional bits of padding are
    at the end of each line of input.  This says the input stream
-   contains *colsP pixels of image data plus *padrightP pixels of
-   padding.
+   contains *colsP pixels of image data (at *bits_per_pixelP bits each)
+   plus *padrightP bits of padding.
 -----------------------------------------------------------------------------*/
     /* Assume X11 headers are larger than X10 ones. */
     unsigned char header[sizeof(X11WDFileHeader)];
@@ -723,8 +749,7 @@ getinit(FILE *             const ifP,
         processX10Header(h10P, ifP, colsP, rowsP, padrightP, maxvalP, 
                          visualclassP, formatP, 
                          colorsP, bits_per_pixelP, bits_per_itemP, 
-                         red_maskP, green_maskP, blue_maskP, 
-                         byte_orderP, bit_orderP);
+                         compMaskP, byte_orderP, bit_orderP);
     } else if (h11P->file_version == X11WD_FILE_VERSION ||
                pm_bs_long(h11P->file_version) == X11WD_FILE_VERSION) {
         
@@ -742,11 +767,11 @@ getinit(FILE *             const ifP,
         if (headerDump)
             dumpX11Header(h11P);
 
-        processX11Header(h11P, ifP, colsP, rowsP, padrightP, maxvalP, 
+        processX11Header(h11P, ifP, cmapDump,
+                         colsP, rowsP, padrightP, maxvalP, 
                          visualclassP, formatP, 
                          colorsP, bits_per_pixelP, bits_per_itemP, 
-                         red_maskP, green_maskP, blue_maskP, 
-                         byte_orderP, bit_orderP);
+                         compMaskP, byte_orderP, bit_orderP);
     } else
         pm_error("unknown XWD file version: %u", h11P->file_version);
 }
@@ -799,13 +824,10 @@ getinit(FILE *             const ifP,
    one pixel at a time from it.
 
    It consists of a structure of type 'pixelReader' and the
-   getpix() and pixelReaderInit() subroutines.
+   pixelReader_*() subroutines.
 -----------------------------------------------------------------------------*/
 
 typedef struct {
-    /* This structure contains the state of the getpix() reader as it
-       reads across a row in the input image.
-       */
     FILE * fileP;
     unsigned long itemBuffer;
         /* The item buffer.  This contains what's left of the item
@@ -850,12 +872,12 @@ typedef struct {
 
 
 static void
-pixelReaderInit(pixelReader *  const pixelReaderP,
-                FILE *         const fileP,
-                int            const bitsPerPixel,
-                int            const bitsPerItem, 
-                enum byteorder const byteOrder,
-                enum byteorder const bitOrder) {
+pixelReader_init(pixelReader *  const pixelReaderP,
+                 FILE *         const fileP,
+                 int            const bitsPerPixel,
+                 int            const bitsPerItem, 
+                 enum byteorder const byteOrder,
+                 enum byteorder const bitOrder) {
     
     pixelReaderP->fileP           = fileP;
     pixelReaderP->bitsPerPixel    = bitsPerPixel;
@@ -869,6 +891,33 @@ pixelReaderInit(pixelReader *  const pixelReaderP,
 
 
 static void
+pixelReader_term(pixelReader * const pixelReaderP) {
+
+    unsigned int remainingByteCount;
+
+    if (pixelReaderP->nBitsLeft > 0)
+        pm_message("Warning: %u unused bits left in the pixel reader "
+                   "buffer after full image converted.  XWD file may be "
+                   "corrupted or Xwdtopnm may have misinterpreted it",
+                   pixelReaderP->nBitsLeft);
+
+
+    pm_drain(pixelReaderP->fileP, 4096, &remainingByteCount);
+
+    if (remainingByteCount >= 4096)
+        pm_message("Warning: at least 4K additional bytes in XWD input stream "
+                   "after full image converted.  XWD file may be corrupted "
+                   "or Xwdtopnm may have misinterpreted it.");
+    else if (remainingByteCount > 0)
+        pm_message("Warning: %u additional bytes in XWD input stream "
+                   "after full image converted.  XWD file may be corrupted "
+                   "or Xwdtopnm may have misinterpreted it.",
+                   remainingByteCount);
+}
+
+
+
+static void
 readItem(pixelReader * const rdrP) {
 /*----------------------------------------------------------------------------
    Read one item from the XWD raster associated with pixel reader *rdrP.
@@ -940,7 +989,6 @@ static unsigned long const lsbmask[] = {
 };
 
 
-
 static unsigned long
 pixelReader_getbits(pixelReader * const rdrP,
                     unsigned int  const nBits) {
@@ -1005,7 +1053,7 @@ pixelReader_getbits(pixelReader * const rdrP,
 
 
 static unsigned long
-getpix(pixelReader * const rdrP) {
+pixelReader_getpix(pixelReader * const rdrP) {
 /*----------------------------------------------------------------------------
    Get a pixel from the input image.
 
@@ -1056,15 +1104,13 @@ getpix(pixelReader * const rdrP) {
 static void
 reportInfo(int              const cols, 
            int              const rows, 
-           int              const padright, 
+           unsigned int     const padright, 
            xelval           const maxval, 
            enum visualclass const visualclass,
            int              const format, 
            int              const bits_per_pixel,
            int              const bits_per_item, 
-           int              const red_mask, 
-           int              const green_mask, 
-           int              const blue_mask,
+           struct compMask  const compMask,
            enum byteorder   const byte_order, 
            enum byteorder   const bit_order) {
     
@@ -1092,15 +1138,37 @@ reportInfo(int              const cols,
     }
     pm_message("%d rows of %d columns with maxval %d",
                rows, cols, maxval);
-    pm_message("padright=%d.  visualclass = %s.  format=%d (%c%c)",
+    pm_message("padright=%u bits.  visualclass = %s.  format=%d (%c%c)",
                padright, visualclass_name, 
                format, format/256, format%256);
     pm_message("bits_per_pixel=%d; bits_per_item=%d",
                bits_per_pixel, bits_per_item);
     pm_message("byte_order=%s; bit_order=%s",
                byte_order_name, bit_order_name);
-    pm_message("red_mask=0x%.8x; green_mask=0x%.8x; blue_mask=0x%.8x",
-               red_mask, green_mask, blue_mask);
+    pm_message("component mask: red=0x%.8lx; grn=0x%.8lx; blu=0x%.8lx",
+               compMask.red, compMask.grn, compMask.blu);
+}
+
+
+
+static void
+warn16Bit(xelval const maxval) {
+/*----------------------------------------------------------------------------
+   This program is often used by users of X, and those users often use
+   'xv', which doesn't properly interpret PNM files with 16 bit samples.
+   Furthermore, the maxval is often much larger than the user assumes
+   because of PNM's need to use the same maxval for all color components,
+   while XWD often uses different resolution for each.
+
+   Users get really frustrated when Xv displays something other than the
+   original mimage, almost always assuming that means Xwdtopnm converted
+   incorrectly.
+-----------------------------------------------------------------------------*/
+
+    if (pm_maxvaltobits(maxval) > 8)
+        pm_message("WARNING: Producing maxval %u output.  This involves "
+                   "multiple bytes per sample, which some programs, e.g. "
+                   "'xv', can't handle.  See manual.", maxval);
 }
 
 
@@ -1113,36 +1181,34 @@ convertRowSimpleIndex(pixelReader *  const pixelReaderP,
     
     unsigned int col;
     for (col = 0; col < cols; ++col)
-        xelrow[col] = colors[getpix(pixelReaderP)];
+        xelrow[col] = colors[pixelReader_getpix(pixelReaderP)];
 }
 
 
 
 static void
-convertRowDirect(pixelReader *  const pixelReaderP,
-                 int            const cols,
-                 const xel *    const colors,
-                 unsigned long  const red_mask,
-                 unsigned long  const grn_mask,
-                 unsigned long  const blu_mask,
-                 xel *          const xelrow) {
+convertRowDirect(pixelReader *   const pixelReaderP,
+                 int             const cols,
+                 const xel *     const colors,
+                 struct compMask const compMask,
+                 xel *           const xelrow) {
         
     unsigned int col;
 
     for (col = 0; col < cols; ++col) {
         unsigned long pixel;
             /* This is a triplet of indices into the color map, packed
-               into this bit string according to red_mask, etc.
+               into this bit string according to compMask
             */
         unsigned int red_index, grn_index, blu_index;
             /* These are indices into the color map, unpacked from 'pixel'.
              */
             
-        pixel = getpix(pixelReaderP);
+        pixel = pixelReader_getpix(pixelReaderP);
 
-        red_index = (pixel & red_mask) >> zero_bits(red_mask);
-        grn_index = (pixel & grn_mask) >> zero_bits(grn_mask); 
-        blu_index = (pixel & blu_mask) >> zero_bits(blu_mask);
+        red_index = (pixel & compMask.red) >> zero_bits(compMask.red);
+        grn_index = (pixel & compMask.grn) >> zero_bits(compMask.grn); 
+        blu_index = (pixel & compMask.blu) >> zero_bits(compMask.blu);
 
         PPM_ASSIGN(xelrow[col],
                    PPM_GETR(colors[red_index]),
@@ -1155,39 +1221,37 @@ convertRowDirect(pixelReader *  const pixelReaderP,
 
 
 static void
-convertRowTrueColor(pixelReader *  const pixelReaderP,
-                    int                  const cols,
-                    pixval               const maxval,
-                    const xel *          const colors,
-                    unsigned long        const red_mask,
-                    unsigned long        const grn_mask,
-                    unsigned long        const blu_mask,
-                    xel *                const xelrow) {
+convertRowTrueColor(pixelReader *   const pixelReaderP,
+                    int             const cols,
+                    pixval          const maxval,
+                    const xel *     const colors,
+                    struct compMask const compMask,
+                    xel *           const xelrow) {
 
     unsigned int col;
     unsigned int red_shift, grn_shift, blu_shift;
     unsigned int red_maxval, grn_maxval, blu_maxval;
 
-    red_shift = zero_bits(red_mask);
-    grn_shift = zero_bits(grn_mask);
-    blu_shift = zero_bits(blu_mask);
+    red_shift = zero_bits(compMask.red);
+    grn_shift = zero_bits(compMask.grn);
+    blu_shift = zero_bits(compMask.blu);
 
-    red_maxval = red_mask >> red_shift;
-    grn_maxval = grn_mask >> grn_shift;
-    blu_maxval = blu_mask >> blu_shift;
+    red_maxval = compMask.red >> red_shift;
+    grn_maxval = compMask.grn >> grn_shift;
+    blu_maxval = compMask.blu >> blu_shift;
 
     for (col = 0; col < cols; ++col) {
         unsigned long pixel;
 
-        pixel = getpix(pixelReaderP);
+        pixel = pixelReader_getpix(pixelReaderP);
 
         /* The parsing of 'pixel' used to be done with hardcoded layout
            parameters.  See comments at end of this file.
         */
         PPM_ASSIGN(xelrow[col],
-                   ((pixel & red_mask) >> red_shift) * maxval / red_maxval,
-                   ((pixel & grn_mask) >> grn_shift) * maxval / grn_maxval,
-                   ((pixel & blu_mask) >> blu_shift) * maxval / blu_maxval
+                   ((pixel & compMask.red) >> red_shift) * maxval / red_maxval,
+                   ((pixel & compMask.grn) >> grn_shift) * maxval / grn_maxval,
+                   ((pixel & compMask.blu) >> blu_shift) * maxval / blu_maxval
             );
 
     }
@@ -1198,13 +1262,11 @@ convertRowTrueColor(pixelReader *  const pixelReaderP,
 static void
 convertRow(pixelReader *    const pixelReaderP,
            FILE *           const ofP,
-           int              const padright, 
+           unsigned int     const padright, 
            int              const cols, 
            xelval           const maxval,
            int              const format, 
-           unsigned long    const red_mask, 
-           unsigned long    const green_mask, 
-           unsigned long    const blue_mask, 
+           struct compMask  const compMask,
            const xel*       const colors, 
            enum visualclass const visualclass) {
 /*----------------------------------------------------------------------------
@@ -1214,7 +1276,7 @@ convertRow(pixelReader *    const pixelReaderP,
    The row is 'cols' pixels.
 
    After reading the 'cols' pixels, we read and discard an additional
-   'padright' pixels from the input stream, so as to read the entire
+   'padright' bits from the input stream, so as to read the entire
    input line.
 -----------------------------------------------------------------------------*/
     xel* xelrow;
@@ -1228,22 +1290,19 @@ convertRow(pixelReader *    const pixelReaderP,
         convertRowSimpleIndex(pixelReaderP, cols, colors, xelrow);
         break;
     case DirectColor: 
-        convertRowDirect(pixelReaderP, cols, colors,
-                         red_mask, green_mask, blue_mask,
-                         xelrow);
+        convertRowDirect(pixelReaderP, cols, colors, compMask, xelrow);
         
         break;
     case TrueColor: 
         convertRowTrueColor(pixelReaderP, cols, maxval, colors,
-                            red_mask, green_mask, blue_mask,
-                            xelrow);
+                            compMask, xelrow);
         break;
             
     default:
         pm_error("unknown visual class");
     }
     pixelReader_getbits(pixelReaderP, padright);
-
+    
     pnm_writepnmrow(ofP, xelrow, cols, maxval, format, 0);
     pnm_freerow(xelrow);
 }
@@ -1278,15 +1337,17 @@ main(int argc, char *argv[]) {
 
     struct cmdlineInfo cmdline;
     FILE * ifP;
-    int rows, cols, format, padright;
+    int rows, cols, format;
+    unsigned int padright;
+        /* Number of bits of padding on the right of each row */
     unsigned int row;
-    int bits_per_pixel;
-    int bits_per_item;
-    unsigned long red_mask, green_mask, blue_mask;
+    int bitsPerPixel;
+    int bitsPerItem;
+    struct compMask compMask;
     xelval maxval;
     enum visualclass visualclass;
-    enum byteorder byte_order, bit_order;
-    xel *colors;  /* the color map */
+    enum byteorder byteOrder, bitOrder;
+    xel * colors;  /* the color map */
     pixelReader pixelReader;
 
     pnm_init(&argc, argv);
@@ -1296,24 +1357,25 @@ main(int argc, char *argv[]) {
     debug = cmdline.debug;
     verbose = cmdline.verbose;
 
-    if (cmdline.input_filename != NULL) 
-        ifP = pm_openr(cmdline.input_filename);
+    if (cmdline.inputFilename != NULL) 
+        ifP = pm_openr(cmdline.inputFilename);
     else
         ifP = stdin;
 
     getinit(ifP, &cols, &rows, &padright, &maxval, &visualclass, &format, 
-            &colors, &bits_per_pixel, &bits_per_item, 
-            &red_mask, &green_mask, &blue_mask, &byte_order, &bit_order,
-            cmdline.headerdump);
+            &colors, &bitsPerPixel, &bitsPerItem, 
+            &compMask, &byteOrder, &bitOrder,
+            cmdline.headerdump, cmdline.cmapdump);
+
+    warn16Bit(maxval);
     
     if (verbose) 
         reportInfo(cols, rows, padright, maxval, visualclass,
-                   format, bits_per_pixel, bits_per_item,
-                   red_mask, green_mask, blue_mask, 
-                   byte_order, bit_order);
+                   format, bitsPerPixel, bitsPerItem, compMask,
+                   byteOrder, bitOrder);
 
-    pixelReaderInit(&pixelReader, ifP, bits_per_pixel, bits_per_item,
-                    byte_order, bit_order);
+    pixelReader_init(&pixelReader, ifP, bitsPerPixel, bitsPerItem,
+                     byteOrder, bitOrder);
 
     pnm_writepnminit(stdout, cols, rows, maxval, format, 0);
 
@@ -1321,9 +1383,11 @@ main(int argc, char *argv[]) {
 
     for (row = 0; row < rows; ++row) {
         convertRow(&pixelReader, stdout,
-                   padright, cols, maxval, format,
-                   red_mask, green_mask, blue_mask, colors, visualclass);
+                   padright, cols, maxval, format, compMask,
+                   colors, visualclass);
     }
+
+    pixelReader_term(&pixelReader);
     
     pm_close(ifP);
     pm_close(stdout);
@@ -1332,6 +1396,7 @@ main(int argc, char *argv[]) {
 }
 
 
+
 /*
    This used to be the way we parsed a direct/true color pixel.  I'm 
    keeping it here in case we find out some application needs it this way.
diff --git a/converter/pbm/Makefile b/converter/pbm/Makefile
index 318b8e9e..c859b105 100644
--- a/converter/pbm/Makefile
+++ b/converter/pbm/Makefile
@@ -5,7 +5,7 @@ endif
 SUBDIR = converter/pbm
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
 PORTBINARIES =	atktopbm brushtopbm cmuwmtopbm ddbugtopbm g3topbm escp2topbm \
 		icontopbm macptopbm mdatopbm mgrtopbm mrftopbm \
@@ -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)
 
@@ -41,7 +41,7 @@ SUBDIRS=pbmtoppa
 .PHONY: all
 all: $(BINARIES) $(SUBDIRS:%=%/all)
 
-include $(SRCDIR)/Makefile.common
+include $(SRCDIR)/common.mk
 
 ifneq ($(LEX)x,x)
 thinkjettopbm.c1:%.c1:%.l
diff --git a/converter/pbm/atktopbm.c b/converter/pbm/atktopbm.c
index c4a81808..62664999 100644
--- a/converter/pbm/atktopbm.c
+++ b/converter/pbm/atktopbm.c
@@ -273,7 +273,7 @@ ReadATKRaster(FILE * const file,
 
     /* read the keyword */
     fscanf(file, " %5s", keyword);
-    if (!STREQ(keyword, "bits"))
+    if (!streq(keyword, "bits"))
       pm_error ("keyword is not 'bits'!");
 
     fscanf(file, " %d %d %d ", &objectid, &width, &height);
diff --git a/converter/pbm/cmuwmtopbm.c b/converter/pbm/cmuwmtopbm.c
index 53c64aaa..eabff40c 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 ((uint32_t)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 ( (uint32_t)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/g3topbm.c b/converter/pbm/g3topbm.c
index 1eefee96..7bb95c92 100644
--- a/converter/pbm/g3topbm.c
+++ b/converter/pbm/g3topbm.c
@@ -18,12 +18,19 @@
   contributing their work to the public domain.
 ===========================================================================*/
 
+#define _BSD_SOURCE   /* Make nstring.h define strcaseeq() */
+
+#include "pm_c_util.h"
 #include "pbm.h"
 #include "shhopt.h"
 #include "nstring.h"
 #include "mallocvar.h"
 #include "g3.h"
 #include "bitreverse.h"
+#include "bitarith.h"
+
+#define LEFTBITS pm_byteLeftBits
+#define RIGHTBITS pm_byteRightBits
 
 #define MAXCOLS 10800
 #define MAXROWS 14400   /* this allows up to two pages of image */
@@ -100,15 +107,15 @@ parseCommandLine(int argc, char ** const argv,
         if (cmdlineP->expectedLineSize < 1)
             pm_error("-width must be at least 1");
     } else if (paper_sizeSpec) {
-        if (STRCASEEQ(paperSize, "A6"))
+        if (strcaseeq(paperSize, "A6"))
             cmdlineP->expectedLineSize = 864;
-        else if (STRCASEEQ(paperSize, "A5"))
+        else if (strcaseeq(paperSize, "A5"))
             cmdlineP->expectedLineSize = 1216;
-        else if (STRCASEEQ(paperSize, "A4"))
+        else if (strcaseeq(paperSize, "A4"))
             cmdlineP->expectedLineSize = 1728;
-        else if (STRCASEEQ(paperSize, "B4"))
+        else if (strcaseeq(paperSize, "B4"))
             cmdlineP->expectedLineSize = 2048;
-        else if (STRCASEEQ(paperSize, "A3"))
+        else if (strcaseeq(paperSize, "A3"))
             cmdlineP->expectedLineSize = 2432;
         else
             pm_error("Unrecognized value for -paper_size '%s'.  "
@@ -295,12 +302,12 @@ buildHashes(g3TableEntry * (*whashP)[HASHSIZE],
 
 
 static void
-makeRowWhite(bit *        const bitrow,
-             unsigned int const cols) {
+makeRowWhite(unsigned char * const packedBitrow,
+             unsigned int    const cols) {
 
-    unsigned int col;
-    for (col = 0; col < MAXCOLS; ++col)
-        bitrow[col] = PBM_WHITE;
+    unsigned int colByte;
+    for (colByte = 0; colByte < pbm_packed_bytes(cols); ++colByte)
+        packedBitrow[colByte] = PBM_WHITE * 0xff;
 }
 
 
@@ -333,16 +340,45 @@ g3code(unsigned int const curcode,
 
 
 
-enum g3tableId {TERMWHITE, TERMBLACK, MKUPWHITE, MKUPBLACK};
+static void
+writeBlackBitSpan(unsigned char * const packedBitrow,
+                  int             const cols,
+                  int             const offset) {
+/*----------------------------------------------------------------------------
+   Write black (="1") bits into packedBitrow[], starting at 'offset',
+   length 'cols'.
+-----------------------------------------------------------------------------*/
+    unsigned char * const dest = & packedBitrow[offset/8];
+    unsigned int const rs  = offset % 8;
+    unsigned int const trs = (cols + rs) % 8;
+    unsigned int const colBytes = pbm_packed_bytes(cols + rs);
+    unsigned int const last = colBytes - 1;
+
+    unsigned char const origHead = dest[0];
+    unsigned char const origEnd =  0x00;
+
+    unsigned int i;
 
+    for( i = 0; i < colBytes; ++i)
+        dest[i] = PBM_BLACK * 0xff;
 
+    if (rs > 0)
+        dest[0] = LEFTBITS(origHead, rs) | RIGHTBITS(dest[0], 8-rs);
+
+    if (trs > 0)
+        dest[last] = LEFTBITS(dest[last], trs) | RIGHTBITS(origEnd, 8-trs);
+}
+
+
+
+enum g3tableId {TERMWHITE, TERMBLACK, MKUPWHITE, MKUPBLACK};
 
 static void
-processG3Code(g3TableEntry * const teP,
-              bit *          const bitrow,
-              unsigned int * const colP,
-              bit *          const colorP,
-              unsigned int * const countP) {
+processG3Code(const g3TableEntry * const teP,
+              unsigned char *      const packedBitrow,
+              unsigned int *       const colP,
+              bit *                const colorP,
+              unsigned int *       const countP) {
               
     enum g3tableId const teId =
         (teP > mtable ? 2 : 0) + (teP - ttable) % 2;
@@ -366,14 +402,10 @@ processG3Code(g3TableEntry * const teP,
         runLengthSoFar = MIN(*countP + teCount, MAXCOLS - col);
 
         if (runLengthSoFar > 0) {
-            if (*colorP == PBM_WHITE) {
-                /* Row was initialized to white, so we just skip */
-                col += runLengthSoFar;
-            } else {
-                unsigned int i;
-                for (i = 0; i < runLengthSoFar; ++i)
-                    bitrow[col++] = PBM_BLACK;
-            }
+            if (*colorP == PBM_BLACK)
+                writeBlackBitSpan(packedBitrow, runLengthSoFar, col);
+            /* else : Row was initialized to white, so we just skip */
+            col += runLengthSoFar;
         }
         *colorP = !*colorP;
         *countP = 0;
@@ -399,7 +431,7 @@ formatBadCodeException(const char ** const exceptionP,
     asprintfN(exceptionP,
         "bad code word at Column %u.  "
         "No prefix of the %u bits 0x%x matches any recognized "
-        "code word and no code words longer than 12 bits are "
+        "code word and no code words longer than 13 bits are "
         "defined.  ",
         col, curlen, curcode);
 }
@@ -408,13 +440,13 @@ formatBadCodeException(const char ** const exceptionP,
 
 static void
 readFaxRow(struct bitStream * const bitStreamP,
-           bit *              const bitrow,
+           unsigned char *    const packedBitrow,
            unsigned int *     const lineLengthP,
            const char **      const exceptionP,
            const char **      const errorP) {
 /*----------------------------------------------------------------------------
   Read one line of G3 fax from the bit stream *bitStreamP into 
-  bitrow[].  Return the length of the line, in pixels, as *lineLengthP.
+  packedBitrow[].  Return the length of the line, in pixels, as *lineLengthP.
 
   If there's a problem with the line, return as much of it as we can,
   advance the input stream past the next EOL mark, and put a text
@@ -438,11 +470,9 @@ readFaxRow(struct bitStream * const bitStreamP,
         /* Number of consecutive pixels of the same color */
     bit currentColor;
         /* The color of the current run of pixels */
-    g3TableEntry * te;
-        /* Address of structure that describes the current G3 code */
     bool done;
 
-    makeRowWhite(bitrow, MAXCOLS);  /* initialize row */
+    makeRowWhite(packedBitrow, MAXCOLS);  /* initialize row */
 
     col = 0;
     curlen = 0;
@@ -483,10 +513,14 @@ readFaxRow(struct bitStream * const bitStreamP,
                     formatBadCodeException(exceptionP, col, curlen, curcode);
                     done = TRUE;
                 } else if (curcode != 0) {
-                    te = g3code(curcode, curlen, currentColor);
-                    
-                    if (te) {
-                        processG3Code(te, bitrow, &col, &currentColor, &count);
+                    const g3TableEntry * const teP =
+                        g3code(curcode, curlen, currentColor);
+                        /* Address of structure that describes the 
+                           current G3 code
+                        */
+                    if (teP) {
+                        processG3Code(teP, packedBitrow,
+                                      &col, &currentColor, &count);
                         
                         curcode = 0;
                         curlen = 0;
@@ -504,9 +538,9 @@ readFaxRow(struct bitStream * const bitStreamP,
 
 
 static void
-freeBits(bit **       const bits,
-         unsigned int const rows,
-         bool         const stretched) {
+freeBits(unsigned char ** const packedBits,
+         unsigned int     const rows,
+         bool             const stretched) {
 
     unsigned int row;
 
@@ -516,9 +550,9 @@ freeBits(bit **       const bits,
                free it twice.
             */
         } else 
-            pbm_freerow(bits[row]);
+            pbm_freerow_packed(packedBits[row]);
     }
-    free(bits);
+    free(packedBits);
 }
 
 
@@ -623,8 +657,8 @@ analyzeLineSize(lineSizeAnalyzer * const analyzerP,
 
 
 /* An empty line means EOF.  An ancient comment in the code said there
-   is supposed to 6 EOL marks in a row to indicate EOF, but the code
-   checked for 3 and considered 2 in row just to mean a zero length
+   is supposed to be 6 EOL marks in a row to indicate EOF, but the code
+   checked for 3 and considered 2 in a row just to mean a zero length
    line.  Starting in Netpbm 10.24 (August 2004), we assume there is
    no valid reason to have an empty line and recognize EOF as any
    empty line.  Alternatively, we could read off and ignore two empty
@@ -636,17 +670,17 @@ readFax(struct bitStream * const bitStreamP,
         bool               const stretch,
         unsigned int       const expectedLineSize,
         bool               const tolerateErrors,
-        bit ***            const bitsP,
+        unsigned char ***  const packedBitsP,
         unsigned int *     const colsP,
         unsigned int *     const rowsP) {
 
     lineSizeAnalyzer lineSizeAnalyzer;
-    bit ** bits;
+    unsigned char ** packedBits;
     const char * error;
     bool eof;
     unsigned int row;
     
-    MALLOCARRAY_NOFAIL(bits, MAXROWS);
+    MALLOCARRAY_NOFAIL(packedBits, MAXROWS);
 
     initializeLineSizeAnalyzer(&lineSizeAnalyzer,
                                expectedLineSize, tolerateErrors);
@@ -664,8 +698,9 @@ readFax(struct bitStream * const bitStreamP,
         else {
             const char * exception;
 
-            bits[row] = pbm_allocrow(MAXCOLS);
-            readFaxRow(bitStreamP, bits[row], &lineSize, &exception, &error);
+            packedBits[row] = pbm_allocrow_packed(MAXCOLS);
+            readFaxRow(bitStreamP, packedBits[row],
+                       &lineSize, &exception, &error);
 
             handleRowException(exception, error, row, tolerateErrors);
 
@@ -683,16 +718,16 @@ readFax(struct bitStream * const bitStreamP,
                                       "program can handle at most %u rows "
                                       "after stretching", MAXROWS);
                         else
-                            bits[row] = bits[row-1];
+                            packedBits[row] = packedBits[row-1];
                     }
                     ++row;
                 }
             }
         }
     }
-    *rowsP  = row;
-    *colsP  = lineSizeAnalyzer.maxLineSize;
-    *bitsP  = bits;
+    *rowsP        = row;
+    *colsP        = lineSizeAnalyzer.maxLineSize;
+    *packedBitsP  = packedBits;
 }
 
 
@@ -704,7 +739,8 @@ main(int argc, char * argv[]) {
     FILE * ifP;
     struct bitStream bitStream;
     unsigned int rows, cols;
-    bit ** bits;
+    unsigned char ** packedBits;
+    int row;
 
     pbm_init(&argc, argv);
 
@@ -726,14 +762,17 @@ main(int argc, char * argv[]) {
 
     readFax(&bitStream, cmdline.stretch, cmdline.expectedLineSize,
             !cmdline.stop_error, 
-            &bits, &cols, &rows);
+            &packedBits, &cols, &rows);
 
     pm_close(ifP);
 
-    pbm_writepbm(stdout, bits, cols, rows, 0);
+    pbm_writepbminit(stdout, cols, rows, 0);
+    for (row = 0; row < rows; ++row)
+        pbm_writepbmrow_packed(stdout, packedBits[row], cols, 0);
+
     pm_close(stdout);
 
-    freeBits(bits, rows, cmdline.stretch);
+    freeBits(packedBits, rows, cmdline.stretch);
 
     return 0;
 }
diff --git a/converter/pbm/icontopbm.c b/converter/pbm/icontopbm.c
index d6dba8ae..a0d1bd2b 100644
--- a/converter/pbm/icontopbm.c
+++ b/converter/pbm/icontopbm.c
@@ -46,35 +46,35 @@ ReadIconFile(FILE *                const file,
         }
         variable[i] = '\0';
 
-        if ( STREQ( variable, "*/" )&& gotsome )
+        if ( streq( variable, "*/" )&& gotsome )
             break;
 
         if ( fscanf( file, "%d", &value ) != 1 )
             continue;
 
-        if ( STREQ( variable, "Width" ) )
+        if ( streq( variable, "Width" ) )
         {
             *widthP = value;
             gotsome = 1;
         }
-        else if ( STREQ( variable, "Height" ) )
+        else if ( streq( variable, "Height" ) )
         {
             *heightP = value;
             gotsome = 1;
         }
-        else if ( STREQ( variable, "Depth" )  )
+        else if ( streq( variable, "Depth" )  )
         {
             if ( value != 1 )
                 pm_error( "invalid depth" );
             gotsome = 1;
         }
-        else if ( STREQ( variable, "Format_version" ) )
+        else if ( streq( variable, "Format_version" ) )
         {
             if ( value != 1 )
                 pm_error( "invalid Format_version" );
             gotsome = 1;
         }
-        else if ( STREQ( variable, "Valid_bits_per_item" ) )
+        else if ( streq( variable, "Valid_bits_per_item" ) )
         {
             if ( value != 16 )
                 pm_error( "invalid Valid_bits_per_item" );
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/mrftopbm.c b/converter/pbm/mrftopbm.c
index 9534f3a5..51281028 100644
--- a/converter/pbm/mrftopbm.c
+++ b/converter/pbm/mrftopbm.c
@@ -41,34 +41,50 @@ bit_input(FILE * const in) {
 
 
 static void 
-doSquare(FILE *          const in,
-          unsigned char * const image,
-          int             const ox,
-          int             const oy,
-          int             const w,
-          int             const size) {
-
-    if (size == 1 || bit_input(in)) { 
+doSquare(FILE *          const ifP,
+         unsigned char * const image,
+         unsigned int    const ulCol,
+         unsigned int    const ulRow,
+         unsigned int    const imageWidth,
+         unsigned int    const size) {
+/*----------------------------------------------------------------------------
+   Do a square of side 'size', whose upper left corner is at (ulCol, ulRow).
+   The contents of that square are next in file *ifP, in MRF format.
+
+   Return the pixel values of the square in the corresponding position of
+   image[], which is a concatenation of rows 'imageWidth' pixels wide, one
+   byte per pixel.
+-----------------------------------------------------------------------------*/
+    if (size == 1 || bit_input(ifP)) { 
         /* It's all black or all white.  Next bit says which. */
 
-        unsigned int const c = bit_input(in);
+        unsigned int const c = bit_input(ifP);
 
-        unsigned int y;
+        unsigned int rowOfSquare;
 
-        for (y = 0; y < size; ++y) {
-            unsigned int x;
-            for (x = 0; x < size; ++x)
-                image[(oy+y)*w+ox+x] = c;
+        for (rowOfSquare = 0; rowOfSquare < size; ++rowOfSquare) {
+            unsigned int colOfSquare;
+            for (colOfSquare = 0; colOfSquare < size; ++colOfSquare) {
+                unsigned int rowOfImage = ulRow + rowOfSquare;
+                unsigned int colOfImage = ulCol + colOfSquare;
+
+                image[rowOfImage * imageWidth + colOfImage] = c;
+            }
         }
     } else {
-        /* not all one color, so recurse. */
-
-        int halfsize = size >> 1;
-
-        doSquare(in, image, ox,          oy,          w, halfsize);
-        doSquare(in, image, ox+halfsize, oy,          w, halfsize);
-        doSquare(in, image, ox,          oy+halfsize, w, halfsize);
-        doSquare(in, image, ox+halfsize, oy+halfsize, w, halfsize);
+        /* Square is not all one color, so recurse.  Do each of the four
+           quadrants of this square individually.
+        */
+        unsigned int const quadSize = size/2;
+
+        doSquare(ifP, image, ulCol,            ulRow,
+                 imageWidth, quadSize);
+        doSquare(ifP, image, ulCol + quadSize, ulRow,
+                 imageWidth, quadSize);
+        doSquare(ifP, image, ulCol,            ulRow + quadSize,
+                 imageWidth, quadSize);
+        doSquare(ifP, image, ulCol + quadSize, ulRow + quadSize,
+                 imageWidth, quadSize);
     }
 }
 
@@ -80,7 +96,7 @@ writeOutput(FILE *                const ofP,
             int                   const rows,
             const unsigned char * const image) {
             
-    /* w64 is units-of-64-bits width, h64 same for height */
+    /* w64 is units-of-64-bits width */
     unsigned int const w64 = (cols+63)/64;
 
     bit * bitrow;
@@ -145,7 +161,7 @@ readMrfImage(FILE *           const ifP,
         pm_error("Ridiculously large, unprocessable image: %u cols x %u rows",
                  cols, rows);
 
-    image = calloc(w64*h64*64*64,1);
+    image = calloc(w64*h64*64*64, 1);
     if (image == NULL)
         pm_error("Unable to get memory for raster");
                  
@@ -179,7 +195,7 @@ main(int argc, char *argv[]) {
 
     expandAll = FALSE;  /* initial assumption */
 
-    if (argc-1 >= 1 && STREQ(argv[1], "-a")) {
+    if (argc-1 >= 1 && streq(argv[1], "-a")) {
         expandAll = TRUE;
         argc--,argv++;
     }
diff --git a/converter/pbm/pbmto4425.c b/converter/pbm/pbmto4425.c
index 605b12d5..1d97ac6a 100644
--- a/converter/pbm/pbmto4425.c
+++ b/converter/pbm/pbmto4425.c
@@ -145,7 +145,7 @@ main(int argc, char * argv[]) {
         pbmfile = argv[argn];
     }
 
-    if(STREQ(pbmfile, "-"))
+    if(streq(pbmfile, "-"))
     {
         pbmfp = stdin;
     }
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/pbmtodjvurle.c b/converter/pbm/pbmtodjvurle.c
index dbe96f31..83e99ec4 100644
--- a/converter/pbm/pbmtodjvurle.c
+++ b/converter/pbm/pbmtodjvurle.c
@@ -50,91 +50,97 @@ writebyte(FILE *        const ofP,
 
 /* Write a run length to the RLE file. */
 static void 
-write_rle (FILE *rlefile, uint32n tally)
-{
-  do {
-    /* Output a single run. */
-    if (tally < 192) {
-      /* Single-byte runs */
-      writebyte (rlefile, tally);
-      tally >>= 8;
+write_rle(FILE *   const rlefile,
+          uint32_t const tallyArg) {
+
+    uint32_t remainingTally;
+
+    remainingTally = tallyArg;  /* initial value */
+
+    do {
+        /* Output a single run. */
+        if (remainingTally < 192) {
+            /* Single-byte runs */
+            writebyte (rlefile, remainingTally);
+            remainingTally >>= 8;
+        }
+        else {
+            /* Two-byte runs */
+            writebyte (rlefile, ((remainingTally>>8) & 0x3F) + 0xC0);
+            writebyte (rlefile, remainingTally & 0xFF);
+            remainingTally >>= 14;
+        }
+
+        /* Very large runs need to be split into smaller runs.  We
+           therefore need to toggle back to the same color we had for the
+           previous smaller run.
+        */
+        if (remainingTally > 0)
+            writebyte (rlefile, 0);
     }
-    else {
-      /* Two-byte runs */
-      writebyte (rlefile, ((tally>>8)&0x3F) + 0xC0);
-      writebyte (rlefile, tally&0xFF);
-      tally >>= 14;
-    }
-
-    /* Very large runs need to be split into smaller runs.  We
-     * therefore need to toggle back to the same color we had for the
-     * previous smaller run. */
-    if (tally > 0)
-      writebyte (rlefile, 0);
-  }
-  while (tally > 0);
+    while (remainingTally > 0);
 }
 
 
 
 int 
-main (int argc, char *argv[])
-{
-  FILE * const rlefile = stdout;    /* Generated Bitonal RLE file */
-
-  FILE *pbmfile;             /* PBM file to convert */
-  int numcols, numrows;      /* Width and height in pixels of the PBM file */
-  int format;                /* Original image type before conversion to PBM */
-  bit *pbmrow;               /* One row of the PBM file */
-  uint32n pixeltally = 0;    /* Run length of the current color */
-  int row, col;              /* Row and column loop variables */
-  const char * pbmfilename;  /* Name of input file */
-
-  /* Parse the command line. */
-  pbm_init (&argc, argv);
-
-  if (argc-1 < 1)
-      pbmfilename = "-";
-  else if (argc-1 == 1)
-      pbmfilename = argv[1];
-  else
-      pm_error("Program takes at most 1 argument -- the input file name.  "
-               "You specified %d", argc-1);
-
-  pbmfile = pm_openr(pbmfilename);
-
-  /* Write an RLE header. */
-  pbm_readpbminit (pbmfile, &numcols, &numrows, &format);
-  fprintf (rlefile, "R4\n");
-  fprintf (rlefile, "%d %d\n", numcols, numrows);
-
-  /* Write the RLE data. */
-  pbmrow = pbm_allocrow (numcols);
-  for (row=0; row<numrows; row++) {
-    bit prevpixel;        /* Previous pixel seen */
-
-    pbm_readpbmrow (pbmfile, pbmrow, numcols, format);
-    prevpixel = PBM_WHITE;   /* Bitonal RLE rows always start with white */
-    pixeltally = 0;
-    for (col=0; col<numcols; col++) {
-      bit newpixel = pbmrow[col];      /* Current pixel color */
-
-      if (newpixel == prevpixel)
-        pixeltally++;
-      else {
-        write_rle (rlefile, pixeltally);
-        pixeltally = 1;
-        prevpixel = newpixel;
-      }
+main (int argc, const char * argv[]) {
+
+    FILE * const rlefile = stdout; /* Generated Bitonal RLE file */
+
+    FILE * pbmfile;          /* PBM file to convert */
+    int numcols, numrows;    /* Width and height in pixels of the PBM file */
+    int format;              /* Original image type before conversion to PBM */
+    bit * pbmrow;            /* One row of the PBM file */
+    unsigned int row;
+    const char * pbmfilename;  /* Name of input file */
+
+    pm_proginit(&argc, argv);
+
+    if (argc-1 < 1)
+        pbmfilename = "-";
+    else if (argc-1 == 1)
+        pbmfilename = argv[1];
+    else
+        pm_error("Program takes at most 1 argument -- the input file name.  "
+                 "You specified %d", argc-1);
+
+    pbmfile = pm_openr(pbmfilename);
+
+    /* Write an RLE header. */
+    pbm_readpbminit(pbmfile, &numcols, &numrows, &format);
+    fprintf(rlefile, "R4\n");
+    fprintf(rlefile, "%d %d\n", numcols, numrows);
+
+    /* Write the RLE data. */
+    pbmrow = pbm_allocrow(numcols);
+    for (row = 0; row < numrows; ++row) {
+        unsigned int col;
+        uint32_t pixeltally;   /* Run length of the current color */
+        bit prevpixel;         /* Previous pixel seen */
+
+        pbm_readpbmrow(pbmfile, pbmrow, numcols, format);
+        prevpixel = PBM_WHITE;   /* Bitonal RLE rows always start with white */
+        pixeltally = 0;
+        for (col = 0; col < numcols; ++col) {
+            bit newpixel = pbmrow[col];      /* Current pixel color */
+
+            if (newpixel == prevpixel)
+                ++pixeltally;
+            else {
+                write_rle(rlefile, pixeltally);
+                pixeltally = 1;
+                prevpixel = newpixel;
+            }
+        }
+        write_rle(rlefile, pixeltally);
     }
-    write_rle (rlefile, pixeltally);
-  }
-
-  /* Finish up cleanly. */
-  pbm_freerow (pbmrow);
-  if (rlefile != stdout)
-    pm_close (rlefile);
-  if (pbmfile != stdin)
-    pm_close (pbmfile);
-  exit (0);
+
+    pbm_freerow(pbmrow);
+    if (rlefile != stdout)
+        pm_close(rlefile);
+    if (pbmfile != stdin)
+        pm_close(pbmfile);
+
+    return 0;
 }
diff --git a/converter/pbm/pbmtoepsi.c b/converter/pbm/pbmtoepsi.c
index 81e03fbe..5eccc298 100644
--- a/converter/pbm/pbmtoepsi.c
+++ b/converter/pbm/pbmtoepsi.c
@@ -16,6 +16,7 @@
 ** implied warranty.
 */
 
+#include "pm_c_util.h"
 #include "pbm.h"
 #include "shhopt.h"
 
diff --git a/converter/pbm/pbmtoepson.c b/converter/pbm/pbmtoepson.c
index 1d1b1608..86185d15 100644
--- a/converter/pbm/pbmtoepson.c
+++ b/converter/pbm/pbmtoepson.c
@@ -16,8 +16,9 @@
 #include <stdio.h>
 #include <string.h>
 
-#include "shhopt.h"
+#include "pm_c_util.h"
 #include "mallocvar.h"
+#include "shhopt.h"
 
 #include "pbm.h"
 
diff --git a/converter/pbm/pbmtoescp2.c b/converter/pbm/pbmtoescp2.c
index 9992fec9..e280b3df 100644
--- a/converter/pbm/pbmtoescp2.c
+++ b/converter/pbm/pbmtoescp2.c
@@ -16,6 +16,7 @@
 
 #include <string.h>
 
+#include "pm_c_util.h"
 #include "pbm.h"
 #include "shhopt.h"
 
diff --git a/converter/pbm/pbmtog3.c b/converter/pbm/pbmtog3.c
index 77ea545a..c0dd8c64 100644
--- a/converter/pbm/pbmtog3.c
+++ b/converter/pbm/pbmtog3.c
@@ -18,12 +18,14 @@
 
 #include <assert.h>
 
-#include "pbm.h"
+#include "pm_c_util.h"
 #include "shhopt.h"
 #include "mallocvar.h"
 #include "bitreverse.h"
 #include "wordaccess.h"
+#include "wordintclz.h"
 #include "g3.h"
+#include "pbm.h"
 
 #define TC_MC 64
 
@@ -55,7 +57,7 @@ struct bitString {
 
 struct outStream {
     struct bitString buffer;
-    
+
     bool reverseBits;
 };
 
@@ -109,6 +111,8 @@ parseCommandLine(int argc, char ** const argv,
     optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
+    free(option_def);
+
     if (argc-1 == 0) 
         cmdlineP->inputFileName = "-";
     else if (argc-1 != 1)
@@ -142,7 +146,7 @@ makeBs(wordint      const bits,
     return retval;
 }
 
-    
+
 
 static __inline__ void
 putbits(struct bitString const newBits) {
@@ -153,7 +157,7 @@ putbits(struct bitString const newBits) {
    Flush the buffer to stdout as necessary to make room.
 
    'newBits' must be shorter than a whole word.
-   
+
    N.B. the definition of struct bitString requires upper bits to be zero.
 -----------------------------------------------------------------------------*/
     unsigned int const spaceLeft = 
@@ -182,11 +186,11 @@ putbits(struct bitString const newBits) {
                        | (newBits.intBuffer >> nextBufBitCount));
         if (out.reverseBits)
             reversebuffer(outbytes, sizeof(outbytes));
-            
+
         rc = fwrite(outbytes, 1, sizeof(outbytes), stdout);
         if (rc != sizeof(outbytes))
             pm_error("Output error.  Unable to fwrite() to stdout");
-        
+
         out.buffer.intBuffer = newBits.intBuffer & ((1<<nextBufBitCount) - 1); 
         out.buffer.bitCount = nextBufBitCount;
     }
@@ -237,7 +241,7 @@ putcode2(int const clr,
 
     if (sizeof(wordint) * 8 > 24) {
         unsigned int const l1 = ttable[loIndex].length;
-        
+
         putbits(
             makeBs(mtable[hiIndex].code << l1 | ttable[loIndex].code,
                    mtable[hiIndex].length + l1)
@@ -299,7 +303,7 @@ puteol(void) {
         puts("EOL");
     else {
         struct bitString const eol = {12, 1};
-            
+
         putbits(eol);
     }
 }
@@ -341,7 +345,7 @@ convertRowToRunLengths(unsigned char * const bitrow,
     wordint      * const bitrowByWord = (wordint *) bitrow;
     int            const wordCount    = (cols + bitsPerWord - 1)/bitsPerWord; 
         /* Number of full and partial words in the row */
-        
+
 
     if (cols % bitsPerWord != 0) {
         /* Clean final word in row.  For loop simplicity */
@@ -411,7 +415,7 @@ main(int    argc,
            a word of zero padding on the high (right) end for the convenience
            of code that accesses this buffer in word-size bites.
         */
-     
+
     int rows;
     int cols;
     int readcols;
@@ -423,7 +427,7 @@ main(int    argc,
     pbm_init(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
-     
+
     ifP = pm_openr(cmdline.inputFileName);
 
     pbm_readpbminit(ifP, &cols, &rows, &format);
@@ -447,9 +451,9 @@ main(int    argc,
         unsigned int i;
 
         pbm_readpbmrow_packed(ifP, bitrow, cols, format);
-        
+
         convertRowToRunLengths(bitrow, readcols, milepost, &nRun);
-        
+
         padToDesiredWidth(milepost, &nRun, readcols, outwidth);
 
         for (i = p = 0; i < nRun; p = milepost[i++])
@@ -459,6 +463,8 @@ main(int    argc,
     }
 
     free(milepost);
+    pbm_freerow_packed(bitrow);
+
     {
         unsigned int i;  
         for( i = 0; i < 6; ++i)
@@ -467,7 +473,7 @@ main(int    argc,
     if (out.buffer.bitCount > 0) {
         /* flush final partial buffer */
         unsigned int const bytesToWrite = (out.buffer.bitCount+7)/8;
-        
+
         unsigned char outbytes[sizeof(wordint)];
         size_t rc;
         wordintToBytes(&outbytes, 
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 18f3ab6c..23b2ee9a 100644
--- a/converter/pbm/pbmtogo.c
+++ b/converter/pbm/pbmtogo.c
@@ -1,11 +1,11 @@
 /* pbmtogo.c - read a PBM image and produce a GraphOn terminal raster file
-**	
-**	Rev 1.1 was based on pbmtolj.c
+**      
+**      Rev 1.1 was based on pbmtolj.c
 **
-**	Bo Thide', Swedish Institute of Space Physics, bt@irfu.se
-**				   
+**      Bo Thide', Swedish Institute of Space Physics, bt@irfu.se
+**                                 
 **
-** $Log:	pbmtogo.c,v $
+** $Log:        pbmtogo.c,v $
  * Revision 1.5  89/11/25  00:24:12  00:24:12  root (Bo Thide)
  * Bug found: The byte after 64 repeated bytes sometimes lost. Fixed.
  * 
@@ -35,63 +35,125 @@
 ** implied warranty.
 */
 
+#include <assert.h>
 #include <stdio.h>
 #include <string.h>
 
 #include "pm_c_util.h"
 #include "pbm.h"
 
-#define BUFSIZE 132	/* GraphOn has 132 byte/1056 bit wide raster lines */
-#define REPEAT_CURRENT_LINE_MASK	0x00 
-#define SKIP_AND_PLOT_MASK		0x40 
-#define REPEAT_PLOT_MASK		0x80 
-#define PLOT_ARBITRARY_DATA_MASK	0xc0 
+#define GRAPHON_WIDTH 1056 /* GraphOn has 1056 bit wide raster lines */
+#define GRAPHON_WIDTH_BYTES (GRAPHON_WIDTH / 8)
+#define REPEAT_CURRENT_LINE_MASK        0x00 
+#define SKIP_AND_PLOT_MASK              0x40 
+#define REPEAT_PLOT_MASK                0x80 
+#define PLOT_ARBITRARY_DATA_MASK        0xc0 
 #define MAX_REPEAT 64
 
-static unsigned char *scanlineptr;		/* Pointer to current scan line byte */
+static unsigned char * scanlineptr;
+    /* Pointer to current scan line byte */
 
-static void putinit ARGS(( void ));
-static void putbit ARGS(( bit b ));
-static void putrest ARGS(( void ));
-static void putitem ARGS(( void ));
+static int item, bitsperitem, bitshift;
 
-int
-main( argc, argv )
-     int argc;
-     char* argv[];
-{
-    FILE* ifp;
-    bit* bitrow;
-    register bit* bP;
-    int argn, rows, cols, format, rucols, padright, row, col;
-    int nbyte, bytesperrow, ecount, ucount, nout, i, linerepeat;
-    int	olditem;
-    unsigned char oldscanline[BUFSIZE];
-    unsigned char newscanline[BUFSIZE];
-    unsigned char diff[BUFSIZE];
-    unsigned char buffer[BUFSIZE];
-    unsigned char outbuffer[2*(BUFSIZE+1)];	/* Worst case.  Should malloc */
-    const char* usage = "[-c] [pbmfile]";
+static void
+putinit(void) {
+
+    /* Enter graphics window */
+    printf("\0331");
+
+    /* Erase graphics window */
+    printf("\033\014");
+
+    /* Set graphics window in raster mode */
+    printf("\033r");
+
+    /* Select standard Tek coding **/
+    printf("\033[=11l");
+
+    bitsperitem = 1;
+    item = 0;
+    bitshift = 7;
+}
+
+
+
+static void
+putitem(void) {
 
+    *scanlineptr++ = item;
+    bitsperitem = 0;
+    item = 0;
+}
+
+
+
+static void
+putbit(bit const b) {
+
+    if (b == PBM_BLACK)
+        item += 1 << bitshift;
+
+    bitshift--;
+
+    if (bitsperitem == 8)
+    {
+        putitem();
+        bitshift = 7;
+    }
+    bitsperitem++;
+}
+
+
+
+static void
+putrest(void) {
 
-    pbm_init( &argc, argv );
+    if (bitsperitem > 1)
+        putitem();
 
-    argn = 2;
+    /* end raster downloading */
+    printf("\033\134");
 
-    /* Check for flags. */
-    if (argc > argn + 1)
-      pm_usage(usage);
+    /* Exit raster mode */
+    printf("\033t");
 
-    if (argc == argn)
-      ifp = pm_openr( argv[argn-1] );
+    /* Exit graphics window
+       printf("\0332"); */
+}
+
+
+
+int
+main(int           argc,
+     const char ** argv) {
+
+    FILE * ifP;
+    bit * bitrow;
+    bit * bP;
+    int rows, cols, format, rucols, padright, row, col;
+    int nbyte, bytesperrow, ecount, ucount, nout, i, linerepeat;
+    int olditem;
+    unsigned char oldscanline[GRAPHON_WIDTH_BYTES];
+    unsigned char newscanline[GRAPHON_WIDTH_BYTES];
+    unsigned char diff[GRAPHON_WIDTH_BYTES];
+    unsigned char buffer[GRAPHON_WIDTH_BYTES];
+    unsigned char outbuffer[2*(GRAPHON_WIDTH_BYTES+1)];     /* Worst case. */
+
+    pm_proginit(&argc, argv);
+
+    if (argc-1 == 0)
+      ifP = stdin;
+    else if (argc-1 == 1)
+      ifP = pm_openr(argv[1]);
     else
-      ifp = stdin;
+        pm_error("There is at most one argument: input file name.  "
+                 "You specified %u", argc-1);
 
-    pbm_readpbminit(ifp, &cols, &rows, &format);
+    pbm_readpbminit(ifP, &cols, &rows, &format);
 
-    if (cols > 1056)
+    if (cols > GRAPHON_WIDTH)
         pm_error("Image is wider (%u pixels) than a Graphon terminal "
-                 "(%u pixels)", cols, 1056);
+                 "(%u pixels)", cols, GRAPHON_WIDTH);
 
     bitrow = pbm_allocrow(cols);
 
@@ -101,7 +163,7 @@ main( argc, argv )
     rucols = rucols * 8;
     padright = rucols - cols;
 
-    for (i = 0; i < BUFSIZE; ++i )
+    for (i = 0; i < GRAPHON_WIDTH_BYTES; ++i )
       buffer[i] = oldscanline[i] = 0;
     putinit();
 
@@ -113,12 +175,14 @@ main( argc, argv )
     for (row = 0; row < rows; row++) {
         /* Store scan line data in the new scan line vector */
         scanlineptr = newscanline;
-        pbm_readpbmrow(ifp, bitrow, cols, format);
+        pbm_readpbmrow(ifP, bitrow, cols, format);
         /* Transfer raster graphics */
         for (col = 0, bP = bitrow; col < cols; col++, bP++)
           putbit(*bP);
         for (col = 0; col < padright; col++)
           putbit(0);
+
+        assert(bytesperrow <= GRAPHON_WIDTH_BYTES);
         
         /* XOR data from the new scan line with data from old scan line */
         for (i = 0; i < bytesperrow; i++)
@@ -219,7 +283,7 @@ main( argc, argv )
             fflush(stdout);
 
             /* Output the plot data */
-            write(1, outbuffer, nout);
+            fwrite(outbuffer, 1, nout, stdout);
 
             /* Reset the counters */
             linerepeat = 0;
@@ -230,7 +294,7 @@ main( argc, argv )
                   putchar(linerepeat);
                   printf("%d/", nout+1);
                   fflush(stdout);
-                  write(1, outbuffer, nout);
+                  fwrite(outbuffer, 1, nout, stdout);
                   linerepeat = 0;
               }
         }
@@ -240,75 +304,11 @@ main( argc, argv )
           oldscanline[i] = newscanline[i];
     }
     putchar(linerepeat);        /* For the last line(s) to be plotted */
-    pm_close(ifp);
+    pm_close(ifP);
     putrest();
-    exit(0);
-}
-
-
-
-static int item, bitsperitem, bitshift;
-
-static void
-putinit()
-{
-  /* Enter graphics window */
-  printf("\0331");
-
-  /* Erase graphics window */
-  printf("\033\014");
-
-  /* Set graphics window in raster mode */
-  printf("\033r");
-
-  /* Select standard Tek coding **/
-  printf("\033[=11l");
 
-  bitsperitem = 1;
-  item = 0;
-  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;
-  bitshift--;
-  if (bitsperitem == 8)
-  {
-    putitem();
-    bitshift = 7;
-  }
-  bitsperitem++;
+    return 0;
 }
 
-static void
-putrest()
-{
-  if (bitsperitem > 1)
-      putitem();
-
-  /* end raster downloading */
-  printf("\033\134");
 
-  /* Exit raster mode */
-  printf("\033t");
 
-  /* Exit graphics window
-  printf("\0332"); */
-}
-
-static void
-putitem()
-  {
-  *scanlineptr++ = item;
-  bitsperitem = 0;
-  item = 0;
-  }
diff --git a/converter/pbm/pbmtoibm23xx.c b/converter/pbm/pbmtoibm23xx.c
index 973f7de0..a83e260d 100644
--- a/converter/pbm/pbmtoibm23xx.c
+++ b/converter/pbm/pbmtoibm23xx.c
@@ -46,6 +46,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "pm_c_util.h"
 #include "pbm.h"
 #include "shhopt.h"
 #include "mallocvar.h"
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/pbmtolj.c b/converter/pbm/pbmtolj.c
index e8373050..be28f635 100644
--- a/converter/pbm/pbmtolj.c
+++ b/converter/pbm/pbmtolj.c
@@ -27,6 +27,7 @@
 ** implied warranty.
 */
 
+#include "pm_c_util.h"
 #include "pbm.h"
 #include "shhopt.h"
 #include "mallocvar.h"
diff --git a/converter/pbm/pbmtoln03.c b/converter/pbm/pbmtoln03.c
index 07c8629f..f7cf53c7 100644
--- a/converter/pbm/pbmtoln03.c
+++ b/converter/pbm/pbmtoln03.c
@@ -219,13 +219,8 @@ main (int argc, char **argv) {
    if( argn != argc )
       pm_usage(usage);
 
-
-   /* Initialize pbm file */
    pbm_readpbminit (input, &width, &height, &format) ;
 
-   if (format != PBM_FORMAT && format != RPBM_FORMAT)
-      pm_error ("input not in PBM format") ;
-
 /*
  * In explanation of the sequence below:
  *      <ESC>[!p        DECSTR  soft terminal reset
diff --git a/converter/pbm/pbmtolps.c b/converter/pbm/pbmtolps.c
index 13a14e2b..5adef4c8 100644
--- a/converter/pbm/pbmtolps.c
+++ b/converter/pbm/pbmtolps.c
@@ -112,7 +112,7 @@ main(int argc, char ** argv) {
 	pbm_init(&argc, argv);
 
     i = 1;
-    if (i < argc && STREQ(argv[i], "-dpi")) {
+    if (i < argc && streq(argv[i], "-dpi")) {
         if (i == argc - 1)
             pm_usage(usage);
         sscanf(argv[i + 1], "%f", &dpi);
diff --git a/converter/pbm/pbmtomgr.c b/converter/pbm/pbmtomgr.c
index acf689e1..d12e6635 100644
--- a/converter/pbm/pbmtomgr.c
+++ b/converter/pbm/pbmtomgr.c
@@ -1,124 +1,127 @@
-/* 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 <assert.h>
 #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 ));
 
-int
-main( argc, argv )
-    int argc;
-    char* argv[];
-    {
-    FILE* ifp;
-    bit* bitrow;
-    register bit* bP;
-    int rows, cols, format, padright, row, col;
 
+static void
+putinit(unsigned int const rows,
+        unsigned int const cols) {
 
-    pbm_init( &argc, argv );
+    struct b_header head;
+    size_t writtenCount;
+
+    /* Because of argument restrictions: maximum dimensions: */
+    assert((rows & 0xfff) == rows);
+    assert((cols & 0xfff) == cols);
+
+    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.");    
+}
 
-    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;
+    unsigned int const maxDimension = 4095;
+        /* Dimensions are 2 characters of the header -- 12 bits */
+
+    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 );
-    if (cols > 4095)
-        pm_error("Image width too large: %u (max: 4095)", cols);
-    if (rows > 4095)
-        pm_error("Image heigth too large: %u (max: 4095)", cols);
-    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);
+    if (cols > maxDimension)
+        pm_error("Image width too large: %u (max: %u)", cols, maxDimension);
+    if (rows > maxDimension)
+        pm_error("Image height too large: %u (max: %u)", rows, maxDimension);
+    
+    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;
-    }
+/* 2006.10 (afu)
+   Changed bitrow from plain to raw, read function from pbm_readpbmrow() to
+   pbm_readpbmrow_packed(), write function from putc() to fwrite().
 
-#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;
-    }
-
-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/pbmtomrf.c b/converter/pbm/pbmtomrf.c
index c93c88aa..e7b7fcc9 100644
--- a/converter/pbm/pbmtomrf.c
+++ b/converter/pbm/pbmtomrf.c
@@ -13,83 +13,139 @@
 #include "pm_c_util.h"
 #include "pbm.h"
 
-static int bitbox;
-static int bitsleft;
 
-static FILE *bit_out;
+
+typedef struct bitOut {
+    int bitbox;
+    int bitsleft;
+    FILE * fileP;
+} bitOut;
+
 
 
 static void 
-bit_init(FILE * const out) {
-    bitbox = 0; 
-    bitsleft = 8;
-    bit_out = out;
+bit_init(struct bitOut * const bitOutP,
+         FILE *          const ofP) {
+
+    bitOutP->bitbox = 0; 
+    bitOutP->bitsleft = 8;
+    bitOutP->fileP = ofP;
 }
 
 
 
 static void 
-bit_output(int const bit) {
-    --bitsleft;
-    bitbox |= (bit << bitsleft);
-    if (bitsleft == 0) {
-        fputc(bitbox, bit_out);
-        bitbox = 0;
-        bitsleft = 8;
+bit_output(struct bitOut * const bitOutP,
+           int             const bit) {
+
+    --bitOutP->bitsleft;
+    bitOutP->bitbox |= (bit << bitOutP->bitsleft);
+    if (bitOutP->bitsleft == 0) {
+        fputc(bitOutP->bitbox, bitOutP->fileP);
+        bitOutP->bitbox = 0;
+        bitOutP->bitsleft = 8;
     }
 }
 
 
 
 static void 
-bit_flush(void) {
+bit_flush(struct bitOut * const bitOutP) {
     /* there are never 0 bits left outside of bit_output, but
      * if 8 bits are left here there's nothing to flush, so
      * only do it if bitsleft!=8.
      */
-    if (bitsleft != 8) {
-        bitsleft = 1;
-        bit_output(0);    /* yes, really. This will always work. */
+    if (bitOutP->bitsleft != 8) {
+        bitOutP->bitsleft = 1;
+        bit_output(bitOutP, 0);    /* yes, really. This will always work. */
     }
 }
 
 
 
-static void 
-doSquare(unsigned char * const image,
-         int             const ox,
-         int             const oy,
-         int             const w,
-         int             const size) {
-
-    unsigned int y;
+static void
+determineBlackWhiteOrMix(const unsigned char * const image,
+                         unsigned int          const ulCol,
+                         unsigned int          const ulRow,
+                         unsigned int          const imageWidth,
+                         unsigned int          const size,
+                         bool *                const oneColorP,
+                         int *                 const colorP) {
+/*----------------------------------------------------------------------------
+   Determine whether a square within 'image' is all white, all black,
+   or a mix.
+-----------------------------------------------------------------------------*/
+    unsigned int rowOfSquare;
     unsigned int t;
 
-    /* check square to see if it's all black or all white. */
+    for (rowOfSquare = 0, t = 0; rowOfSquare < size; ++rowOfSquare) {
+        unsigned int colOfSquare;
+        for (colOfSquare = 0; colOfSquare < size; ++colOfSquare) {
+            unsigned int rowOfImage = ulRow + rowOfSquare;
+            unsigned int colOfImage = ulCol + colOfSquare;
 
-    t = 0;
-    for (y = 0; y < size; ++y) {
-        unsigned int x;
-        for (x = 0; x < size; ++x)
-            t += image[(oy+y)*w + ox + x];
+            t += image[rowOfImage * imageWidth + colOfImage];
+        }
     }        
     /* if the total's 0, it's black. if it's size*size, it's white. */
-    if (t == 0 || t == size*size) {
-        if (size != 1)     /* (it's implicit when size is 1, of course) */
-            bit_output(1);  /* all same color */
-        bit_output(t?1:0);
-        return;
-    }
-    
-    /* otherwise, if our square is greater than 1x1, we need to recurse. */
-    if(size > 1) {
-        int halfsize = size >> 1;
-
-        bit_output(0);    /* not all same */
-        doSquare(image, ox,          oy,          w, halfsize);
-        doSquare(image, ox+halfsize, oy,          w, halfsize);
-        doSquare(image, ox,          oy+halfsize, w, halfsize);
-        doSquare(image, ox+halfsize, oy+halfsize, w, halfsize);
+    if (t == 0) {
+        *oneColorP = TRUE;
+        *colorP = 0;
+    } else if (t == SQR(size)) {
+        *oneColorP = TRUE;
+        *colorP = 1;
+    } else
+        *oneColorP = FALSE;
+}
+
+
+
+static void 
+doSquare(bitOut *              const bitOutP,
+         const unsigned char * const image,
+         unsigned int          const ulCol,
+         unsigned int          const ulRow,
+         unsigned int          const imageWidth,
+         unsigned int          const size) {
+/*----------------------------------------------------------------------------
+   Do a square of side 'size', whose upper left corner is at (ulCol, ulRow).
+   This is a square within 'image', which is a concatenation of rows
+   'imageWidth' pixels wide, one byte per pixel.
+
+   Write the pixel values out to the bit stream *bitOutP, in MRF format.
+-----------------------------------------------------------------------------*/
+    if (size == 1) {
+        /* The fact that it is all one color is implied because the square is
+           just one pixel; no bit goes in MRF output to state that.
+        */
+        bit_output(bitOutP, image[ulRow * imageWidth + ulCol] ? 1 : 0);
+    } else {
+        bool oneColor;
+        int color;
+
+        determineBlackWhiteOrMix(image, ulCol, ulRow, imageWidth, size,
+                                 &oneColor, &color);
+
+        if (oneColor) {
+            bit_output(bitOutP, 1);  /* all same color */
+            bit_output(bitOutP, color);
+        } else {
+            /* Square is not all the same color, so recurse.  Do each
+               of the four quadrants of this square individually.
+            */
+            unsigned int const quadSize = size/2;
+
+            bit_output(bitOutP, 0);    /* not all same color */
+
+            doSquare(bitOutP, image, ulCol,            ulRow,
+                     imageWidth, quadSize);
+            doSquare(bitOutP, image, ulCol + quadSize, ulRow,
+                     imageWidth, quadSize);
+            doSquare(bitOutP, image, ulCol,            ulRow + quadSize,
+                     imageWidth, quadSize);
+            doSquare(bitOutP, image, ulCol + quadSize, ulRow + quadSize,
+                     imageWidth, quadSize);
+        }
     }
 }
     
@@ -243,7 +299,7 @@ readPbmImage(FILE *           const ifP,
         pm_error("Ridiculously large, unprocessable image: %u cols x %u rows",
                  cols, rows);
 
-    image = calloc(w64*h64*64*64,1);
+    image = calloc(w64*h64*64*64, 1);
     if (image == NULL)
         pm_error("Unable to get memory for raster");
                  
@@ -276,6 +332,8 @@ outputMrf(FILE *          const ofP,
     unsigned int const w64 = (cols + 63) / 64;
     unsigned int const h64 = (rows + 63) / 64;
 
+    bitOut bitOut;
+
     unsigned int row;
 
     fprintf(ofP, "MRF1");
@@ -285,14 +343,14 @@ outputMrf(FILE *          const ofP,
     
     /* now recursively check squares. */
 
-    bit_init(ofP);
+    bit_init(&bitOut, ofP);
 
     for (row = 0; row < h64; ++row) {
         unsigned int col;
         for (col = 0; col < w64; ++col)
-            doSquare(image, col*64, row*64, w64*64, 64);
+            doSquare(&bitOut, image, col*64, row*64, w64*64, 64);
     }
-    bit_flush();
+    bit_flush(&bitOut);
 }
 
 
diff --git a/converter/pbm/pbmtonokia.c b/converter/pbm/pbmtonokia.c
index 214958c5..b8057393 100644
--- a/converter/pbm/pbmtonokia.c
+++ b/converter/pbm/pbmtonokia.c
@@ -1,231 +1,527 @@
-/* pbmtonokia.c - convert a portable bitmap to Nokia Smart Messaging
+/* pbmtonokia.c - convert a PBM image to Nokia Smart Messaging
    Formats (NOL, NGG, HEX)
 
-** Copyright (C)2001 OMS Open Media System GmbH, Tim Rühsen
-** <tim.ruehsen@openmediasystem.de>.
-**
-** 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.
+   Copyright information is at end of file.
+*/
 
-History
-  07.06.2001 Created
-  20.11.2001 Handle Picture Messages
-             new option -txt to embed text into Picture Messages
-             new option -net to specify operator network code for 
-                Nokia Operator Logos
+#define _BSD_SOURCE    /* Make sure strcaseeq() is in nstring.h */
+#include <string.h>
+#include <assert.h>
 
-Notes:
-  - limited to rows <= 255 and columns <= 255
-  - limited to b/w graphics, not animated
+#include "pm_c_util.h"
+#include "nstring.h"
+#include "mallocvar.h"
+#include "shhopt.h"
+#include "pbm.h"
 
-Testing:
-  Testing was done with SwissCom SMSC (Switzerland) and IC3S SMSC (Germany).
-  The data was send with EMI/UCP protocol over TCP/IP.
+enum outputFormat {
+    FMT_HEX_NOL,
+    FMT_HEX_NGG,
+    FMT_HEX_NPM,
+    FMT_NOL,
+    FMT_NGG,
+    FMT_NPM
+};
 
-  - 7.6.2001: tested with Nokia 3210: 72x14 Operator Logo
-  - 7.6.2001: tested with Nokia 6210: 72x14 Operator Logo and 
-              72x14 Group Graphic
 
-Todo:
-  - more testing
-  - sendsms compatibility ?
-  - are -fmt NOL and -fmt NGG working ok?  */
+struct cmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char * inputFileName;  /* Filename of input files */
+    int outputFormat;
+    const char * networkCode;
+    const char * txt;  /* NULL means unspecified */
+};
 
-#define _BSD_SOURCE    /* Make sure strcasecmp() is in string.h */
-#include <string.h>
 
-#include "nstring.h"
-#include "pbm.h"
 
-#define FMT_HEX_NOL   1
-#define FMT_HEX_NGG   2
-#define FMT_HEX_NPM   3
-#define FMT_NOL       4
-#define FMT_NGG       5
-
-static void 
-usage(char *myname)
-{
-    pm_message("Copyright (C)2001 OMS GmbH");
-    pm_message("Contact: Tim Ruehsen <tim.ruehsen@openmediasystem.de>\n");
-    pm_usage("[options] [pbmfile]\n"
-             "  Options:\n"
-             "    -fmt <HEX_NOL|HEX_NGG|HEX_NPM|NOL|NGG>  "
-             "Output format (default=HEX_NOL)\n"
-             "    -net <network code>                     "
-             "Network code for NOL operator logos\n"
-             "    -txt <text message>                     "
-             "Text for NPM picture messages\n");
-
-    exit(1);
+static const char *
+uppercase(const char * const subject) {
+
+    char * buffer;
+
+    buffer = malloc(strlen(subject) + 1);
+
+    if (buffer == NULL)
+        pm_error("Out of memory allocating buffer for uppercasing a "
+                 "%u-character string", strlen(subject));
+    else {
+        unsigned int i;
+
+        i = 0;
+        while (subject[i]) {
+            buffer[i] = TOUPPER(subject[i]);
+            ++i;
+        }
+        buffer[i] = '\0';
+    }
+    return buffer;
+}
+
+
+
+static void
+parseCommandLine(int argc, char ** argv,
+                 struct cmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   Note that the file spec array we return is stored in the storage that
+   was passed to us as the argv array.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;
+        /* Instructions to optParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+    unsigned int fmtSpec, netSpec, txtSpec;
+    const char * fmtOpt;
+    const char * netOpt;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "fmt",     OPT_STRING, &fmtOpt, 
+            &fmtSpec, 0);
+    OPTENT3(0, "net",     OPT_STRING, &netOpt,
+            &netSpec, 0);
+    OPTENT3(0, "txt",     OPT_STRING, &cmdlineP->txt,
+            &txtSpec, 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 (fmtSpec) {
+        if (strcaseeq(fmtOpt, "HEX_NOL"))
+            cmdlineP->outputFormat = FMT_HEX_NOL;
+        else if (strcaseeq(fmtOpt, "HEX_NGG"))
+            cmdlineP->outputFormat = FMT_HEX_NGG;
+        else if (strcaseeq(fmtOpt, "HEX_NPM"))
+            cmdlineP->outputFormat = FMT_HEX_NPM;
+        else if (strcaseeq(fmtOpt, "NOL"))
+            cmdlineP->outputFormat = FMT_NOL;
+        else if (strcaseeq(fmtOpt, "NGG"))
+            cmdlineP->outputFormat = FMT_NGG;
+        else if (strcaseeq(fmtOpt, "NPM"))
+            cmdlineP->outputFormat = FMT_NPM;
+        else
+            pm_error("-fmt option must be HEX_NGG, HEX_NOL, HEX_NPM, "
+                     "NGG, NOL or NPM.  You specified '%s'", fmtOpt);
+    } else
+        cmdlineP->outputFormat = FMT_HEX_NOL;
+
+    if (netSpec) {
+        if (strlen(netOpt) != 6)
+            pm_error("-net option must be 6 hex digits long.  "
+                     "You specified %u characters", strlen(netOpt));
+        else if (!strishex(netOpt))
+            pm_error("-net option must be hexadecimal.  You specified '%s'",
+                     netOpt);
+        else
+            cmdlineP->networkCode = uppercase(netOpt);
+    } else
+        cmdlineP->networkCode = strdup("62F210");  /* German D1 net */
+
+    if (!txtSpec)
+        cmdlineP->txt = NULL;
+    else if (strlen(cmdlineP->txt) > 120)
+        pm_error("Text message is longer (%u characters) than "
+                 "the 120 characters allowed by the format.",
+                 strlen(cmdlineP->txt));
+
+    if (argc-1 == 0) 
+        cmdlineP->inputFileName = "-";
+    else if (argc-1 != 1)
+        pm_error("Program takes zero or one argument (filename).  You "
+                 "specified %u", argc-1);
+    else
+        cmdlineP->inputFileName = argv[1];
 }
 
-int 
-main(int argc, char *argv[])
-{
-    FILE    *fp;
-    bit    **image;
-    unsigned int    c;
-    int    argpos, output=FMT_HEX_NOL, rows, cols, row, col, p, it, len;
-    char    header[32], *myname;
-    char    network_code[6+1];
-    char    *text=NULL;
-
-    if ((myname=strrchr(argv[0],'/'))!=NULL) myname++; else myname=argv[0];
 
-    pbm_init(&argc, argv);
 
-    strcpy(network_code, "62F210"); /* default is German D1 net */
-
-    for(argpos=1;argpos<argc;argpos++) {
-        if (argv[argpos][0]=='-') {
-            if (argv[argpos][1]=='-') {
-                if (argc>argpos+1 && ISDIGIT(argv[argpos+1][0]))
-                    {argpos++;break;}
-            } else if (STREQ(argv[argpos],"-fmt") && argc>argpos+1) {
-                ++argpos;
-                if (!strcasecmp(argv[argpos],"HEX_NOL")) output=FMT_HEX_NOL;
-                else if (!strcasecmp(argv[argpos],"HEX_NGG")) 
-                    output=FMT_HEX_NGG;
-                else if (!strcasecmp(argv[argpos],"HEX_NPM")) 
-                    output=FMT_HEX_NPM;
-                else if (!strcasecmp(argv[argpos],"NOL")) output=FMT_NOL;
-                else if (!strcasecmp(argv[argpos],"NGG")) output=FMT_NGG;
-                else usage(myname);
-            } else if (STREQ(argv[argpos],"-net") && argc>argpos+1) {
-                char * const network_code_arg=argv[++argpos];
-                unsigned int it;
-                len=strlen(network_code_arg);
-                if (len!=6) 
-                    pm_error("Network code must be 6 hex-digits long");
-                for (it=0;it<strlen(network_code_arg);it++) {
-                    if (!ISXDIGIT(network_code_arg[it])) 
-                        pm_error("Network code must contain hex-digits only");
-                    network_code[it]=TOUPPER(network_code_arg[it]);
-                }
-                network_code[it] = '\0';
-            } else if (STREQ(argv[argpos],"-txt") && argc>argpos+1) {
-                text=argv[++argpos];
+static void
+freeCmdline(struct cmdlineInfo const cmdline) {
+
+    strfree(cmdline.networkCode);
+}
+
+
+
+static void
+validateSize(unsigned int const cols,
+             unsigned int const rows){
+
+    if (cols > 255)
+        pm_error("This program cannot handle files with more than 255 "
+                 "columns");
+    if (rows > 255)
+        pm_error("This program cannot handle files with more than 255 "
+                 "rows");
+}
+
+
+
+
+static void
+convertToHexNol(bit **       const image,
+                unsigned int const cols,
+                unsigned int const rows,
+                const char * const networkCode,
+                FILE *       const ofP) {
+
+    unsigned int row;
+
+    /* header */
+    fprintf(ofP, "06050415820000%s00%02X%02X01", networkCode, cols, rows);
+    
+    /* image */
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+        unsigned int p;
+        unsigned int c;
+
+        c = 0;
+
+        for (p = 0, col = 0; col < cols; ++col) {
+            if (image[row][col] == PBM_BLACK)
+                c |= 0x80 >> p;
+            if (++p == 8) {
+                fprintf(ofP, "%02X",c);
+                p = c = 0;
             }
-            else usage(myname);
-        } else break;
+        }
+        if (p > 0)
+            fprintf(ofP, "%02X", c);
     }
+}
 
-    if (argpos==argc) {
-        image = pbm_readpbm(stdin, &cols, &rows);
-    } else {
-        fp=pm_openr(argv[argpos]);
-        image = pbm_readpbm(fp, &cols, &rows);
-        pm_close(fp);
-    }
 
-    memset(header,0,sizeof(header));
 
-    switch (output) {
-    case FMT_HEX_NOL:
-        /* header */
-        printf("06050415820000%s00%02X%02X01",network_code,cols,rows);
-
-        /* image */
-        for (row=0;row<rows;row++) {
-            for (p=c=col=0;col<cols;col++) {
-                if (image[row][col]==PBM_BLACK) c|=0x80>>p;
-                if (++p==8) {
-                    printf("%02X",c);
-                    p=c=0;
-                }
+static void
+convertToHexNgg(bit **       const image,
+                unsigned int const cols,
+                unsigned int const rows,
+                FILE *       const ofP) {
+
+    unsigned int row;
+
+    /* header */
+    fprintf(ofP, "0605041583000000%02X%02X01", cols, rows);
+
+    /* image */
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+        unsigned int p;
+        unsigned int c;
+
+        for (p = 0, c = 0, col = 0; col < cols; ++col) {
+            if (image[row][col] == PBM_BLACK)
+                c |= 0x80 >> p;
+            if (++p == 8) {
+                fprintf(ofP, "%02X", c);
+                p = c = 0;
             }
-            if (p) printf("%02X",c);
         }
-        break;
-    case FMT_HEX_NGG:
-        /* header */
-        printf("0605041583000000%02X%02X01",cols,rows);
-
-        /* image */
-        for (row=0;row<rows;row++) {
-            for (p=c=col=0;col<cols;col++) {
-                if (image[row][col]==PBM_BLACK) c|=0x80>>p;
-                if (++p==8) {
-                    printf("%02X",c);
-                    p=c=0;
-                }
+        if (p > 0)
+            fprintf(ofP, "%02X", c);
+    }
+}
+
+
+
+
+static void
+convertToHexNpm(bit **       const image,
+                unsigned int const cols,
+                unsigned int const rows,
+                const char * const text,
+                FILE *       const ofP) {
+
+    unsigned int row;
+    
+    /* header */
+    fprintf(ofP, "060504158A0000");
+
+    /* text */
+    if (text) {
+        size_t const len = strlen(text);
+
+        unsigned int it;
+
+        fprintf(ofP, "00%04X", len);
+
+        for (it = 0; it < len; ++it)
+            fprintf(ofP, "%02X", text[it]);
+    }
+
+    /* image */
+    fprintf(ofP, "02%04X00%02X%02X01", (cols * rows) / 8 + 4, cols, rows);
+
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+        unsigned int p;
+        unsigned int c;
+
+        for (p = 0, c = 0, col = 0; col < cols; ++col) {
+            if (image[row][col] == PBM_BLACK)
+                c |= 0x80 >> p;
+            if (++p == 8) {
+                fprintf(ofP, "%02X", c);
+                p = c = 0;
             }
-            if (p) printf("%02X",c);
         }
-        break;
-    case FMT_HEX_NPM:
-        /* header */
-        printf("060504158A0000");
+        if (p > 0)
+            fprintf(ofP, "%02X", c);
+    }
+}
+
+
+
+static void
+convertToNol(bit **       const image,
+             unsigned int const cols,
+             unsigned int const rows,
+             FILE *       const ofP) {
+
+    unsigned int row;
+    char header[32];
+    unsigned int it;
+    
+    /* header - this is a hack */
+
+    header[ 0] = 'N';
+    header[ 1] = 'O';
+    header[ 2] = 'L';
+    header[ 3] = 0;
+    header[ 4] = 1;
+    header[ 5] = 0;
+    header[ 6] = 4;
+    header[ 7] = 1;
+    header[ 8] = 1;
+    header[ 9] = 0;
+    header[10] = cols;
+    header[11] = 0;
+    header[12] = rows;
+    header[13] = 0;
+    header[14] = 1;
+    header[15] = 0;
+    header[16] = 1;
+    header[17] = 0;
+    header[18] = 0x53;
+    header[19] = 0;
 
-        /* text */
-        if (text!=NULL) {
-            printf("00%04X",(len=strlen(text)));
-            for (it=0;it<len;it++) printf("%02X",text[it]);
+    fwrite(header, 20, 1, ofP);
+    
+    /* image */
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+        unsigned int p;
+        unsigned int c;
+
+        for (p = 0, c = 0, col = 0; col < cols; ++col) {
+            char const output = image[row][col] == PBM_BLACK ? '1' : '0';
+
+            putc(output, ofP);
         }
+    }
 
-        /* image */
-        printf("02%04X00%02X%02X01",(cols*rows)/8+4,cols,rows);
-        for (row=0;row<rows;row++) {
-            for (p=c=col=0;col<cols;col++) {
-                if (image[row][col]==PBM_BLACK) c|=0x80>>p;
-                if (++p==8) {
-                    printf("%02X",c);
-                    p=c=0;
-                }
-            }
-            if (p) printf("%02X",c);
+    /* padding (to keep gnokii happy) */
+    for (it = 0; it < 8 - cols * rows % 8; ++it)
+        putc('0', ofP);
+}
+
+
+
+
+static void
+convertToNgg(bit **       const image,
+             unsigned int const cols,
+             unsigned int const rows,
+             FILE *       const ofP) {
+
+    unsigned int row;
+    char    header[32];
+    unsigned int it;
+
+    /* header - this is a hack */
+
+    header[ 0] = 'N';
+    header[ 1] = 'G';
+    header[ 2] = 'G';
+    header[ 3] = 0;
+    header[ 4] = 1;
+    header[ 5] = 0;
+    header[ 6] = cols;
+    header[ 7] = 0;
+    header[ 8] = rows;
+    header[ 9] = 0;
+    header[10] = 1;
+    header[11] = 0;
+    header[12] = 1;
+    header[13] = 0;
+    header[14] = 0x4a;
+    header[15] = 0;
+
+    fwrite(header, 16, 1, ofP);
+    
+    /* image */
+
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+        unsigned int p;
+        unsigned int c;
+
+        for (p = 0, c = 0, col = 0; col < cols; ++col) {
+            char const output = image[row][col] == PBM_BLACK ? '1' : '0';
+
+            putc(output, ofP);
         }
-        break;
-    case FMT_NOL:
-        /* header - this is a hack */
-        header[0]='N';
-        header[1]='O';
-        header[2]='L';
-        header[4]=header[7]=header[8]=header[14]=header[16]=1;
-        header[6]=4;
-        header[10]=cols;
-        header[12]=rows;
-        header[18]=0x53;
-        fwrite(header,20,1,stdout);
-
-        /* image */
-        for (row=0;row<rows;row++) {
-            for (p=c=col=0;col<cols;col++) {
-                if (image[row][col]==PBM_BLACK) putchar('1');
-                else putchar('0');
+    }
+
+    /* padding (to keep gnokii happy) */
+    for (it = 0; it < 8 - cols * rows % 8; ++it)
+        putc('0', ofP);
+}
+
+
+
+static void
+convertToNpm(bit **       const image,
+             unsigned int const cols,
+             unsigned int const rows,
+             const char * const text,
+             FILE *       const ofP) {
+
+    unsigned int row;
+    char header[132];
+    size_t len;
+
+    if (text) 
+        len = strlen(text);
+    else
+        len = 0;
+
+    /* header and optional text */
+
+    header[       0] = 'N';
+    header[       1] = 'P';
+    header[       2] = 'M';
+    header[       3] = 0;
+    header[       4] = len;
+    header[       5] = 0;
+    memcpy(&header[5], text, len);
+    header[ 6 + len] = cols;
+    header[ 7 + len] = rows;
+    header[ 8 + len] = 1;
+    header[ 9 + len] = 1;
+    header[10 + len] = 0; /* unknown */
+
+    assert(10 + len < sizeof(header));
+
+    fwrite(header, 11 + len, 1, ofP);
+    
+    /* image: stream of bits, each row padded to a byte boundary
+       inspired by gnokii/common/gsm-filesystems.c
+     */
+    for (row = 0; row < rows; row++) {
+        unsigned int byteNumber;
+        int bitNumber;
+        char buffer[32];  /* picture messages are (always?) 72 x 28 */
+        unsigned int col;
+
+        byteNumber = 0;
+        bitNumber = 7;
+
+        memset(buffer, 0, sizeof(buffer));
+
+        for (col = 0; col < cols; ++col) {
+            if (image[row][col] == PBM_BLACK)
+                buffer[byteNumber] |= (1 << bitNumber);
+            --bitNumber;
+            if (bitNumber < 0 && col < (cols - 1)) {
+                bitNumber = 7;
+                ++byteNumber;
             }
         }
+        fwrite(buffer, byteNumber + 1, 1, ofP);
+    }
+}
+
+
+
+int 
+main(int    argc,
+     char * argv[]) {
+
+    struct cmdlineInfo cmdline;
+    FILE  * ifP;
+    bit ** bits;
+    int rows, cols;
+
+    pbm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFileName);
+    bits = pbm_readpbm(ifP, &cols, &rows);
+    pm_close(ifP);
+
+    validateSize(cols, rows);
+
+    switch (cmdline.outputFormat) {
+    case FMT_HEX_NGG:
+        convertToHexNgg(bits, cols, rows, stdout);
+        break;
+    case FMT_HEX_NOL:
+        convertToHexNol(bits, cols, rows, cmdline.networkCode, stdout);
+        break;
+    case FMT_HEX_NPM:
+        convertToHexNpm(bits, cols, rows, cmdline.txt, stdout);
         break;
     case FMT_NGG:
-        /* header - this is a hack */
-        header[0]='N';
-        header[1]='G';
-        header[2]='G';
-        header[4]=header[10]=header[12]=1;
-        header[6]=cols;
-        header[8]=rows;
-        header[14]=0x4a;
-        fwrite(header,16,1,stdout);
-
-        /* image */
-        for (row=0;row<rows;row++) {
-            for (p=c=col=0;col<cols;col++) {
-                if (image[row][col]==PBM_BLACK) putchar('1');
-                else putchar('0');
-            }
-        }
+        convertToNgg(bits, cols, rows, stdout);
+        break;
+    case FMT_NOL:
+        convertToNol(bits, cols, rows, stdout);
+        break;
+    case FMT_NPM:
+        convertToNpm(bits, cols, rows, cmdline.txt, stdout);
         break;
-    default:
-        pm_error("Output format %d not implemented!\n"
-                 "Contact Tim Ruehsen <tim.ruehsen@openmediasystem.de>\n",
-                 output);
-        return 1;
     }
+
+freeCmdline(cmdline);
+
     return 0;
 }
 
+
+
+/* Copyright (C)2001 OMS Open Media System GmbH, Tim Rühsen
+** <tim.ruehsen@openmediasystem.de>.
+**
+** 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.
+
+  Created 2001.06.07
+
+Notes:
+  - limited to rows <= 255 and columns <= 255
+  - limited to b/w graphics, not animated
+
+Testing:
+  Testing was done with SwissCom SMSC (Switzerland) and IC3S SMSC (Germany).
+  The data was send with EMI/UCP protocol over TCP/IP.
+
+  - 7.6.2001: tested with Nokia 3210: 72x14 Operator Logo
+  - 7.6.2001: tested with Nokia 6210: 72x14 Operator Logo and 
+              72x14 Group Graphic
+*/
diff --git a/converter/pbm/pbmtopi3.c b/converter/pbm/pbmtopi3.c
index 8d178f61..1dbf1a71 100644
--- a/converter/pbm/pbmtopi3.c
+++ b/converter/pbm/pbmtopi3.c
@@ -90,14 +90,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/pbmtopk.c b/converter/pbm/pbmtopk.c
index 08aff49a..fc94f855 100644
--- a/converter/pbm/pbmtopk.c
+++ b/converter/pbm/pbmtopk.c
@@ -172,7 +172,7 @@ pbmtopk_add_suffix(char * const name,
     char *slash = strrchr(name, '/');
     char *dot = strrchr(name, '.');
 
-    if ((dot && slash ? dot < slash : !dot) && !STREQ(name, "-"))
+    if ((dot && slash ? dot < slash : !dot) && !streq(name, "-"))
         strcat(name, suffix);
 }
 
diff --git a/converter/pbm/pbmtoppa/Makefile b/converter/pbm/pbmtoppa/Makefile
index ba15adaa..5f205230 100644
--- a/converter/pbm/pbmtoppa/Makefile
+++ b/converter/pbm/pbmtoppa/Makefile
@@ -5,7 +5,7 @@ endif
 SUBDIR = converter/pbm/pbmtoppa
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
 all: pbmtoppa
 
@@ -16,7 +16,7 @@ MERGEBINARIES = $(BINARIES)
 OBJECTS = pbmtoppa.o ppa.o pbm.o cutswath.o
 MERGE_OBJECTS = pbmtoppa.o2 ppa.o pbm.o cutswath.o
 
-include $(SRCDIR)/Makefile.common
+include $(SRCDIR)/common.mk
 
 pbmtoppa: $(OBJECTS) $(NETPBMLIB) $(LIBOPT)
 	$(LD) -o pbmtoppa $(OBJECTS) \
diff --git a/converter/pbm/pbmtopsg3.c b/converter/pbm/pbmtopsg3.c
index 68b265f0..54d0a0a0 100644
--- a/converter/pbm/pbmtopsg3.c
+++ b/converter/pbm/pbmtopsg3.c
@@ -26,6 +26,7 @@
 #include <unistd.h>
 #include <ctype.h>
 
+#include "pm_c_util.h"
 #include "pbm.h"
 #include "shhopt.h"
 
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..340642ce 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,114 @@
 ** 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 "pm_c_util.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
+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) {
+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
@@ -34,7 +131,7 @@ generateName(char const filenameArg[], const char ** const nameP) {
    "noname".  Also, if the argument is null or ends in a slash, we
    return "noname".
 -----------------------------------------------------------------------------*/
-    if (STREQ(filenameArg, "-"))
+    if (streq(filenameArg, "-"))
         *nameP = strdup("noname");
     else {
         int nameIndex, argIndex;
@@ -67,99 +164,248 @@ 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) ? "" : ",");
+        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;
 
-    pm_close(ifp);
+    for (i = 0; i < itemCnt; ++i) {
+        int rc;
 
-    if (bitsperitem > 0)
-        PUTITEM;
-    printf("};\n");
+        rc = printf("%s0x%02x%s",
+                    (i == 0)  ? " " : "",
+                    itemBuff[i],
+                    (i == itemCnt - 1) ? "" : ",");
+
+        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;
+}
+
+
+
+static void
+putterm(void) {
+
+    switch (itemVersion) {
+    case X10: puttermX10(); break;
+    case X11: puttermX11(); break;
+    }
+
+    {
+        int rc;
+
+        rc = printf("};\n");
+
+        if (rc < 0)        
+            pm_error("Error writing end of X11 bitmap raster.  "
+                     "printf() failed with errno %d (%s)",
+                     errno, strerror(errno));
+    }
+}
+
+
+
+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);
+    
+    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;
+        }
+
+        if (padright >= 8)
+            bitrow[bitrowBytes-1] = 0x00;
+
+        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/pbmtozinc.c b/converter/pbm/pbmtozinc.c
index d39b71bc..2df39f0d 100644
--- a/converter/pbm/pbmtozinc.c
+++ b/converter/pbm/pbmtozinc.c
@@ -49,7 +49,7 @@ main(int argc, char * argv[]) {
 	{
         ifp = pm_openr( argv[1] );
         strcpy( name, argv[1] );
-        if ( STREQ( name, "-" ) )
+        if ( streq( name, "-" ) )
             strcpy( name, "noname" );
 
         if ( ( cp = strchr( name, '.' ) ) != 0 )
diff --git a/converter/pbm/pktopbm.c b/converter/pbm/pktopbm.c
index af49e9c7..712f339f 100644
--- a/converter/pbm/pktopbm.c
+++ b/converter/pbm/pktopbm.c
@@ -50,7 +50,7 @@ pktopbm_add_suffix(char *       const name,
     char * const slash = strrchr(name, '/');
     char * const dot   = strrchr(name, '.');
     
-    if ((dot && slash ? dot < slash : !dot) && !STREQ(name, "-"))
+    if ((dot && slash ? dot < slash : !dot) && !streq(name, "-"))
         strcat(name, suffix);
 }
 
diff --git a/converter/pbm/thinkjettopbm.l b/converter/pbm/thinkjettopbm.l
index a66ae07e..71501596 100644
--- a/converter/pbm/thinkjettopbm.l
+++ b/converter/pbm/thinkjettopbm.l
@@ -37,6 +37,7 @@
 #include <string.h>
 #include <errno.h>
 #include <unistd.h>
+#include "pm_c_util.h"
 #include "pbm.h"
 #include "shhopt.h"
 
diff --git a/converter/pbm/xbmtopbm.c b/converter/pbm/xbmtopbm.c
index 7779a9b5..9505ba67 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,382 @@
 ** 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-1] >>= 8 - cols % 8;
+            bitrow[bytesPerRow-1] <<= 8 - cols % 8;
+        }
+            
+        pbm_writepbmrow_packed(stdout, bitrow, cols, 0);
+    }
+
+    pbm_freerow(bitrow);
+    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/Makefile b/converter/pgm/Makefile
index f562fe92..b109683b 100644
--- a/converter/pgm/Makefile
+++ b/converter/pgm/Makefile
@@ -5,7 +5,7 @@ endif
 SUBDIR = converter/pgm
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
 PORTBINARIES =	asciitopgm bioradtopgm fstopgm hipstopgm \
 		lispmtopgm pgmtofs pgmtolispm pgmtopgm \
@@ -20,4 +20,4 @@ MERGE_OBJECTS = $(MERGEBINARIES:%=%.o2)
 .PHONY: all
 all: $(BINARIES)
 
-include $(SRCDIR)/Makefile.common
+include $(SRCDIR)/common.mk
diff --git a/converter/pgm/asciitopgm.c b/converter/pgm/asciitopgm.c
index 42f6e7db..a3a5bd48 100644
--- a/converter/pgm/asciitopgm.c
+++ b/converter/pgm/asciitopgm.c
@@ -68,7 +68,7 @@ main( argc, argv )
 
     if ( argv[argn][0] == '-' )
     {
-        if ( STREQ( argv[argn], "-d" ) )
+        if ( streq( argv[argn], "-d" ) )
         {
             if ( argc == argn + 1 )
                 pm_usage( usage );
diff --git a/converter/pgm/hipstopgm.c b/converter/pgm/hipstopgm.c
index 826a8511..2f5956e1 100644
--- a/converter/pgm/hipstopgm.c
+++ b/converter/pgm/hipstopgm.c
@@ -98,7 +98,7 @@ read_hips_header( fd, hP )
 	{
         read_line( fd, buf, 5000 );
 	}
-    while ( !STREQ( buf, ".\n" ) );
+    while ( !streq( buf, ".\n" ) );
 }
 
 
diff --git a/converter/pgm/lispmtopgm.c b/converter/pgm/lispmtopgm.c
index 7b98ef00..40dd3fb4 100644
--- a/converter/pgm/lispmtopgm.c
+++ b/converter/pgm/lispmtopgm.c
@@ -89,7 +89,7 @@ getinit( file, colsP, rowsP, depthP, padrightP )
     for ( i = 0; i < sizeof(magic)-1; ++i )
         magic[i] = getc( file );
     magic[i]='\0';
-    if (!STREQ(LISPM_MAGIC, magic))
+    if (!streq(LISPM_MAGIC, magic))
         pm_error( "bad id string in Lispm file" );
     
     if ( pm_readlittleshort( file, colsP ) == -1 )
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/pgm/pgmtopgm.c b/converter/pgm/pgmtopgm.c
index c65e98e0..250bb4dc 100644
--- a/converter/pgm/pgmtopgm.c
+++ b/converter/pgm/pgmtopgm.c
@@ -19,7 +19,7 @@ main(int argc, char *argv[]) {
     int rows, cols;
     gray maxval;
     int row;
-    gray* grayrow;
+    gray * grayrow;
     
     pgm_init(&argc, argv);
     
@@ -32,7 +32,7 @@ main(int argc, char *argv[]) {
 
     grayrow = pgm_allocrow(cols);
 
-    for (row = 0; row < rows; row++) {
+    for (row = 0; row < rows; ++row) {
         pgm_readpgmrow(stdin, grayrow, cols, maxval, format);
         pgm_writepgmrow(stdout, grayrow, cols, maxval, 0);
     }
diff --git a/converter/pgm/rawtopgm.c b/converter/pgm/rawtopgm.c
index c91c6178..0180a02c 100644
--- a/converter/pgm/rawtopgm.c
+++ b/converter/pgm/rawtopgm.c
@@ -11,6 +11,8 @@
 */
 
 #include <math.h>
+
+#include "pm_c_util.h"
 #include "pgm.h"
 #include "shhopt.h"
 
@@ -18,13 +20,13 @@ struct cmdline_info {
     /* 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 * inputFileName;
     unsigned int headerskip;
     float rowskip;
     int bottomfirst;  /* the -bottomfirst/-bt option */
     int autosize;  /* User wants us to figure out the size */
-    int width;
-    int height;
+    unsigned int width;
+    unsigned int height;
     int bpp;
       /* bytes per pixel in input format.  1 or 2 */
     int littleendian;
@@ -74,21 +76,21 @@ parse_command_line(int argc, char ** argv,
         /* Uses and sets argc, argv, and some of *cmdline_p and others. */
 
     if (argc-1 == 0) {
-        cmdline_p->input_filespec = "-";
+        cmdline_p->inputFileName = "-";
         cmdline_p->autosize = TRUE;
     } else if (argc-1 == 1) {
-        cmdline_p->input_filespec = argv[1];
+        cmdline_p->inputFileName = argv[1];
         cmdline_p->autosize = TRUE;
     } else if (argc-1 == 2) {
-        cmdline_p->input_filespec = "-";
+        cmdline_p->inputFileName = "-";
         cmdline_p->autosize = FALSE;
-        cmdline_p->width = atoi(argv[1]);
-        cmdline_p->height = atoi(argv[2]);
+        cmdline_p->width = pm_parse_width(argv[1]);
+        cmdline_p->height = pm_parse_height(argv[2]);
     } else if (argc-1 == 3) {
-        cmdline_p->input_filespec = argv[3];
+        cmdline_p->inputFileName = argv[3];
         cmdline_p->autosize = FALSE;
-        cmdline_p->width = atoi(argv[1]);
-        cmdline_p->height = atoi(argv[2]);
+        cmdline_p->width = pm_parse_width(argv[1]);
+        cmdline_p->height = pm_parse_height(argv[2]);
     } else
         pm_error("Program takes zero, one, two, or three arguments.  You "
                  "specified %d", argc-1);
@@ -107,11 +109,6 @@ parse_command_line(int argc, char ** argv,
         pm_error("Maxval must be less than 65536.  You specified %d.",
                  cmdline_p->maxval);
 
-    if (cmdline_p->width <= 0) 
-        pm_error("Width must be a positive number.");
-    if (cmdline_p->height <= 0) 
-        pm_error("Height must be a positive number.");
-
     if (cmdline_p->rowskip && cmdline_p->autosize)
         pm_error("If you specify -rowskip, you must also give the image "
                  "dimensions.");
@@ -221,7 +218,7 @@ main(int argc, char *argv[] ) {
 
     parse_command_line(argc, argv, &cmdline);
 
-    ifp = pm_openr(cmdline.input_filespec);
+    ifp = pm_openr(cmdline.inputFileName);
 
     if (cmdline.autosize || cmdline.bottomfirst) {
         buf = pm_read_unknown_size( ifp, &nread );
diff --git a/converter/pgm/sbigtopgm.c b/converter/pgm/sbigtopgm.c
index 228b71b3..dd4e921a 100644
--- a/converter/pgm/sbigtopgm.c
+++ b/converter/pgm/sbigtopgm.c
@@ -142,7 +142,7 @@ int main(argc, argv)
 	    cols = atoi(hdr + 6);
         } else if (strncmp(hdr, "sat_level=", 10) == 0) {
 	    maxval = atoi(hdr + 10);
-        } else if (STREQ(hdr, "end")) {
+        } else if (streq(hdr, "end")) {
 	    break;
 	}
 	hdr = cp + 1;
diff --git a/converter/ppm/411toppm.c b/converter/ppm/411toppm.c
index a5b25ac1..6ece4c4b 100644
--- a/converter/ppm/411toppm.c
+++ b/converter/ppm/411toppm.c
@@ -58,6 +58,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include "pm_c_util.h"
 #include "ppm.h"
 #include "shhopt.h"
 #include "mallocvar.h"
diff --git a/converter/ppm/Makefile b/converter/ppm/Makefile
index 31ca826b..adc3a400 100644
--- a/converter/ppm/Makefile
+++ b/converter/ppm/Makefile
@@ -5,7 +5,7 @@ endif
 SUBDIR = converter/ppm
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
 SUBDIRS = hpcdtoppm ppmtompeg
 
@@ -42,7 +42,7 @@ MERGE_OBJECTS = $(BINARIES:%=%.o2)
 .PHONY: all
 all: $(BINARIES) $(SUBDIRS:%=%/all)
 
-include $(SRCDIR)/Makefile.common
+include $(SRCDIR)/common.mk
 
 ppmtobmp.o ppmtobmp.o2: bmp.h
 
diff --git a/converter/ppm/eyuvtoppm.c b/converter/ppm/eyuvtoppm.c
index dcbb9547..33d57409 100644
--- a/converter/ppm/eyuvtoppm.c
+++ b/converter/ppm/eyuvtoppm.c
@@ -34,6 +34,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
+
+#include "pm_c_util.h"
 #include "ppm.h"
 #include "shhopt.h"
 #include "mallocvar.h"
diff --git a/converter/ppm/hpcdtoppm/Makefile b/converter/ppm/hpcdtoppm/Makefile
index 9a7c67d0..ddf79ee5 100644
--- a/converter/ppm/hpcdtoppm/Makefile
+++ b/converter/ppm/hpcdtoppm/Makefile
@@ -5,21 +5,21 @@ endif
 SUBDIR = converter/ppm/hpcdtoppm
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
 all: hpcdtoppm
 
 SCRIPTS = hpcdtoppm pcdovtoppm
 MERGE_OBJECTS =
 
-include $(SRCDIR)/Makefile.common
+include $(SRCDIR)/common.mk
 
 install: install.bin.local
 .PHONY: install.bin.local
 install.bin.local: $(PKGDIR)/bin
 # In June 2002, pcdovtoppm replaced pcdindex
 	cd $(PKGDIR)/bin ; \
-	$(SYMLINK) pcdindex$(EXE) pcdovtoppm
+	$(SYMLINK) pcdindex$(EXE) pcdovtoppm$(EXE)
 
 
 FORCE:
diff --git a/converter/ppm/ilbmtoppm.c b/converter/ppm/ilbmtoppm.c
index 5001741a..5ceb70b6 100644
--- a/converter/ppm/ilbmtoppm.c
+++ b/converter/ppm/ilbmtoppm.c
@@ -1,4 +1,4 @@
-/* ilbmtoppm.c - read an IFF ILBM file and produce a portable pixmap
+/* ilbmtoppm.c - read an IFF ILBM file and produce a PPM
 **
 ** Copyright (C) 1989 by Jef Poskanzer.
 **
@@ -43,11 +43,10 @@
 #include <string.h>
 
 #include "pm_c_util.h"
-#include "ppm.h"
-#include "ilbm.h"
 #include "mallocvar.h"
-
-/*#define DEBUG*/
+#include "intcode.h"
+#include "ilbm.h"
+#include "ppm.h"
 
 typedef struct {
     int reg;            /* color register to change */
@@ -764,10 +763,15 @@ multi_free(cmap)
  ****************************************************************************/
 
 static void
-check_cmap(bmhd, cmap)
-    BitMapHeader *bmhd;
-    ColorMap *cmap;
-{
+prepareCmap(const BitMapHeader * const bmhd,
+            ColorMap *           const cmap) {
+/*----------------------------------------------------------------------------
+   This is a really ugly subroutine that 1) analyzes a colormap and its
+   context (returning the analysis in global variables); and 2) modifies that
+   color map, because it's really one type of data structure as input and
+   another as output.
+
+-----------------------------------------------------------------------------*/
     pixval colmaxval = 0;
     int shifted = 1;
     int i, r, g, b;
@@ -990,6 +994,8 @@ std_to_ppm(FILE *         const ifp,
            ColorMap *     const cmap, 
            long           const viewportmodes);
 
+
+
 static void
 ham_to_ppm(FILE *         const ifp, 
            long           const chunksize, 
@@ -1255,7 +1261,7 @@ dcol_to_ppm(FILE *         const ifP,
     unsigned int const greenplanes = dcol->g;
     unsigned int const blueplanes  = dcol->b;
     
-    int col, row, i;
+    int col, row;
     rawtype *Rrow, *Grow, *Brow;
     pixval maxval, redmaxval, greenmaxval, bluemaxval;
     pixval *redtable, *greentable, *bluetable;
@@ -1301,13 +1307,15 @@ dcol_to_ppm(FILE *         const ifP,
     MALLOCARRAY_NOFAIL(greentable, greenmaxval +1);
     MALLOCARRAY_NOFAIL(bluetable,  bluemaxval  +1);
 
-    for( i = 0; i <= redmaxval; i++ )
-        redtable[i] = (i * maxval + redmaxval/2)/redmaxval;
-    for( i = 0; i <= greenmaxval; i++ )
-        greentable[i] = (i * maxval + greenmaxval/2)/greenmaxval;
-    for( i = 0; i <= bluemaxval; i++ )
-        bluetable[i] = (i * maxval + bluemaxval/2)/bluemaxval;
-
+    {
+        unsigned int i;
+        for (i = 0; i <= redmaxval; ++i)
+            redtable[i] = ROUNDDIV(i * maxval, redmaxval);
+        for (i = 0; i <= greenmaxval; ++i)
+            greentable[i] = ROUNDDIV(i * maxval, greenmaxval);
+        for (i = 0; i <= bluemaxval; ++i)
+            bluetable[i] = ROUNDDIV(i * maxval, bluemaxval);
+    }
     if( transpName ) {
         MALLOCVAR_NOFAIL(transpColor);
         *transpColor = ppm_parsecolor(transpName, maxval);
@@ -1343,16 +1351,10 @@ dcol_to_ppm(FILE *         const ifP,
 
 
 static void
-cmap_to_ppm(cmap)
-    ColorMap *cmap;
-{
-    ppm_colorrowtomapfile(stdout, cmap->color, cmap->ncolors, MAXCOLVAL);
-#if 0
-    int i;
-    ppm_writeppminit(stdout, cmap->ncolors, 1, MAXCOLVAL, 1);
-    for( i = 0; i < cmap->ncolors; i++ )
-        ppm_writeppmrow(stdout, &(cmap->color[i]), 1, MAXCOLVAL, 1);
-#endif
+cmapToPpm(FILE *     const ofP,
+            ColorMap * const cmapP) {
+
+    ppm_colorrowtomapfile(ofP, cmapP->color, cmapP->ncolors, MAXCOLVAL);
 }
 
 
@@ -1657,39 +1659,41 @@ PCHG_DecompHuff(src, dest, tree, origsize)
 }
 
 
+
 static void
-PCHG_Decompress(PCHG, CompHdr, compdata, compsize, comptree, data)
-    PCHGHeader *PCHG;
-    PCHGCompHeader *CompHdr;
-    unsigned char *compdata;
-    unsigned long compsize;
-    unsigned char *comptree;
-    unsigned char *data;
-{
-    short *hufftree;
-    unsigned long huffsize, i;
-    unsigned long treesize = CompHdr->CompInfoSize;
+PCHG_Decompress(PCHGHeader *     const PCHG,
+                PCHGCompHeader * const CompHdr,
+                unsigned char *  const compdata,
+                unsigned long    const compsize,
+                unsigned char *  const comptree,
+                unsigned char *  const data) {
 
-    switch( PCHG->Compression ) {
-        case PCHG_COMP_HUFFMAN:
+    switch(PCHG->Compression) {
+    case PCHG_COMP_HUFFMAN: {
+        unsigned long const treesize = CompHdr->CompInfoSize;
+        unsigned long const huffsize = treesize / 2;
+        const bigend16 * const bigendComptree = (const void *)comptree;
 
-#ifdef DEBUG
-            pm_message("PCHG Huffman compression");
-#endif
-            /* turn big-endian 2-byte shorts into native format */
-            huffsize = treesize/2;
-            MALLOCARRAY_NOFAIL(hufftree, huffsize);
-            for( i = 0; i < huffsize; i++ ) {
-                hufftree[i] = (short)BIG_WORD(comptree);
-                comptree += 2;
-            }
+        short * hufftree;
+        unsigned long i;
 
-            /* decompress the change structure data */
-            PCHG_DecompHuff(compdata, data, &hufftree[huffsize-1], 
-                            CompHdr->OriginalDataSize);
+        /* Convert big-endian 2-byte shorts to C shorts */
 
-            free(hufftree);
-            break;
+        MALLOCARRAY(hufftree, huffsize);
+
+        if (!hufftree)
+            pm_error("Couldn't get memory for %lu-byte Huffman tree",
+                     huffsize);
+
+        for (i = 0; i < huffsize; ++i)
+            hufftree[i] = pm_uintFromBigend16(bigendComptree[i]);
+
+        /* decompress the change structure data */
+        PCHG_DecompHuff(compdata, data, &hufftree[huffsize-1], 
+                        CompHdr->OriginalDataSize);
+        
+        free(hufftree);
+    } break;
         default:
             pm_error("unknown PCHG compression type %d", PCHG->Compression);
     }
@@ -1798,94 +1802,119 @@ fail2:
 }
 
 
+
 static void
-PCHG_ConvertBig(PCHG, cmap, mask, datasize)
-    PCHGHeader *PCHG;
-    ColorMap *cmap;
-    unsigned char *mask;
-    unsigned long datasize;
-{
-    unsigned char *data;
+PCHG_ConvertBig(PCHGHeader *    const PCHG,
+                ColorMap *      const cmap,
+                unsigned char * const maskStart,
+                unsigned long   const datasize) {
+
+    unsigned char * data;
     unsigned char thismask;
-    int bits, row, i, changes, masklen, reg;
-    unsigned long totalchanges = 0;
-    int changedlines = PCHG->ChangedLines;
+    int bits;
+    unsigned int row;
+    int changes;
+    int masklen;
+    int reg;
+    unsigned long totalchanges;
+    int changedlines;
+    unsigned long dataRemaining;
+    unsigned char * mask;
+
+    mask = maskStart;  /* initial value */
+    dataRemaining = datasize;  /* initial value */
+    changedlines = PCHG->ChangedLines;  /* initial value */
+    totalchanges = 0;  /* initial value */
 
     masklen = 4 * MaskLongWords(PCHG->LineCount);
-    data = mask + masklen; datasize -= masklen;
+    data = mask + masklen; dataRemaining -= masklen;
 
-    bits = 0;
-    for( row = PCHG->StartLine; changedlines && row < 0; row++ ) {
-        if( bits == 0 ) {
-            if( masklen == 0 ) goto fail2;
+    for (row = PCHG->StartLine, bits = 0; changedlines && row < 0; ++row) {
+        if (bits == 0) {
+            if (masklen == 0)
+                pm_error("insufficient data in line mask");
             thismask = *mask++;
             --masklen;
             bits = 8;
         }
-        if( thismask & (1<<7) ) {
-            if( datasize < 2 ) goto fail;
-            changes = BIG_WORD(data); data += 2; datasize -= 2;
+        if (thismask & (1<<7)) {
+            unsigned int i;
+
+            if (dataRemaining < 2)
+                pm_error("insufficient data in BigLineChanges structures");
+
+            changes = BIG_WORD(data); data += 2; dataRemaining -= 2;
+
+            for (i = 0; i < changes; ++i) {
+                if (totalchanges >= PCHG->TotalChanges)
+                    pm_error("insufficient data in BigLineChanges structures");
+
+                if (dataRemaining < 6)
+                    pm_error("insufficient data in BigLineChanges structures");
 
-            for( i = 0; i < changes; i++ ) {
-                if( totalchanges >= PCHG->TotalChanges ) goto fail;
-                if( datasize < 6 ) goto fail;
                 reg = BIG_WORD(data); data += 2;
                 cmap->mp_init[reg - PCHG->MinReg].reg = reg;
                 ++data; /* skip alpha */
                 cmap->mp_init[reg - PCHG->MinReg].r = *data++;
                 cmap->mp_init[reg - PCHG->MinReg].b = *data++;  /* yes, RBG */
                 cmap->mp_init[reg - PCHG->MinReg].g = *data++;
-                datasize -= 6;
+                dataRemaining -= 6;
                 ++totalchanges;
             }
             --changedlines;
         }
         thismask <<= 1;
-        bits--;
+        --bits;
     }
 
-    for( row = PCHG->StartLine; changedlines && row < cmap->mp_rows; row++ ) {
-        if( bits == 0 ) {
-            if( masklen == 0 ) goto fail2;
+    for (row = PCHG->StartLine; changedlines && row < cmap->mp_rows; ++row) {
+        if (bits == 0) {
+            if (masklen == 0)
+                pm_error("insufficient data in line mask");
+
             thismask = *mask++;
             --masklen;
             bits = 8;
         }
-        if( thismask & (1<<7) ) {
-            if( datasize < 2 ) goto fail;
-            changes = BIG_WORD(data); data += 2; datasize -= 2;
+        if (thismask & (1<<7)) {
+            unsigned int i;
+
+            if (dataRemaining < 2)
+                pm_error("insufficient data in BigLineChanges structures");
+
+            changes = BIG_WORD(data); data += 2; dataRemaining -= 2;
 
             MALLOCARRAY_NOFAIL(cmap->mp_change[row], changes + 1);
-            for( i = 0; i < changes; i++ ) {
-                if( totalchanges >= PCHG->TotalChanges ) goto fail;
-                if( datasize < 6 ) goto fail;
+            for (i = 0; i < changes; ++i) {
+                if (totalchanges >= PCHG->TotalChanges)
+                    pm_error("insufficient data in BigLineChanges structures");
+
+                if (dataRemaining < 6)
+                    pm_error("insufficient data in BigLineChanges structures");
+
                 reg = BIG_WORD(data); data += 2;
                 cmap->mp_change[row][i].reg = reg;
                 ++data; /* skip alpha */
                 cmap->mp_change[row][i].r = *data++;
                 cmap->mp_change[row][i].b = *data++;    /* yes, RBG */
                 cmap->mp_change[row][i].g = *data++;
-                datasize -= 6;
+                dataRemaining -= 6;
                 ++totalchanges;
             }
             cmap->mp_change[row][changes].reg = MP_REG_END;
             --changedlines;
         }
         thismask <<= 1;
-        bits--;
+        --bits;
     }
-    if( totalchanges != PCHG->TotalChanges )
+    if (totalchanges != PCHG->TotalChanges)
         pm_message("warning - got %ld change structures, "
                    "chunk header reports %ld", 
                    totalchanges, PCHG->TotalChanges);
-    return;
-fail:
-    pm_error("insufficient data in BigLineChanges structures");
-fail2:
-    pm_error("insufficient data in line mask");
 }
 
 
+
 static void
 read_pchg(FILE *     const ifp,
           IFF_ID     const iffid,
@@ -1939,7 +1968,7 @@ read_pchg(FILE *     const ifp,
             read_bytes(ifp, treesize, comptree, iffid, &remainingChunksize);
 
             compsize = remainingChunksize;
-            MALLOCARRAY_NOFAIL(compdata, remainingChunksize);
+            MALLOCARRAY_NOFAIL(compdata, compsize);
             read_bytes(ifp, compsize, compdata, iffid, &remainingChunksize);
 
             datasize = CompHdr.OriginalDataSize;
@@ -2033,7 +2062,7 @@ process_body( FILE *          const ifp,
         pm_error("%s chunk without %s chunk", 
                  ID2string(ID_BODY), ID2string(ID_BMHD));
 
-    check_cmap(bmhdP, cmap);
+    prepareCmap(bmhdP, cmap);
 
     pixelrow = ppm_allocrow(bmhdP->w);
     if( maskfile ) {
@@ -2081,21 +2110,21 @@ process_body( FILE *          const ifp,
 
 
 static void 
-process_chunk(FILE *          const ifp,
-              long            const formsize,
-              IFF_ID          const ignorelist[],
-              unsigned int    const ignorecount,
-              int             const fakeviewport,
-              int             const viewportmask,
-              int             const isdeepopt,
-              bool            const cmaponly,
-              bool *          const bodyChunkProcessedP,
-              bool *          const endchunkP,
-              BitMapHeader ** const bmhdP,
-              ColorMap *      const cmap,
-              DirectColor **  const dcolP,
-              int *           const viewportmodesP,
-              long *          const bytesReadP
+processChunk(FILE *          const ifP,
+             long            const formsize,
+             IFF_ID          const ignorelist[],
+             unsigned int    const ignorecount,
+             int             const fakeviewport,
+             int             const viewportmask,
+             int             const isdeepopt,
+             bool            const cmaponly,
+             bool *          const bodyChunkProcessedP,
+             bool *          const endchunkP,
+             BitMapHeader ** const bmhdP,
+             ColorMap *      const cmap,
+             DirectColor **  const dcolP,
+             int *           const viewportmodesP,
+             long *          const bytesReadP
     ) {
 
     IFF_ID iffid;
@@ -2104,129 +2133,168 @@ process_chunk(FILE *          const ifp,
 
     bytesread = 0;
 
-    iffid = get_big_long(ifp, ID_FORM, NULL);
-    chunksize = get_big_long(ifp, iffid, NULL);
+    iffid = get_big_long(ifP, ID_FORM, NULL);
+    chunksize = get_big_long(ifP, iffid, NULL);
     bytesread += 8;
 
     if (debug)
-        pm_message("reading %s chunk: %ld bytes", 
-                   ID2string(iffid), chunksize);
+        pm_message("reading %s chunk: %ld bytes", ID2string(iffid), chunksize);
 
-    if( ignored_iffid(iffid, ignorelist, ignorecount) ) {
+    if (ignored_iffid(iffid, ignorelist, ignorecount)) {
         pm_message("ignoring %s chunk", ID2string(iffid));
-        skip_chunk(ifp, iffid, chunksize);
-    } else if( iffid == ID_END ) {
+        skip_chunk(ifP, iffid, chunksize);
+    } else if (iffid == ID_END) {
         /* END chunks are not officially valid in IFF, but
            suggested as a future expansion for stream-writing,
            see Amiga RKM Devices, 3rd Ed, page 376 
         */
-        if( chunksize != 0 ) {
+        if (chunksize != 0 ) {
             pm_message("warning - non-0 %s chunk", ID2string(iffid));
-            skip_chunk(ifp, iffid, chunksize);
+            skip_chunk(ifP, iffid, chunksize);
         }
-        if( formsize != 0xffffffff )
+        if (formsize != 0xffffffff)
             pm_message("warning - %s chunk with FORM size 0x%08lx "
                        "(should be 0x%08x)",
                        ID2string(iffid), formsize, 0xffffffff);
         *endchunkP = 1;
-    } else if( *bodyChunkProcessedP ) {
+    } else if (*bodyChunkProcessedP) {
         pm_message("%s chunk found after %s chunk - skipping", 
                    ID2string(iffid), ID2string(ID_BODY));
-        skip_chunk(ifp, iffid, chunksize);
+        skip_chunk(ifP, iffid, chunksize);
     } else
-        switch( iffid ) {
+        switch (iffid) {
         case ID_BMHD:
-            *bmhdP = read_bmhd(ifp, iffid, chunksize);
+            *bmhdP = read_bmhd(ifP, iffid, chunksize);
             break;
         case ID_CMAP:
-            read_cmap(ifp, iffid, chunksize, cmap);
+            read_cmap(ifP, iffid, chunksize, cmap);
             break;
         case ID_CMYK:
-            read_cmyk(ifp, iffid, chunksize, cmap);
+            read_cmyk(ifP, iffid, chunksize, cmap);
             break;
         case ID_CLUT:
-            read_clut(ifp, iffid, chunksize, cmap);
+            read_clut(ifP, iffid, chunksize, cmap);
             break;
         case ID_CAMG:
-            if( chunksize != CAMGChunkSize )
+            if (chunksize != CAMGChunkSize)
                 pm_error("%s chunk size mismatch", ID2string(iffid));
-            *viewportmodesP = get_big_long(ifp, ID_CAMG, NULL);
+            *viewportmodesP = get_big_long(ifP, ID_CAMG, NULL);
             *viewportmodesP &= viewportmask;      /* -isnotham/-isnotehb */
             break;
         case ID_PCHG:
-            read_pchg(ifp, iffid, chunksize, cmap);
+            read_pchg(ifP, iffid, chunksize, cmap);
             break;
         case ID_CTBL:
         case ID_SHAM:
-            read_4bit_mp(ifp, iffid, chunksize, cmap);
+            read_4bit_mp(ifP, iffid, chunksize, cmap);
             break;
         case ID_DCOL:
-            if( chunksize != DirectColorSize )
+            if (chunksize != DirectColorSize)
                 pm_error("%s chunk size mismatch", ID2string(iffid));
             MALLOCVAR_NOFAIL(*dcolP);
-            (*dcolP)->r = get_byte(ifp, iffid, NULL);
-            (*dcolP)->g = get_byte(ifp, iffid, NULL);
-            (*dcolP)->b = get_byte(ifp, iffid, NULL);
-            (void)get_byte(ifp, iffid, NULL);       /* skip pad byte */
+            (*dcolP)->r = get_byte(ifP, iffid, NULL);
+            (*dcolP)->g = get_byte(ifP, iffid, NULL);
+            (*dcolP)->b = get_byte(ifP, iffid, NULL);
+            get_byte(ifP, iffid, NULL);       /* skip pad byte */
             break;
         case ID_BODY: 
-            if( cmaponly || (*bmhdP && (*bmhdP)->nPlanes == 0 )) {
-                skip_chunk(ifp, ID_BODY,  chunksize);
-                return;
-            }
-    
-            process_body(ifp, chunksize, *bmhdP, cmap, 
-                         maskfile, fakeviewport, isdeepopt, *dcolP,
-                         viewportmodesP);
-
-            *bodyChunkProcessedP = TRUE;
+            if (cmaponly || (*bmhdP && (*bmhdP)->nPlanes == 0))
+                skip_chunk(ifP, ID_BODY,  chunksize);
+            else {
+                process_body(ifP, chunksize, *bmhdP, cmap, 
+                             maskfile, fakeviewport, isdeepopt, *dcolP,
+                             viewportmodesP);
 
-            break;
+                *bodyChunkProcessedP = TRUE;
+            } break;
         case ID_GRAB:   case ID_DEST:   case ID_SPRT:   case ID_CRNG:
         case ID_CCRT:   case ID_DYCP:   case ID_DPPV:   case ID_DRNG:
         case ID_EPSF:   case ID_JUNK:   case ID_CNAM:   case ID_PRVW:
         case ID_TINY:   case ID_DPPS:
-            skip_chunk(ifp, iffid, chunksize);
+            skip_chunk(ifP, iffid, chunksize);
             break;
         case ID_copy:   case ID_AUTH:   case ID_NAME:   case ID_ANNO:
         case ID_TEXT:   case ID_FVER:
-            if( verbose )
-                display_chunk(ifp, iffid, chunksize);
+            if (verbose)
+                display_chunk(ifP, iffid, chunksize);
             else
-                skip_chunk(ifp, iffid, chunksize);
+                skip_chunk(ifP, iffid, chunksize);
             break;
-        case ID_DPI:
-        {
+        case ID_DPI: {
             int x, y;
 
-            x = get_big_short(ifp, ID_DPI, NULL);
-            y = get_big_short(ifp, ID_DPI, NULL);
-            if( verbose )
+            x = get_big_short(ifP, ID_DPI, NULL);
+            y = get_big_short(ifP, ID_DPI, NULL);
+            if (verbose)
                 pm_message("%s chunk:  dpi_x = %d    dpi_y = %d", 
                            ID2string(ID_DPI), x, y);
-        }
-        break;
+        } break;
         default:
             pm_message("unknown chunk type %s - skipping", 
                        ID2string(iffid));
-            skip_chunk(ifp, iffid, chunksize);
+            skip_chunk(ifP, iffid, chunksize);
             break;
         }
 
     bytesread += chunksize;
 
-    if( ODD(chunksize) ) {
-        (void) get_byte(ifp, iffid, NULL);
+    if (ODD(chunksize)) {
+        get_byte(ifP, iffid, NULL);
         bytesread += 1;
     } 
     *bytesReadP = bytesread;
 }
 
 
+
+static void
+maybeWriteColorMap(FILE *               const ofP,
+                   const BitMapHeader * const bmhdP,
+                   ColorMap *           const cmapP,
+                   bool                 const bodyChunkProcessed,
+                   bool                 const cmaponly) {
+/*----------------------------------------------------------------------------
+   Write to file *ofP the color map *cmapP as a PPM, if appropriate.
+
+   The logic (not just here -- in the program as a whole) for deciding whether
+   to write the image or the colormap is quite twisted.  If I thought anyone
+   was actually using this program, I would take the time to straighten it
+   out.
+
+   What's really sick about this subroutine is that in choosing to write
+   a color map, it has to know that Caller hasn't already written
+   the image.  Huge modularity violation.
+-----------------------------------------------------------------------------*/
+    if (cmaponly) {
+        if (HAS_COLORMAP(cmapP)) {
+            prepareCmap(bmhdP, cmapP);
+            cmapToPpm(ofP, cmapP);
+        } else
+            pm_error("You specified -cmaponly, but the ILBM "
+                     "has no colormap");
+    } else if (bmhdP && bmhdP->nPlanes == 0) {
+        if (HAS_COLORMAP(cmapP)) {
+            prepareCmap(bmhdP, cmapP);
+            cmapToPpm(ofP, cmapP);
+        } else
+            pm_error("ILBM has neither a color map nor color planes");
+    } else if (!bodyChunkProcessed) {
+        if (HAS_COLORMAP(cmapP)) {
+            pm_message("input is a colormap file");
+            prepareCmap(bmhdP, cmapP);
+            cmapToPpm(ofP, cmapP);
+        } else
+            pm_error("ILBM has neither %s or %s chunk", 
+                     ID2string(ID_BODY), ID2string(ID_CMAP));
+    }
+}
+
+
+
 int
 main(int argc, char *argv[]) {
 
-    FILE *ifp;
+    FILE * ifP;
     int argn;
     short cmaponly = 0, isdeepopt = 0;
     bool endchunk;
@@ -2300,25 +2368,25 @@ main(int argc, char *argv[]) {
     }    
 
     if( argn < argc ) {
-        ifp = pm_openr( argv[argn] );
+        ifP = pm_openr( argv[argn] );
         argn++;
     } else
-        ifp = stdin;
+        ifP = stdin;
 
     if( argn != argc )
         pm_usage(usage);
 
     /* Read in the ILBM file. */
 
-    firstIffid = get_big_long(ifp, ID_FORM, NULL);
-    if( firstIffid != ID_FORM )
+    firstIffid = get_big_long(ifP, ID_FORM, NULL);
+    if (firstIffid != ID_FORM)
         pm_error("input is not a FORM type IFF file");
-    formsize = get_big_long(ifp, ID_FORM, NULL);
-    typeid = get_big_long(ifp, ID_FORM, NULL);
-    if( typeid != ID_ILBM && typeid != ID_RGBN && typeid != ID_RGB8 && 
-        typeid != ID_PBM )
-        pm_error( "input is not an ILBM, RGBN, RGB8 or PBM "
-                  "type FORM IFF file" );
+    formsize = get_big_long(ifP, ID_FORM, NULL);
+    typeid = get_big_long(ifP, ID_FORM, NULL);
+    if (typeid != ID_ILBM && typeid != ID_RGBN && typeid != ID_RGB8 && 
+        typeid != ID_PBM)
+        pm_error("input is not an ILBM, RGBN, RGB8 or PBM "
+                 "type FORM IFF file");
     bytesread = 4;  /* FORM and formsize do not count */
 
     cmap = alloc_cmap();
@@ -2326,55 +2394,41 @@ main(int argc, char *argv[]) {
     /* Main loop, parsing the IFF FORM. */
     bodyChunkProcessed = FALSE;
     endchunk = FALSE;
-    while( !endchunk && formsize-bytesread >= 8 ) {
-        long bytes_read_for_chunk;
+    while (!endchunk && formsize-bytesread >= 8) {
+        long bytesReadForChunk;
 
-        process_chunk(ifp, formsize, ignorelist, ignorecount,
-                      fakeviewport, viewportmask,
-                      isdeepopt, cmaponly,
-                      &bodyChunkProcessed,
-                      &endchunk, &bmhdP, cmap, &dcol,
-                      &viewportmodes, &bytes_read_for_chunk);
+        processChunk(ifP, formsize, ignorelist, ignorecount,
+                     fakeviewport, viewportmask,
+                     isdeepopt, cmaponly,
+                     &bodyChunkProcessed,
+                     &endchunk, &bmhdP, cmap, &dcol,
+                     &viewportmodes, &bytesReadForChunk);
 
-        bytesread += bytes_read_for_chunk;
+        bytesread += bytesReadForChunk;
     }
 
-    if( maskfile ) {
+    if (maskfile) {
         pm_close(maskfile);
-        if( !wrotemask )
+        if (!wrotemask)
             remove(maskname);
         pbm_freerow(maskrow);
     }
 
-    if( cmaponly || (bmhdP && bmhdP->nPlanes == 0 )) {
-        if( HAS_COLORMAP(cmap) ) {
-            check_cmap(bmhdP, cmap);
-            cmap_to_ppm(cmap);
-        } else
-            pm_error("no colormap");
-    } else if( !bodyChunkProcessed ) {
-        if( HAS_COLORMAP(cmap) ) {
-            pm_message("input is a colormap file");
-            check_cmap(bmhdP, cmap);
-            cmap_to_ppm(cmap);
-        } else
-            pm_error("no %s or %s chunk found", 
-                     ID2string(ID_BODY), ID2string(ID_CMAP));
-    }
+    maybeWriteColorMap(stdout, bmhdP, cmap, bodyChunkProcessed, cmaponly);
 
     {
         unsigned int skipped;
         
-        for( skipped = 0; fgetc(ifp) != EOF; ++skipped )
-            bytesread++;
+        for (skipped = 0; fgetc(ifP) != EOF; ++skipped)
+            ++bytesread;
 
-        if( skipped > 0 )
+        if (skipped > 0)
             pm_message("skipped %u extraneous byte%s after last chunk",
                        skipped, (skipped == 1 ? "" : "s"));
     }
-    pm_close(ifp);
+    pm_close(ifP);
 
-    if( !endchunk && bytesread != formsize ) {
+    if (!endchunk && bytesread != formsize) {
         pm_message("warning - file length/FORM size field mismatch "
                    "(%ld != %ld+8)",
                    bytesread+8 /* FORM+size */, formsize);
diff --git a/converter/ppm/mitsu.h b/converter/ppm/mitsu.h
index 8676a39d..bca4fbdf 100644
--- a/converter/ppm/mitsu.h
+++ b/converter/ppm/mitsu.h
@@ -1,7 +1,6 @@
 #ifndef MITSU_H_INCLUDED
 #define MITSU_H_INCLUDED
 
-/* static char SCCSid[] = "@(#)mitsu.h\t\t1.3\t(SPZ)\t3/11/92\n"; */
 #define MAXLUTCOL   255
 
 #define A4_MAXCOLS  1184
diff --git a/converter/ppm/pcxtoppm.c b/converter/ppm/pcxtoppm.c
index 9f403538..25a81531 100644
--- a/converter/ppm/pcxtoppm.c
+++ b/converter/ppm/pcxtoppm.c
@@ -31,6 +31,7 @@
  *  - moved check of 16-color-palette into pcx_16col_to_ppm(),
  *    now checks if it contains only a single color
  */
+#include "pm_c_util.h"
 #include "mallocvar.h"
 #include "shhopt.h"
 #include "ppm.h"
diff --git a/converter/ppm/picttoppm.c b/converter/ppm/picttoppm.c
index d52963fc..9a7d8e7c 100644
--- a/converter/ppm/picttoppm.c
+++ b/converter/ppm/picttoppm.c
@@ -94,16 +94,16 @@ struct rgbPlanes {
     word * blu;
 };
 
+struct canvas {
+    struct rgbPlanes planes;
+};
+
 typedef void (*transfer_func) (struct RGBColor* src, struct RGBColor* dst);
 
-static const char* stage;
+static const char * stage;
 static struct Rect picFrame;
-static word* red;
-static word* green;
-static word* blue;
 static word rowlen;
 static word collen;
-static longword planelen;
 static int verbose;
 static int fullres;
 static int recognize_comment;
@@ -142,13 +142,6 @@ static int ps_cent_x;
 static int ps_cent_y;
 static int ps_cent_set;
 
-struct opdef {
-    const char* name;
-    int len;
-    void (*impl) (int);
-    const char* description;
-};
-
 struct raster {
 /*----------------------------------------------------------------------------
    An image raster.  May be either truecolor or paletted.
@@ -178,13 +171,28 @@ struct raster {
 };
 
 
+
 static void
 allocateRaster(struct raster * const rasterP,
                unsigned int    const width,
                unsigned int    const height,
                unsigned int    const bitsPerPixel) {
+/*----------------------------------------------------------------------------
+   Allocate storage for a raster that can contain a 'width' x 'height'
+   pixel rectangle read from a PICT image with 'bitsPerPixel' bits
+   per pixel.
+
+   Make the space large enough to round the number of pixels up to a
+   multiple of 16, because we've seen many images in which the PICT raster
+   does contain that much padding on the right.  I don't know why; I could
+   understand a multiple of 8, since in 1 bpp image, the smallest unit
+   expressable in PICT is 8 pixels.  But why 16?  The images we saw came
+   from Adobe Illustrator 10 in March 2007, supplied by
+   Guillermo Gómez Valcárcel.
+-----------------------------------------------------------------------------*/
+    unsigned int const allocWidth = ROUNDUP(width, 16);
 
-    if (width > UINT_MAX/4)
+    if (width > UINT_MAX/4 - 16)
         pm_error("Width %u pixels too large for arithmetic", width);
 
     rasterP->rowCount = height;
@@ -209,16 +217,16 @@ allocateRaster(struct raster * const rasterP,
            We have yet to see if we can properly interpret the data.
         */
 
-        rasterP->rowSize = width * 4;
+        rasterP->rowSize = allocWidth * 4;
         break;
     case 16:
-        rasterP->rowSize = width * 2;
+        rasterP->rowSize = allocWidth * 2;
         break;
     case 8:
     case 4:
     case 2:
     case 1:
-        rasterP->rowSize = width * 1;
+        rasterP->rowSize = allocWidth * 1;
         break;
     default:
         pm_error("INTERNAL ERROR: impossible bitsPerPixel value in "
@@ -248,13 +256,30 @@ struct blit_info {
     struct raster      srcplane;
     int                pixSize;
     struct Rect        dstRect;
-    struct RGBColor *  color_map;
+    struct RGBColor *  colorMap;
     int                mode;
     struct blit_info * next;
 };
 
-static struct blit_info* blit_list = 0;
-static struct blit_info** last_bl = &blit_list;
+typedef struct {
+    struct blit_info * firstP;
+    struct blit_info ** connectorP;
+    bool unblittableText;
+        /* The image contains text opcodes, and we don't know how to put that
+           in a blit list (I really don't even know what a blit _is_), so
+           the image information here is incomplete.
+        */
+} blitList;
+
+
+typedef void (drawFn)(struct canvas *, blitList *, int);
+
+struct opdef {
+    const char* name;
+    int len;
+    drawFn * impl;
+    const char* description;
+};
 
 #define WORD_LEN (-1)
 
@@ -589,15 +614,25 @@ picComment(word const type,
 
 
 
+static drawFn ShortComment;
+
 static void
-ShortComment(int const version) {
+ShortComment(struct canvas * const canvasP,
+             blitList *      const blitListP,
+             int             const version) {
+
     picComment(read_word(), 0);
 }
 
 
 
+static drawFn LongComment;
+
 static void
-LongComment(int const version) {
+LongComment(struct canvas * const canvasP,
+            blitList *      const blitListP,
+            int             const version) {
+
     word type;
 
     type = read_word();
@@ -606,8 +641,13 @@ LongComment(int const version) {
 
 
 
+static drawFn skip_poly_or_region;
+
 static void
-skip_poly_or_region(int const version) {
+skip_poly_or_region(struct canvas * const canvasP,
+                    blitList *      const blitListP,
+                    int             const version) {
+
     stage = "skipping polygon or region";
     skip(read_word() - 2);
 }
@@ -639,56 +679,98 @@ static struct fontinfo** fontlist_ins = &fontlist;
 
 
 
+static void
+tokenize(char *         const s,
+         const char **  const vec,
+         unsigned int   const vecSize,
+         unsigned int * const nTokenP) {
+
+    unsigned int nToken;
+    char * p;
+
+    p = &s[0];   /* start at beginning of string */
+    nToken = 0;  /* no tokens yet */
+
+    while (*p && nToken < vecSize - 1) {
+        if (ISSPACE(*p))
+            *p++ = '\0';
+        else {
+            vec[nToken++] = p;
+            /* Skip to next non-space character or end */
+            while (*p && !ISSPACE(*p))
+                ++p;
+        }
+    }
+    vec[nToken] = NULL;
+
+    *nTokenP = nToken;
+}
+
+
+
+static void
+parseFontLine(const char **      const token,
+              struct fontinfo ** const fontinfoPP) {
+
+    struct fontinfo * fontinfoP;
+
+    MALLOCVAR(fontinfoP);
+    if (fontinfoP == NULL)
+        pm_error("out of memory for font information");
+    MALLOCARRAY(fontinfoP->filename, strlen(token[3] + 1));
+    if (fontinfoP->filename == NULL)
+        pm_error("out of memory for font information file name");
+
+    fontinfoP->font  = atoi(token[0]);
+    fontinfoP->size  = atoi(token[1]);
+    fontinfoP->style = atoi(token[2]);
+    strcpy(fontinfoP->filename, token[3]);
+    fontinfoP->loaded = 0;
+
+    *fontinfoPP = fontinfoP;
+}
+
+
+
 static int 
 load_fontdir(const char * const dirfile) {
 /*----------------------------------------------------------------------------
    Load the font directory from file named 'dirfile'.  Add its contents
    to the global list of fonts 'fontlist'.
 -----------------------------------------------------------------------------*/
-    FILE* fp;
-    int n, nfont;
-    char* arg[5], line[1024];
-    struct fontinfo* fontinfo;
+    FILE * ifP;
+    unsigned int nFont;
+    char line[1024]; 
 
-    if (!(fp = fopen(dirfile, "rb")))
-        return -1;
-    
-    nfont = 0;
-    while (fgets(line, 1024, fp)) {
-        if ((n = mk_argvn(line, arg, 5)) == 0 || arg[0][0] == '#')
-            continue;
-        if (n != 4)
-            continue;
-        MALLOCVAR(fontinfo);
-        if (fontinfo == NULL)
-            pm_error("out of memory for font information");
-        MALLOCARRAY(fontinfo->filename, strlen(arg[3] + 1));
-        if (fontinfo->filename == NULL)
-            pm_error("out of memory for font information file name");
+    ifP = pm_openr(dirfile);
 
-        fontinfo->font = atoi(arg[0]);
-        fontinfo->size = atoi(arg[1]);
-        fontinfo->style = atoi(arg[2]);
-        strcpy(fontinfo->filename, arg[3]);
-        fontinfo->loaded = 0;
+    nFont = 0;
+    while (fgets(line, 1024, ifP) && nFont < INT_MAX) {
+        const char * token[10];
+        unsigned int nToken;
 
-        fontinfo->next = 0;
-        *fontlist_ins = fontinfo;
-        fontlist_ins = &fontinfo->next;
-        nfont++;
-    }
+        tokenize(line, token, ARRAY_SIZE(token), &nToken);
 
-    return nfont;
-}
+        if (nToken == 0) {
+            /* blank line - ignore */
+        } else if (token[0][0] == '#') {
+            /* comment - ignore */
+        } else if (nToken != 4) {
+            /* Unrecognized format - ignore */
+        } else {
+            struct fontinfo * fontinfoP;
 
+            parseFontLine(token, &fontinfoP);
 
+            fontinfoP->next = 0;
+            *fontlist_ins = fontinfoP;
+            fontlist_ins = &fontinfoP->next;
+            ++nFont;
+        }
+    }
+    pm_close(ifP);
 
-static void
-read_rect(struct Rect * const r) {
-    r->top = read_word();
-    r->left = read_word();
-    r->bottom = read_word();
-    r->right = read_word();
+    return nFont;
 }
 
 
@@ -705,6 +787,26 @@ dumpRect(const char * const label,
 
 
 
+static void
+read_rect(struct Rect * const r) {
+
+    r->top    = read_word();
+    r->left   = read_word();
+    r->bottom = read_word();
+    r->right  = read_word();
+
+    if (r->top > r->bottom || r->right < r->left)
+        dumpRect("Invalid rectangle", *r);
+
+    if (r->top > r->bottom)
+        pm_error("Invalid PICT: a rectangle has a top below its bottom");
+    if (r->right < r->left)
+        pm_error("Invalid PICT: a rectangle has a right edge "
+                 "left of its left edge");
+}
+
+
+
 static int
 rectwidth(const struct Rect * const r) {
     return r->right - r->left;
@@ -720,10 +822,10 @@ rectheight(const struct Rect * const r) {
 
 
 static bool
-rectsamesize(const struct Rect * const r1, 
-             const struct Rect * const r2) {
-    return r1->right - r1->left == r2->right - r2->left &&
-           r1->bottom - r1->top == r2->bottom - r2->top ;
+rectsamesize(struct Rect const r1, 
+             struct Rect const r2) {
+    return r1.right - r1.left == r2.right - r2.left &&
+           r1.bottom - r1.top == r2.bottom - r2.top ;
 }
 
 
@@ -753,20 +855,45 @@ rectscale(struct Rect * const r,
 
 
 
-static struct blit_info* 
-add_blit_list(void) {
+static void
+    initBlitList(blitList * const blitListP) {
 
-    struct blit_info * bi;
+    blitListP->firstP          = NULL;
+    blitListP->connectorP      = &blitListP->firstP;
+    blitListP->unblittableText = false;
+}
+
+
+
+static void
+addBlitList(blitList *        const blitListP,
+            struct Rect       const srcRect,
+            struct Rect       const srcBounds,
+            struct raster     const srcplane,
+            int               const pixSize,
+            struct Rect       const dstRect,
+            struct RGBColor * const colorMap,
+            int               const mode) {
+
+    struct blit_info * biP;
     
-    MALLOCVAR(bi);
-    if (bi == NULL)
+    MALLOCVAR(biP);
+    if (biP == NULL)
         pm_error("out of memory for blit list");
-    
-    bi->next = 0;
-    *last_bl = bi;
-    last_bl = &bi->next;
-    
-    return bi;
+    else {
+        biP->srcRect   = srcRect;
+        biP->srcBounds = srcBounds;
+        biP->srcplane  = srcplane;
+        biP->pixSize   = pixSize;
+        biP->dstRect   = dstRect;
+        biP->colorMap  = colorMap;
+        biP->mode      = mode;
+
+        biP->next = NULL;
+
+        *blitListP->connectorP = biP;
+        blitListP->connectorP = &biP->next;
+    }
 }
 
 
@@ -1026,7 +1153,7 @@ static pixval
 redepth(pixval const c,
         pixval const oldMaxval) {
     
-    return (c * PPM_MAXMAXVAL + oldMaxval / 2) / oldMaxval;
+    return ROUNDDIV(c * PPM_MAXMAXVAL, oldMaxval);
 }
 
 
@@ -1245,8 +1372,6 @@ doSameSize(transfer_func           trf,
            struct rgbPlanes  const dst,
            unsigned int      const dstwid) {
 /*----------------------------------------------------------------------------
-   Generalized (but slow) blit.
-
    Transfer pixels from 'src' to 'dst', applying the transfer function
    'trf'.
 
@@ -1419,18 +1544,30 @@ blitIdempotent(unsigned int          const pixSize,
 
 
 static void
-generalBlit(struct Rect       const srcRect, 
-            struct Rect       const srcBounds, 
-            struct raster     const srcplane,
-            int               const pixSize, 
-            struct Rect       const dstRect, 
-            struct Rect       const dstBounds, 
-            int               const dstwid, 
-            struct RGBColor * const color_map, 
-            int               const mode,
-            struct Rect       const clipsrc,
-            struct Rect       const clipdst) {
-    
+doBlit(struct Rect       const srcRect, 
+       struct Rect       const dstRect, 
+       struct Rect       const srcBounds, 
+       struct raster     const srcplane,
+       struct Rect       const dstBounds, 
+       struct rgbPlanes  const canvasPlanes,
+       int               const pixSize, 
+       int               const dstwid, 
+       struct RGBColor * const color_map, 
+       int               const mode) {
+/*----------------------------------------------------------------------------
+   Transfer some pixels from 'srcplane' to 'canvasPlanes', applying the
+   transfer function 'trf'.
+
+   'srcplane' contains the rectangle 'srcBounds' of the image.
+   'canvasPlanes' contains the rectangle 'dstRect' of the image.
+
+   Take the rectangle 'srcRect' of the source image and copy it to the
+   rectangle 'dstRec' of the destination image.
+
+   Each plane of 'canvasPlanes' is one word per pixel and contains actual
+   colors, never a palette index.  It is an array in row-major order
+   with 'dstwid' words per row.
+-----------------------------------------------------------------------------*/
     unsigned char * src;
     struct rgbPlanes dst;
     int dstoff;
@@ -1440,31 +1577,31 @@ generalBlit(struct Rect       const srcRect,
     transfer_func trf;
 
     if (verbose) {
-        dumpRect("copying from:", clipsrc);
-        dumpRect("to:          ", clipdst);
+        dumpRect("copying from:", srcRect);
+        dumpRect("to:          ", dstRect);
         pm_message("a %u x %u area to a %u x %u area",
-                   rectwidth(&clipsrc), rectheight(&clipsrc),
-                   rectwidth(&clipdst), rectheight(&clipdst));
+                   rectwidth(&srcRect), rectheight(&srcRect),
+                   rectwidth(&dstRect), rectheight(&dstRect));
     }
 
     {
         unsigned int const pkpixsize = pixSize == 16 ? 2 : 1;
-        unsigned int const srcRowNumber = clipsrc.top - srcBounds.top;
+        unsigned int const srcRowNumber = srcRect.top - srcBounds.top;
         unsigned int const srcRowOffset =
-            (clipsrc.left - srcBounds.left) * pkpixsize;
+            (srcRect.left - srcBounds.left) * pkpixsize;
         assert(srcRowNumber < srcplane.rowCount);
         assert(srcRowOffset < srcplane.rowSize);
         src = srcplane.bytes + srcRowNumber * srcplane.rowSize + srcRowOffset;
-        xsize = clipsrc.right - clipsrc.left;
-        ysize = clipsrc.bottom - clipsrc.top;
+        xsize = rectwidth(&srcRect);
+        ysize = rectheight(&srcRect);
         srcadd = srcplane.rowSize - xsize * pkpixsize;
     }
 
-    dstoff = (clipdst.top - dstBounds.top) * dstwid +
-        (clipdst.left - dstBounds.left);
-    dst.red = red + dstoff;
-    dst.grn = green + dstoff;
-    dst.blu = blue + dstoff;
+    dstoff = (dstRect.top - dstBounds.top) * dstwid +
+        (dstRect.left - dstBounds.left);
+    dst.red = canvasPlanes.red + dstoff;
+    dst.grn = canvasPlanes.grn + dstoff;
+    dst.blu = canvasPlanes.blu + dstoff;
 
     /* get rid of Text mask mode bit, if (erroneously) set */
     if ((mode & ~64) == 0)
@@ -1472,8 +1609,8 @@ generalBlit(struct Rect       const srcRect,
     else
         trf = transfer(mode & ~64);
 
-    if (!rectsamesize(&clipsrc, &clipdst))
-        doDiffSize(clipsrc, clipdst, pixSize, xsize, ysize,
+    if (!rectsamesize(srcRect, dstRect))
+        doDiffSize(srcRect, dstRect, pixSize, xsize, ysize,
                    trf, color_map, src, srcplane.rowSize, dst, dstwid);
     else {
         if (trf == NULL)
@@ -1491,12 +1628,22 @@ static int
 blit(struct Rect       const srcRect, 
      struct Rect       const srcBounds, 
      struct raster     const srcplane,
+     struct canvas *   const canvasP,
+     blitList *        const blitListP,
      int               const pixSize, 
      struct Rect       const dstRect, 
      struct Rect       const dstBounds, 
      int               const dstwid, 
      struct RGBColor * const color_map, 
      int               const mode) {
+/*----------------------------------------------------------------------------
+   'srcplane' contains the rectangle 'srcBounds' of the image.
+
+   We transfer rectangle 'srcRect' from that.
+
+   if 'blitListP' is non-null, we don't draw anything on 'canvasP'; instead,
+   we add to the list *blitlistP a description of what needs to be drawn.
+-----------------------------------------------------------------------------*/
 
     /* I can't tell what the result value of this function is supposed to mean,
        but I found several return statements that did not set it to anything,
@@ -1511,9 +1658,7 @@ blit(struct Rect       const srcRect,
         retval = 1;
     else {
         /* Almost got it.  Clip source rect with source bounds.
-           clip dest rect with dest bounds.  If source and
-           destination are not the same size, use Pnmscale
-           to get a nicely sized rectangle.
+           clip dest rect with dest bounds.
         */
         struct Rect clipsrc;
         struct Rect clipdst;
@@ -1521,22 +1666,16 @@ blit(struct Rect       const srcRect,
         rectinter(srcBounds, srcRect, &clipsrc);
         rectinter(dstBounds, dstRect, &clipdst);
 
-        if (fullres) {
-            struct blit_info * bi;
-            bi = add_blit_list();
-            bi->srcRect   = clipsrc;
-            bi->srcBounds = srcBounds;
-            bi->srcplane  = srcplane;
-            bi->pixSize   = pixSize;
-            bi->dstRect   = clipdst;
-            bi->color_map = color_map;
-            bi->mode      = mode;
+        if (blitListP) {
+            addBlitList(blitListP,
+                        clipsrc, srcBounds, srcplane, pixSize,
+                        clipdst, color_map, mode);
 
             retval = 0;
         } else {
-            generalBlit(srcRect, srcBounds, srcplane, pixSize,
-                        dstRect, dstBounds, dstwid, color_map, mode,
-                        clipsrc, clipdst);
+            doBlit(clipsrc, clipdst,
+                   srcBounds, srcplane, dstBounds, canvasP->planes,
+                   pixSize, dstwid, color_map, mode);
 
             retval = 1;
         }
@@ -1553,17 +1692,15 @@ blit(struct Rect       const srcRect,
  */
 
 static void 
-allocPlanes(struct rgbPlanes * const planesP) {
-
-    struct rgbPlanes planes;
+allocPlanes(unsigned int       const width,
+            unsigned int       const height,
+            struct rgbPlanes * const planesP) {
 
-    rowlen = picFrame.right - picFrame.left;
-    collen = picFrame.bottom - picFrame.top;
+    unsigned int const planelen = width * height;
 
-    clip_rect = picFrame;
+    struct rgbPlanes planes;
 
-    planelen = rowlen * collen;
-    MALLOCARRAY(planes.red,  planelen);
+    MALLOCARRAY(planes.red, planelen);
     MALLOCARRAY(planes.grn, planelen);
     MALLOCARRAY(planes.blu, planelen);
     if (planes.red == NULL || planes.grn == NULL || planes.blu == NULL)
@@ -1575,14 +1712,6 @@ allocPlanes(struct rgbPlanes * const planesP) {
     memset(planes.blu, 255, planelen * sizeof(word));
 
     *planesP = planes;
-
-    /* Until we wean this program off of global variables, we have to
-       set these:
-    */
-
-    red   = planes.red;
-    green = planes.grn;
-    blue  = planes.blu;
 }
 
 
@@ -1606,9 +1735,31 @@ compact(word const input) {
 
 
 static void
-do_blits(struct rgbPlanes * const planesP) {
+reportBlitList(blitList * const blitListP) {
+
+    if (verbose) {
+        unsigned int count;
+        struct blit_info * biP;
+
+        for (count = 0, biP = blitListP->firstP; biP; biP = biP->next)
+            ++count;
+
+        pm_message("# blits: %u", count);
+    }
+}
+
+
+
+static void
+doBlitList(struct canvas * const canvasP,
+           blitList *      const blitListP) {
+/*----------------------------------------------------------------------------
+   Do the list of blits *blitListP, drawing on canvas *canvasP.
 
-    struct blit_info* bi;
+   We allocate new plane data structures in *canvasP.  We assume it doesn't
+   have them already.
+-----------------------------------------------------------------------------*/
+    struct blit_info * bi;
     int srcwidth, dstwidth, srcheight, dstheight;
     double  scale, scalelow, scalehigh;
     double  xscale = 1.0;
@@ -1616,9 +1767,11 @@ do_blits(struct rgbPlanes * const planesP) {
     double  lowxscale, highxscale, lowyscale, highyscale;
     int     xscalecalc = 0, yscalecalc = 0;
 
+    reportBlitList(blitListP);
+
     fullres = 0;
 
-    for (bi = blit_list; bi; bi = bi->next) {
+    for (bi = blitListP->firstP; bi; bi = bi->next) {
         srcwidth = rectwidth(&bi->srcRect);
         dstwidth = rectwidth(&bi->dstRect);
         srcheight = rectheight(&bi->srcRect);
@@ -1694,29 +1847,34 @@ do_blits(struct rgbPlanes * const planesP) {
     }
 
     if (xscale != 1.0 || yscale != 1.0) {
-        for (bi = blit_list; bi; bi = bi->next)
-            rectscale(&bi->dstRect, xscale, yscale);
+        struct blit_info * biP;
+        
+        for (biP = blitListP->firstP; biP; biP = biP->next)
+            rectscale(&biP->dstRect, xscale, yscale);
 
-        pm_message("Scaling output by %f in X and %f in Y",
-                   xscale, yscale);
+        pm_message("Scaling output by %f in X and %f in Y", xscale, yscale);
         rectscale(&picFrame, xscale, yscale);
     }
 
-    allocPlanes(planesP);
+    rowlen = picFrame.right  - picFrame.left;
+    collen = picFrame.bottom - picFrame.top;
+
+    allocPlanes(rowlen, collen, &canvasP->planes);
 
-    for (bi = blit_list; bi; bi = bi->next) {
-        blit(bi->srcRect, bi->srcBounds, bi->srcplane,
-             bi->pixSize,
-             bi->dstRect, picFrame, rowlen,
-             bi->color_map,
-             bi->mode);
+    clip_rect = picFrame;
+
+    for (bi = blitListP->firstP; bi; bi = bi->next) {
+        doBlit(bi->srcRect, bi->dstRect,
+               bi->srcBounds, bi->srcplane, picFrame, canvasP->planes,
+               bi->pixSize, rowlen, bi->colorMap, bi->mode);
     }
 }
 
 
 
 static void
-outputPpm(struct rgbPlanes const planes) {
+outputPpm(FILE *           const ofP,
+          struct rgbPlanes const planes) {
 
     unsigned int width;
     unsigned int height;
@@ -1732,7 +1890,7 @@ outputPpm(struct rgbPlanes const planes) {
     width  = picFrame.right  - picFrame.left;
     height = picFrame.bottom - picFrame.top;
 
-    ppm_writeppminit(stdout, width, height, PPM_MAXMAXVAL, 0);
+    ppm_writeppminit(ofP, width, height, PPM_MAXMAXVAL, 0);
     pixelrow = ppm_allocrow(width);
     srcCursor = 0;
     for (row = 0; row < height; ++row) {
@@ -1745,9 +1903,8 @@ outputPpm(struct rgbPlanes const planes) {
                 );
             ++srcCursor;
         }
-        ppm_writeppmrow(stdout, pixelrow, width, PPM_MAXMAXVAL, 0);
+        ppm_writeppmrow(ofP, pixelrow, width, PPM_MAXMAXVAL, 0);
     }
-    pm_close(stdout);
 }
 
 
@@ -1773,8 +1930,13 @@ get_op(int const version) {
 
 
 
+static drawFn Clip;
+
 static void
-Clip(int const version) {
+Clip(struct canvas * const canvasP,
+     blitList *      const blitListP,
+     int             const version) {
+
     word len;
 
     len = read_word();
@@ -1791,8 +1953,13 @@ Clip(int const version) {
 
 
 
+static drawFn OpColor;
+
 static void
-OpColor(int const version) {
+OpColor(struct canvas * const canvasP,
+        blitList *      const blitListP,
+        int             const version) {
+
     op_color.red = read_word();
     op_color.grn = read_word();
     op_color.blu = read_word();
@@ -1806,17 +1973,17 @@ read_pixmap(struct pixMap * const p) {
     stage = "getting pixMap header";
 
     read_rect(&p->Bounds);
-    p->version = read_word();
-    p->packType = read_word();
-    p->packSize = read_long();
-    p->hRes = read_long();
-    p->vRes = read_long();
-    p->pixelType = read_word();
-    p->pixelSize = read_word();
-    p->cmpCount = read_word();
-    p->cmpSize = read_word();
+    p->version    = read_word();
+    p->packType   = read_word();
+    p->packSize   = read_long();
+    p->hRes       = read_long();
+    p->vRes       = read_long();
+    p->pixelType  = read_word();
+    p->pixelSize  = read_word();
+    p->cmpCount   = read_word();
+    p->cmpSize    = read_word();
     p->planeBytes = read_long();
-    p->pmTable = read_long();
+    p->pmTable    = read_long();
     p->pmReserved = read_long();
 
     if (verbose) {
@@ -1824,6 +1991,8 @@ read_pixmap(struct pixMap * const p) {
         pm_message("pixelSize: %d", p->pixelSize);
         pm_message("cmpCount:  %d", p->cmpCount);
         pm_message("cmpSize:   %d", p->cmpSize);
+        if (verbose)
+            dumpRect("Bounds:", p->Bounds);
     }
 
     if (p->pixelType != 0)
@@ -1878,7 +2047,7 @@ read_color_table(void) {
         color_table[val].blu = read_word();
 
         if (verbose > 1)
-            pm_message("%d: [%d,%d,%d]", val,
+            pm_message("Color %3u: [%u,%u,%u]", val,
                 color_table[val].red,
                 color_table[val].grn,
                 color_table[val].blu);
@@ -2084,6 +2253,42 @@ unpackUncompressedBits(FILE *          const ifP,
 
 
 static void
+reportValidateCompressedLineLen(unsigned int const row,
+                                unsigned int const linelen,
+                                unsigned int const rowSize) {
+/*----------------------------------------------------------------------------
+   'row' is a row number in the raster.
+
+   'linelen' is the number of bytes of PICT that the PICT says hold the
+   compressed version of that row.
+
+   'rowSize' is the number of bytes we expect the uncompressed line to
+   be (includes pad pixels on the right).
+-----------------------------------------------------------------------------*/
+    if (verbose > 1)
+        pm_message("Row %u: %u-byte compressed line", row, linelen);
+
+    /* When the line length value is garbage, it often causes the program to
+       try to read beyond EOF.  To make that failure easier to diagnose,
+       we sanity check the line length now.
+    */
+
+    /* In the worst case, a pixel is represented by two bytes: a one byte
+       repeat count of one followed by a one byte pixel value (the byte could
+       be up to 8 pixels) or a one byte block length of one followed by the
+       pixel value.  So expansion factor two.
+    */
+
+    if (linelen > rowSize * 2)
+        pm_error("Invalid PICT: compressed line of %u bytes for Row %u "
+                 "is too big "
+                 "to represent a %u-byte padded row, even with worse case "
+                 "compression.", linelen, row, rowSize);
+}
+
+
+
+static void
 expandRun(unsigned char * const block,
           unsigned int    const blockLimit,
           unsigned int    const bitsPerPixel,
@@ -2099,6 +2304,9 @@ expandRun(unsigned char * const block,
    returned.
 -----------------------------------------------------------------------------*/
     unsigned int const pkpixsize = bitsPerPixel == 16 ? 2 : 1;
+        /* The repetition unit size, in bytes.  The run consists of this many
+           bytes of packed data repeated the specified number of times.
+        */
 
     if (1 + pkpixsize > blockLimit)
         pm_error("PICT run block runs off the end of its line.  "
@@ -2114,14 +2322,28 @@ expandRun(unsigned char * const block,
         assert(block[0] & 0x80);  /* It's a run */
 
         if (verbose > 1)
-            pm_message("Block: run of %u pixels or plane samples", runLength);
-        
+            pm_message("Block: run of %u packed %u-byte units",
+                       runLength, pkpixsize);
+
         unpackBuf(&block[1], pkpixsize, bitsPerPixel,
                   &bytePixels, &expandedByteCount);
+
+        /* I assume in a legal PICT the run never has padding for the
+           case that the run is at the right edge of a row and the
+           remaining columns in the row don't fill whole bytes.
+           E.g. if there are 25 columns left in the row and 1 bit per
+           pixel, we won't see a run of 4 bytes and have to ignore the
+           last 7 pixels.  Instead, we'll see a run of 3 bytes
+           followed by a non-run block for the remaining pixel.
+
+           That is what I saw in a test image.
+        */
         
-        if (expandedByteCount > expandedSize)
+        if (expandedByteCount * runLength > expandedSize)
             pm_error("Invalid PICT image.  It contains a row with more pixels "
-                     "than the width of the image");
+                     "than the width of the rectangle containing it, "
+                     "even padded up to a "
+                     "multiple of 16 pixels.  Use -verbose to see details.");
         
         outputCursor = 0;
         for (i = 0; i < runLength; ++i) {
@@ -2146,9 +2368,23 @@ copyPixelGroup(unsigned char * const block,
                unsigned int *  const rasterBytesGeneratedP) {
 /*----------------------------------------------------------------------------
    Copy a group of pixels (the data says, "take the following N pixels").
+
+   Copy them (unpacked) from block block[] to dest[].
+
+   block[] self-describes its length.  Return that length as
+   *blockLengthP.
+
+   block[] contains at most 'blockLimit' valid array elements, so if
+   the length information in block[] indicates the block is larger
+   than that, the block is corrupt.
+
+   Return the number of pixels placed in dest[] as *rasterBytesGeneratedP.
+
+   The output array dest[] has 'destSize' elements of space.  Ignore
+   any pixels on the right that won't fit in that.
 -----------------------------------------------------------------------------*/
-    unsigned int const pkpixsize = bitsPerPixel == 16 ? 2 : 1;
-    unsigned int const groupLen = block[0] + 1;
+    unsigned int const pkpixsize   = bitsPerPixel == 16 ? 2 : 1;
+    unsigned int const groupLen    = block[0] + 1;
     unsigned int const blockLength = 1 + groupLen * pkpixsize;
 
     if (blockLength > blockLimit)
@@ -2159,22 +2395,35 @@ copyPixelGroup(unsigned char * const block,
         unsigned int i;
         unsigned char * bytePixels;  /* Points to static storage */
         unsigned int bytePixelLen;
+        unsigned int rasterBytesGenerated;
         
         assert(blockLimit >= 1);  /* block[0] exists */
         assert((block[0] & 0x80) == 0);  /* It's not a run */
         
         if (verbose > 1)
-            pm_message("Block: %u individual pixels or plane samples",
-                       groupLen);
+            pm_message("Block: %u explicit packed %u-byte units",
+                       groupLen, pkpixsize);
         
         unpackBuf(&block[1], groupLen * pkpixsize, bitsPerPixel,
                   &bytePixels, &bytePixelLen);
-        
-        for (i = 0; i < MIN(bytePixelLen, destSize); ++i)
+
+        /* It is normal for the above to return more pixels than there
+           are left in the row, because of padding.  E.g. there is one
+           pixel left in the row, at one bit per pixel.  But a block
+           contains full bytes, so it must contain at least 8 pixels.
+           7 of them are padding, which we should ignore.
+
+           BUT: I saw an image in which the block had _two_ data bytes
+           (16 pixels) when only 1 pixel remained in the row.  I don't
+           understand why, but ignoring the 15 extra seemed to work.
+        */
+        rasterBytesGenerated = MIN(bytePixelLen, destSize);
+
+        for (i = 0; i < rasterBytesGenerated; ++i)
             dest[i] = bytePixels[i];
         
         *blockLengthP = blockLength;
-        *rasterBytesGeneratedP = MIN(bytePixelLen, destSize);
+        *rasterBytesGeneratedP = rasterBytesGenerated;
     }
 }
 
@@ -2218,12 +2467,83 @@ static unsigned int const maxPixelBytesPerBlock = 1024;
 
 
 static void
+interpretCompressedLine(unsigned char * const linebuf,
+                        unsigned int    const linelen,
+                        unsigned char * const rowRaster,
+                        unsigned int    const rowSize,
+                        unsigned int    const bitsPerPixel) {
+/*----------------------------------------------------------------------------
+   linebuf[] contains 'linelen' bytes from the PICT image that represents
+   one row of the image, in compressed format.  Return the
+   uncompressed pixels of that row as rowRaster[].
+
+   rowRaster[] has 'rowSize' bytes of space.  Caller ensures that
+   linebuf[] does not contain more pixels than that, unless the PICT
+   image from which it comes is corrupt.
+-----------------------------------------------------------------------------*/
+    unsigned int lineCursor;
+        /* Cursor into linebuf[] -- the compressed data */
+    unsigned int rasterCursor;
+        /* Cursor into rowRaster[] -- the uncompressed data */
+
+    for (lineCursor = 0, rasterCursor = 0; lineCursor < linelen; ) {
+        unsigned int blockLength, rasterBytesGenerated;
+        
+        assert(lineCursor <= linelen);
+            
+        if (verbose > 2)
+            pm_message("At Byte %u of line, Column %u of row",
+                       lineCursor, rasterCursor);
+
+        interpretOneRasterBlock(
+            &linebuf[lineCursor], linelen - lineCursor,
+            bitsPerPixel,
+            &rowRaster[rasterCursor], rowSize - rasterCursor,
+            &blockLength, &rasterBytesGenerated);
+        
+        lineCursor += blockLength;
+        rasterCursor += rasterBytesGenerated;
+        assert(rasterCursor <= rowSize);
+    }
+    if (verbose > 1)
+        pm_message("Got %u pixels for row", rasterCursor);
+}
+
+
+/* There is some confusion about when, in PICT, a line length is one byte and
+  when it is two.  An Apple document says it is two bytes when the number of
+  pixels in the row, padded, is > 250.  Ppmtopict generated PICTs that way
+  until January 2009.  Picttoppm assumed something similar until March 2004:
+  It assumed the line length is two bytes when the number of pixels > 250 _or_
+  bits per pixel > 8.  But in March 2004, Steve Summit did a bunch of
+  experiments on existing PICT files and found that they all worked with the
+  rule "pixels per row > 200 => 2 byte line length" and some did not work
+  with the original rule.
+
+  So in March 2004, Picttoppm changed to pixels per row > 200.  Ppmtopict
+  didn't catch up until January 2009.
+
+  http://developer.apple.com/documentation/mac/QuickDraw/QuickDraw-460.html#HEADING460-0
+
+  Of course, neither 200 nor 250 make any logical sense.  In the worst case,
+  you can represent 254 pixels of 8 bpp or less in a 255 byte line.
+  In the worst case, you can represent 127 16bpp pixels in a 255 byte line.
+  So with 200 being the cutoff, it's actually impossible to represent some 
+  16 bpp images with 200 pixels per row.
+
+  We have not been able to find an offical spec for PICT.
+
+  Some day, we may have to make a user option for this.
+*/
+
+
+static void
 unpackCompressedBits(FILE *          const ifP,
                      struct raster   const raster,
                      unsigned int    const rowBytes,
                      unsigned int    const bitsPerPixel) {
 /*----------------------------------------------------------------------------
-   Read the raster of on file *ifP and place it in 'raster'.
+   Read the raster on file *ifP and place it in 'raster'.
 
    The data in the file is compressed with run length encoding and
    possibly packed multiple pixels per byte as well.
@@ -2232,11 +2552,13 @@ unpackCompressedBits(FILE *          const ifP,
    "packing" and I don't know what packing is called.  But we don't
    use that confusing terminology in this program, except when talking
    to the user.
-
-   *boundsP describes the rectangle.
 -----------------------------------------------------------------------------*/
     unsigned int const llsize = rowBytes > 200 ? 2 : 1;
-    unsigned int rowOfRect;
+        /* Width in bytes of the field at the beginning of a line that tells
+           how long (in bytes) the line is.  See notes above about this
+           computation.
+        */
+    unsigned int row;
     unsigned char * linebuf;
     unsigned int linebufSize;
 
@@ -2245,20 +2567,17 @@ unpackCompressedBits(FILE *          const ifP,
     if (linebuf == NULL)
         pm_error("can't allocate memory for line buffer");
 
-    for (rowOfRect = 0; rowOfRect < raster.rowCount; ++rowOfRect) {
+    for (row = 0; row < raster.rowCount; ++row) {
         unsigned char * const rowRaster =
-            &raster.bytes[rowOfRect * raster.rowSize];
+            &raster.bytes[row * raster.rowSize];
         unsigned int linelen;
-        unsigned int lineCursor;
-        unsigned int rasterCursor;
 
         if (llsize == 2)
             linelen = read_word();
         else
             linelen = read_byte();
 
-        if (verbose > 1)
-            pm_message("linelen: %u", linelen);
+        reportValidateCompressedLineLen(row, linelen, raster.rowSize);
 
         if (linelen > linebufSize) {
             linebufSize = linelen;
@@ -2268,23 +2587,8 @@ unpackCompressedBits(FILE *          const ifP,
         }
         readBytes(ifP, linelen, linebuf);
 
-        for (lineCursor = 0, rasterCursor = 0; lineCursor < linelen; ) {
-            unsigned int blockLength, rasterBytesGenerated;
-
-            assert(lineCursor <= linelen);
-            
-            interpretOneRasterBlock(
-                &linebuf[lineCursor], linelen - lineCursor,
-                bitsPerPixel,
-                &rowRaster[rasterCursor], raster.rowSize - rasterCursor,
-                &blockLength, &rasterBytesGenerated);
-
-            lineCursor += blockLength;
-            rasterCursor += rasterBytesGenerated;
-            assert(rasterCursor <= raster.rowSize);
-        }
-        if (verbose > 1)
-            pm_message("row %u: got %u", rowOfRect, rasterCursor);
+        interpretCompressedLine(linebuf, linelen, rowRaster, raster.rowSize,
+                                bitsPerPixel);
     }
     free(linebuf);
 }
@@ -2386,21 +2690,42 @@ read_pattern(void) {
 
 /* these 3 do nothing but skip over their data! */
 
+static drawFn BkPixPat;
+
 static void
-BkPixPat(int const version) {
+BkPixPat(struct canvas * const canvasP,
+         blitList *      const blitListP,
+         int             const version) {
+
     read_pattern();
 }
 
+
+
+static drawFn PnPixPat;
+
 static void
-PnPixPat(int const version) {
+PnPixPat(struct canvas * const canvasP,
+         blitList *      const blitListP,
+         int             const version) {
+
     read_pattern();
 }
 
+
+
+static drawFn FillPixPat;
+
 static void
-FillPixPat(int const version) {
+FillPixPat(struct canvas * const canvasP,
+           blitList *      const blitListP,
+           int             const version) {
+
     read_pattern();
 }
 
+
+
 static void
 read_8x8_pattern(struct Pattern * const pat) {
     unsigned char buf[8];
@@ -2424,29 +2749,49 @@ read_8x8_pattern(struct Pattern * const pat) {
 
 
 
+static drawFn BkPat;
+
 static void 
-BkPat(int const version) {
+BkPat(struct canvas * const canvasP,
+      blitList *      const blitListP,
+      int             const version) {
+
     read_8x8_pattern(&bkpat);
 }
 
 
 
+static drawFn PnPat;
+
 static void 
-PnPat(int const version) {
+PnPat(struct canvas * const canvasP,
+      blitList *      const blitListP,
+      int             const version) {
+
     read_8x8_pattern(&pen_pat);
 }
 
 
 
+static drawFn FillPat;
+
 static void 
-FillPat(int const version) {
+FillPat(struct canvas * const canvasP,
+        blitList *      const blitListP,
+        int             const version) {
+
     read_8x8_pattern(&fillpat);
 }
 
 
 
+static drawFn PnSize;
+
 static void 
-PnSize(int const version) {
+PnSize(struct canvas * const canvasP,
+       blitList *      const blitListP,
+       int             const version) {
+
     pen_height = read_word();
     pen_width = read_word();
     if (verbose)
@@ -2455,8 +2800,12 @@ PnSize(int const version) {
 
 
 
+static drawFn PnSize;
+
 static void 
-PnMode(int const version) {
+PnMode(struct canvas * const canvasP,
+       blitList *      const blitListP,
+       int             const version) {
 
     pen_mode = read_word();
 
@@ -2480,8 +2829,13 @@ read_rgb(struct RGBColor * const rgb) {
 
 
 
+static drawFn RGBFgCol;
+
 static void 
-RGBFgCol(int const v) {
+RGBFgCol(struct canvas * const canvasP,
+         blitList *      const blitListP,
+         int             const version) {
+
     read_rgb(&foreground);
     if (verbose)
         pm_message("foreground now [%d,%d,%d]", 
@@ -2490,8 +2844,13 @@ RGBFgCol(int const v) {
 
 
 
+static drawFn RGBBkCol;
+
 static void 
-RGBBkCol(int const v) {
+RGBBkCol(struct canvas * const canvasP,
+         blitList *      const blitListP,
+         int             const version) {
+
     read_rgb(&background);
     if (verbose)
         pm_message("background now [%d,%d,%d]", 
@@ -2503,34 +2862,37 @@ RGBBkCol(int const v) {
 #define PIXEL_INDEX(x,y) ((y) - picFrame.top) * rowlen + (x) - picFrame.left
 
 static void 
-draw_pixel(int                const x, 
-           int                const y, 
+draw_pixel(struct canvas *   const canvasP,
+           int               const x, 
+           int               const y, 
            struct RGBColor * const clr, 
-           transfer_func            trf) {
-
-    int i;
-    struct RGBColor dst;
+           transfer_func           trf) {
 
     if (x < clip_rect.left || x >= clip_rect.right ||
-        y < clip_rect.top || y >= clip_rect.bottom)
-    {
-        return;
-    }
+        y < clip_rect.top || y >= clip_rect.bottom) {
+    } else {
+        unsigned int const i = PIXEL_INDEX(x, y);
+
+        struct RGBColor dst;
+
+        dst.red = canvasP->planes.red[i];
+        dst.grn = canvasP->planes.grn[i];
+        dst.blu = canvasP->planes.blu[i];
+ 
+        (*trf)(clr, &dst);
 
-    i = PIXEL_INDEX(x, y);
-    dst.red = red[i];
-    dst.grn = green[i];
-    dst.blu = blue[i];
-    (*trf)(clr, &dst);
-    red[i] = dst.red;
-    green[i] = dst.grn;
-    blue[i] = dst.blu;
+        canvasP->planes.red[i] = dst.red;
+        canvasP->planes.grn[i] = dst.grn;
+        canvasP->planes.blu[i] = dst.blu;
+    }
 }
 
 
 
 static void 
-draw_pen_rect(struct Rect * const r) {
+draw_pen_rect(struct canvas * const canvasP,
+              struct Rect *   const r) {
+
     int const rowadd = rowlen - (r->right - r->left);
 
     int i;
@@ -2541,16 +2903,18 @@ draw_pen_rect(struct Rect * const r) {
     
     for (y = r->top; y < r->bottom; y++) {
         for (x = r->left; x < r->right; x++) {
-            dst.red = red[i];
-            dst.grn = green[i];
-            dst.blu = blue[i];
+            dst.red = canvasP->planes.red[i];
+            dst.grn = canvasP->planes.grn[i];
+            dst.blu = canvasP->planes.blu[i];
+
             if (pen_pat.pix[(x & 7) + (y & 7) * 8])
                 (*pen_trf)(&black, &dst);
             else
                 (*pen_trf)(&white, &dst);
-            red[i] = dst.red;
-            green[i] = dst.grn;
-            blue[i] = dst.blu;
+
+            canvasP->planes.red[i] = dst.red;
+            canvasP->planes.grn[i] = dst.grn;
+            canvasP->planes.blu[i] = dst.blu;
 
             i++;
         }
@@ -2561,8 +2925,10 @@ draw_pen_rect(struct Rect * const r) {
 
 
 static void 
-draw_pen(int const x, 
-         int const y) {
+draw_pen(struct canvas * const canvasP,
+         int             const x, 
+         int             const y) {
+
     struct Rect penrect;
 
     penrect.left = x;
@@ -2572,7 +2938,7 @@ draw_pen(int const x,
 
     rectinter(penrect, clip_rect, &penrect);
 
-    draw_pen_rect(&penrect);
+    draw_pen_rect(canvasP, &penrect);
 }
 
 /*
@@ -2589,10 +2955,12 @@ draw_pen(int const x,
  * Paul Heckbert    3 Sep 85
  */
 static void 
-scan_line(short const x1, 
-          short const y1, 
-          short const x2, 
-          short const y2) {
+scan_line(struct canvas * const canvasP,
+          short           const x1, 
+          short           const y1, 
+          short           const x2, 
+          short           const y2) {
+
     int d, x, y, ax, ay, sx, sy, dx, dy;
 
     if (!(pen_width == 0 && pen_height == 0)) {
@@ -2605,7 +2973,7 @@ scan_line(short const x1,
         if (ax>ay) {        /* x dominant */
             d = ay-(ax>>1);
             for (;;) {
-                draw_pen(x, y);
+                draw_pen(canvasP, x, y);
                 if (x==x2) return;
                 if ((x > rowlen) && (sx > 0)) return;
                 if (d>=0) {
@@ -2619,7 +2987,7 @@ scan_line(short const x1,
         else {          /* y dominant */
             d = ax-(ay>>1);
             for (;;) {
-                draw_pen(x, y);
+                draw_pen(canvasP, x, y);
                 if (y==y2) return;
                 if ((y > collen) && (sy > 0)) return;
                 if (d>=0) {
@@ -2635,137 +3003,178 @@ scan_line(short const x1,
 
 
 
+static drawFn Line;
+
 static void 
-Line(int const v) {
+Line(struct canvas * const canvasP,
+     blitList *      const blitListP,
+     int             const version) {
+
   struct Point p1;
   read_point(&p1);
   read_point(&current);
   if (verbose)
     pm_message("(%d,%d) to (%d, %d)",
            p1.x,p1.y,current.x,current.y);
-  scan_line(p1.x,p1.y,current.x,current.y);
+  scan_line(canvasP, p1.x,p1.y,current.x,current.y);
 }
 
 
 
+static drawFn LineFrom;
+
 static void 
-LineFrom(int const v) {
-  struct Point p1;
-  read_point(&p1);
-  if (verbose)
-    pm_message("(%d,%d) to (%d, %d)",
-           current.x,current.y,p1.x,p1.y);
+LineFrom(struct canvas * const canvasP,
+         blitList *      const blitListP,
+         int             const version) {
+
+    struct Point p1;
+    read_point(&p1);
+    if (verbose)
+        pm_message("(%d,%d) to (%d, %d)", current.x, current.y, p1.x, p1.y);
 
-  if (!fullres)
-      scan_line(current.x,current.y,p1.x,p1.y);
+    if (!blitListP)
+        scan_line(canvasP, current.x, current.y, p1.x, p1.y);
 
-  current.x = p1.x;
-  current.y = p1.y;
+    current.x = p1.x;
+    current.y = p1.y;
 }
 
 
 
+static drawFn ShortLine;
+
 static void 
-ShortLine(int const v) {
-  struct Point p1;
-  read_point(&p1);
-  read_short_point(&current);
-  if (verbose)
-    pm_message("(%d,%d) delta (%d, %d)",
-           p1.x,p1.y,current.x,current.y);
-  current.x += p1.x;
-  current.y += p1.y;
+ShortLine(struct canvas * const canvasP,
+          blitList *      const blitListP,
+          int             const version) {
 
-  if (!fullres)
-      scan_line(p1.x,p1.y,current.x,current.y);
+    struct Point p1;
+    read_point(&p1);
+    read_short_point(&current);
+    if (verbose)
+        pm_message("(%d,%d) delta (%d, %d)", p1.x, p1.y, current.x, current.y);
+    current.x += p1.x;
+    current.y += p1.y;
+    
+    if (!blitListP)
+        scan_line(canvasP, p1.x, p1.y, current.x, current.y);
 }
 
 
 
+static drawFn ShortLineFrom;
+
 static void 
-ShortLineFrom(int const v) {
-  struct Point p1;
-  read_short_point(&p1);
-  if (verbose)
-    pm_message("(%d,%d) delta (%d, %d)",
-               current.x,current.y,p1.x,p1.y);
-  p1.x += current.x;
-  p1.y += current.y;
-  if (!fullres)
-      scan_line(current.x,current.y,p1.x,p1.y);
-  current.x = p1.x;
-  current.y = p1.y;
+ShortLineFrom(struct canvas * const canvasP,
+              blitList *      const blitListP,
+              int             const version) {
+
+    struct Point p1;
+    read_short_point(&p1);
+    if (verbose)
+        pm_message("(%d,%d) delta (%d, %d)",
+                   current.x,current.y,p1.x,p1.y);
+    p1.x += current.x;
+    p1.y += current.y;
+    if (!blitListP)
+        scan_line(canvasP, current.x, current.y, p1.x, p1.y);
+    current.x = p1.x;
+    current.y = p1.y;
 }
 
+
+
 static void 
-do_paintRect(struct Rect const prect) {
+do_paintRect(struct canvas * const canvasP,
+             struct Rect     const prect) {
+
     struct Rect rect;
   
-    if (fullres)
-        return;
-
     if (verbose)
         dumpRect("painting", prect);
 
     rectinter(clip_rect, prect, &rect);
 
-    draw_pen_rect(&rect);
+    draw_pen_rect(canvasP, &rect);
 }
 
 
 
+static drawFn paintRect;
+
 static void 
-paintRect(int const v) {
+paintRect(struct canvas * const canvasP,
+          blitList *      const blitListP,
+          int             const version) {
+
     read_rect(&cur_rect);
-    do_paintRect(cur_rect);
+    if (!blitListP)
+        do_paintRect(canvasP, cur_rect);
 }
 
 
 
+static drawFn paintSameRect;
+
 static void 
-paintSameRect(int const v) {
-    do_paintRect(cur_rect);
+paintSameRect(struct canvas * const canvasP,
+              blitList *      const blitListP,
+              int             const version) {
+
+    if (!blitListP)
+        do_paintRect(canvasP, cur_rect);
 }
 
 
 
 static void 
-do_frameRect(struct Rect const rect) {
-    int x, y;
+do_frameRect(struct canvas * const canvasP,
+             struct Rect     const rect) {
 
-    if (fullres)
-        return;
-  
     if (verbose)
         dumpRect("framing", rect);
 
-    if (pen_width == 0 || pen_height == 0)
-        return;
-
-    for (x = rect.left; x <= rect.right - pen_width; x += pen_width) {
-        draw_pen(x, rect.top);
-        draw_pen(x, rect.bottom - pen_height);
-    }
+    if (pen_width > 0 && pen_height > 0) {
+        unsigned int x, y;
 
-    for (y = rect.top; y <= rect.bottom - pen_height ; y += pen_height) {
-        draw_pen(rect.left, y);
-        draw_pen(rect.right - pen_width, y);
+        for (x = rect.left; x <= rect.right - pen_width; x += pen_width) {
+            draw_pen(canvasP, x, rect.top);
+            draw_pen(canvasP, x, rect.bottom - pen_height);
+        }
+        
+        for (y = rect.top; y <= rect.bottom - pen_height ; y += pen_height) {
+            draw_pen(canvasP, rect.left, y);
+            draw_pen(canvasP, rect.right - pen_width, y);
+        }
     }
 }
 
 
 
+static drawFn frameRect;
+
 static void 
-frameRect(int const v) {
+frameRect(struct canvas * const canvasP,
+          blitList *      const blitListP,
+          int             const version) {
+
     read_rect(&cur_rect);
-    do_frameRect(cur_rect);
+    if (!blitListP)
+        do_frameRect(canvasP, cur_rect);
 }
 
 
 
+static drawFn frameSameRect;
+
 static void 
-frameSameRect(int const v) {
-    do_frameRect(cur_rect);
+frameSameRect(struct canvas * const canvasP,
+              blitList *      const blitListP,
+              int             const version) {
+
+    if (!blitListP)
+        do_frameRect(canvasP, cur_rect);
 }
 
 
@@ -2806,8 +3215,10 @@ poly_sort(int const sort_index, struct Point points[]) {
 /* Watch out for the lack of error checking in the next two functions ... */
 
 static void 
-scan_poly(int          const np, 
-          struct Point       pts[]) {
+scan_poly(struct canvas * const canvasP,
+          int             const np, 
+          struct Point          pts[]) {
+
   int dx,dy,dxabs,dyabs,i,scan_index,j,k,px,py;
   int sdx,sdy,x,y,toggle,old_sdy,sy0;
 
@@ -2860,7 +3271,7 @@ scan_poly(int          const np,
         scan_index++;
       }
       px += sdx;
-      draw_pen(px, py);
+      draw_pen(canvasP, px, py);
     }
       }
     else
@@ -2876,7 +3287,7 @@ scan_poly(int          const np,
         old_sdy = sdy;
         if (sdy != 0) scan_index--;
       }
-      draw_pen(px,py);
+      draw_pen(canvasP, px,py);
       coord[scan_index].x = px;
       coord[scan_index].y = py;
       scan_index++;
@@ -2896,7 +3307,7 @@ scan_poly(int          const np,
     if ((coord[i].y == coord[i+1].y) && (toggle == 0))
       {
     for (j = coord[i].x; j <= coord[i+1].x; j++)
-      draw_pen(j, coord[i].y);
+      draw_pen(canvasP, j, coord[i].y);
     toggle = 1;
       }
     else
@@ -2905,9 +3316,14 @@ scan_poly(int          const np,
 }
   
 
+
+static drawFn paintPoly;
   
 static void 
-paintPoly(int const v) {
+paintPoly(struct canvas * const canvasP,
+          blitList *      const blitListP,
+          int             const version) {
+
   struct Rect bb;
   struct Point pts[100];
   int i, np = (read_word() - 10) >> 2;
@@ -2917,14 +3333,19 @@ paintPoly(int const v) {
     read_point(&pts[i]);
 
   /* scan convert poly ... */
-  if (!fullres)
-      scan_poly(np, pts);
+  if (!blitListP)
+      scan_poly(canvasP, np, pts);
 }
 
 
 
+static drawFn PnLocHFrac;
+
 static void 
-PnLocHFrac(int const version) {
+PnLocHFrac(struct canvas * const canvasP,
+           blitList *      const blitListP,
+           int             const version) {
+
     word frac = read_word();
 
     if (verbose)
@@ -2933,8 +3354,13 @@ PnLocHFrac(int const version) {
 
 
 
+static drawFn TxMode;
+
 static void 
-TxMode(int const version) {
+TxMode(struct canvas * const canvasP,
+       blitList *      const blitListP,
+       int             const version) {
+
     text_mode = read_word();
 
     if (text_mode >= 8 && text_mode < 15)
@@ -2949,8 +3375,13 @@ TxMode(int const version) {
 
 
 
+static drawFn TxFont;
+
 static void 
-TxFont(int const version) {
+TxFont(struct canvas * const canvasP,
+       blitList *      const blitListP,
+       int             const version) {
+
     text_font = read_word();
     if (verbose)
         pm_message("text font %s", const_name(font_name, text_font));
@@ -2958,8 +3389,13 @@ TxFont(int const version) {
 
 
 
+static drawFn TxFace;
+
 static void 
-TxFace(int const version) {
+TxFace(struct canvas * const canvasP,
+       blitList *      const blitListP,
+       int             const version) {
+
     text_face = read_byte();
     if (verbose)
         pm_message("text face %d", text_face);
@@ -2967,8 +3403,13 @@ TxFace(int const version) {
 
 
 
+static drawFn TxSize;
+
 static void 
-TxSize(int const version) {
+TxSize(struct canvas * const canvasP,
+       blitList *      const blitListP,
+       int             const version) {
+
     text_size = read_word();
     if (verbose)
         pm_message("text size %d", text_size);
@@ -2977,8 +3418,11 @@ TxSize(int const version) {
 
 
 static void
-skip_text(void) {
+skip_text(blitList * const blitListP) {
+
     skip(read_byte());
+
+    blitListP->unblittableText = true;
 }
 
 
@@ -2997,6 +3441,7 @@ static struct font*
 get_font(int const font, 
          int const size, 
          int const style) {
+
     int closeness, bestcloseness;
     struct fontinfo* fi, *best;
 
@@ -3058,8 +3503,10 @@ rotate(int * const x,
 
 
 static void
-do_ps_text(word const tx, 
-           word const ty) {
+do_ps_text(struct canvas * const canvasP,
+           word            const tx, 
+           word            const ty) {
+
     int len, width, i, w, h, x, y, rx, ry, o;
     byte str[256], ch;
     struct glyph* glyph;
@@ -3110,9 +3557,9 @@ do_ps_text(word const tx,
                 {
                     o = PIXEL_INDEX(rx, ry);
                     if (glyph->bmap[h * glyph->width + w]) {
-                        red[o] = foreground.red;
-                        green[o] = foreground.grn;
-                        blue[o] = foreground.blu;
+                        canvasP->planes.red[o] = foreground.red;
+                        canvasP->planes.grn[o] = foreground.grn;
+                        canvasP->planes.blu[o] = foreground.blu;
                     }
                 }
             }
@@ -3125,16 +3572,19 @@ do_ps_text(word const tx,
 
 
 static void
-do_text(word const startx, 
-        word const starty) {
-    if (fullres)
-        skip_text();
+do_text(struct canvas *  const canvasP,
+        blitList *       const blitListP,
+        word             const startx, 
+        word             const starty) {
+
+    if (blitListP)
+        skip_text(blitListP);
     else {
         if (!(tfont = get_font(text_font, text_size, text_face)))
             tfont = pbm_defaultfont("bdf");
 
         if (ps_text)
-            do_ps_text(startx, starty);
+            do_ps_text(canvasP, startx, starty);
         else {
             int len;
             word x, y;
@@ -3154,7 +3604,8 @@ do_text(word const startx,
                             struct RGBColor * const colorP = 
                                 glyph->bmap[h * glyph->width + w] ?
                                 &black : &white;
-                            draw_pixel(x + w + glyph->x, dy, colorP, text_trf);
+                            draw_pixel(canvasP,
+                                       x + w + glyph->x, dy, colorP, text_trf);
                         }
                     }
                     x += glyph->xadd;
@@ -3168,34 +3619,56 @@ do_text(word const startx,
 
 
 
+static drawFn LongText;
+
 static void
-LongText(int const version) {
+LongText(struct canvas * const canvasP,
+         blitList *      const blitListP,
+         int             const version) {
+
     struct Point p;
 
     read_point(&p);
-    do_text(p.x, p.y);
+
+    do_text(canvasP, blitListP, p.x, p.y);
 }
 
 
 
+static drawFn DHText;
+
 static void
-DHText(int const version) {
+DHText(struct canvas * const canvasP,
+       blitList *      const blitListP,
+       int             const version) {
+
     current.x += read_byte();
-    do_text(current.x, current.y);
+
+    do_text(canvasP, blitListP, current.x, current.y);
 }
 
 
 
+static drawFn DVText;
+
 static void
-DVText(int const version) {
+DVText(struct canvas * const canvasP,
+       blitList *      const blitListP,
+       int             const version) {
+
     current.y += read_byte();
-    do_text(current.x, current.y);
+
+    do_text(canvasP, blitListP, current.x, current.y);
 }
 
 
 
+static drawFn DHDVText;
+
 static void
-DHDVText(int const version) {
+DHDVText(struct canvas * const canvasP,
+         blitList *      const blitListP,
+         int             const version) {
     byte dh, dv;
 
     dh = read_byte();
@@ -3206,7 +3679,8 @@ DHDVText(int const version) {
 
     current.x += dh;
     current.y += dv;
-    do_text(current.x, current.y);
+
+    do_text(canvasP, blitListP, current.x, current.y);
 }
 
 
@@ -3216,8 +3690,10 @@ DHDVText(int const version) {
  */
 
 static void
-directBits(unsigned int const pictVersion, 
-           bool         const skipRegion) {
+directBits(struct canvas * const canvasP,
+           blitList *      const blitListP,
+           unsigned int    const pictVersion, 
+           bool            const skipRegion) {
 
     struct pixMap   p;
     struct Rect     srcRect;
@@ -3257,11 +3733,11 @@ directBits(unsigned int const pictVersion,
         pm_message("transfer mode = %s", const_name(transfer_name, mode));
 
     if (skipRegion) 
-        skip_poly_or_region(pictVersion);
+        skip_poly_or_region(canvasP, blitListP, pictVersion);
 
     unpackbits(ifp, &p.Bounds, 0, p.pixelSize, &raster);
 
-    blit(srcRect, p.Bounds, raster, p.pixelSize,
+    blit(srcRect, p.Bounds, raster, canvasP, blitListP, p.pixelSize,
          dstRect, picFrame, rowlen, NULL, mode);
 
     freeRaster(raster);
@@ -3272,26 +3748,36 @@ directBits(unsigned int const pictVersion,
 #define SKIP_REGION_TRUE TRUE
 #define SKIP_REGION_FALSE FALSE
 
+static drawFn DirectBitsRect;
+
 static void
-DirectBitsRect(int const version) {
+DirectBitsRect(struct canvas * const canvasP,
+               blitList *      const blitListP,
+               int             const version) {
 
-    directBits(version, SKIP_REGION_FALSE);
+    directBits(canvasP, blitListP, version, SKIP_REGION_FALSE);
 }
 
 
 
+static drawFn DirectBitsRgn;
+
 static void
-DirectBitsRgn(int const version) {
+DirectBitsRgn(struct canvas * const canvasP,
+              blitList *      const blitListP,
+              int             const version) {
 
-    directBits(version, SKIP_REGION_TRUE);
+    directBits(canvasP, blitListP, version, SKIP_REGION_TRUE);
 }
 
 
 
 static void
-do_pixmap(int  const version, 
-          word const rowBytes, 
-          int  const is_region) {
+do_pixmap(struct canvas * const canvasP,
+          blitList *      const blitListP,
+          int             const version, 
+          word            const rowBytes, 
+          int             const is_region) {
 /*----------------------------------------------------------------------------
    Do a paletted image.
 -----------------------------------------------------------------------------*/
@@ -3327,13 +3813,13 @@ do_pixmap(int  const version,
         pm_message("transfer mode = %s", const_name(transfer_name, mode));
 
     if (is_region)
-        skip_poly_or_region(version);
+        skip_poly_or_region(canvasP, blitListP, version);
 
     stage = "unpacking rectangle";
 
     unpackbits(ifp, &p.Bounds, rowBytes, p.pixelSize, &raster);
 
-    blit(srcRect, p.Bounds, raster, 8,
+    blit(srcRect, p.Bounds, raster, canvasP, blitListP, 8,
          dstRect, picFrame, rowlen, color_table, mode);
 
     free(color_table);
@@ -3343,17 +3829,25 @@ do_pixmap(int  const version,
 
 
 static void
-do_bitmap(int const version, 
-          int const rowBytes, 
-          int const is_region) {
+do_bitmap(FILE *          const ifP,
+          struct canvas * const canvasP,
+          blitList *      const blitListP,
+          int             const version, 
+          int             const rowBytes, 
+          int             const is_region) {
 /*----------------------------------------------------------------------------
    Do a bitmap.  That's one bit per pixel, 0 is white, 1 is black.
+
+   Read the raster from file 'ifP'.
 -----------------------------------------------------------------------------*/
     struct Rect Bounds;
     struct Rect srcRect;
     struct Rect dstRect;
     word mode;
     struct raster raster;
+        /* This raster contains padding on the right to make a multiple
+           of 16 pixels per row.
+        */
     static struct RGBColor color_table[] = { 
         {65535L, 65535L, 65535L}, {0, 0, 0} };
 
@@ -3365,13 +3859,13 @@ do_bitmap(int const version,
         pm_message("transfer mode = %s", const_name(transfer_name, mode));
 
     if (is_region)
-        skip_poly_or_region(version);
+        skip_poly_or_region(canvasP, blitListP, version);
 
     stage = "unpacking rectangle";
 
-    unpackbits(ifp, &Bounds, rowBytes, 1, &raster);
+    unpackbits(ifP, &Bounds, rowBytes, 1, &raster);
 
-    blit(srcRect, Bounds, raster, 8,
+    blit(srcRect, Bounds, raster, canvasP, blitListP, 8,
          dstRect, picFrame, rowlen, color_table, mode);
 
     freeRaster(raster);
@@ -3379,8 +3873,12 @@ do_bitmap(int const version,
 
 
 
+static drawFn BitsRect;
+
 static void
-BitsRect(int const version) {
+BitsRect(struct canvas * const canvasP,
+         blitList *      const blitListP,
+         int             const version) {
 
     word rowBytesWord;
     bool pixMap;
@@ -3392,16 +3890,20 @@ BitsRect(int const version) {
     interpretRowBytesWord(rowBytesWord, &pixMap, &rowBytes);
 
     if (pixMap)
-        do_pixmap(version, rowBytes, 0);
+        do_pixmap(canvasP, blitListP, version, rowBytes, 0);
     else
-        do_bitmap(version, rowBytes, 0);
+        do_bitmap(ifp, canvasP, blitListP, version, rowBytes, 0);
 }
 
 
 
-static void
-BitsRegion(int const version) {
+static drawFn BitsRegion;
 
+static void
+BitsRegion(struct canvas * const canvasP,
+           blitList *      const blitListP,
+           int             const version) {
+    
     word rowBytesWord;
     bool pixMap;
     unsigned int rowBytes;
@@ -3412,9 +3914,9 @@ BitsRegion(int const version) {
     interpretRowBytesWord(rowBytesWord, &pixMap, &rowBytes);
 
     if (pixMap)
-        do_pixmap(version, rowBytes, 1);
+        do_pixmap(canvasP, blitListP, version, rowBytes, 1);
     else
-        do_bitmap(version, rowBytes, 1);
+        do_bitmap(ifp, canvasP, blitListP, version, rowBytes, 1);
 }
 
 
@@ -3597,14 +4099,85 @@ static struct opdef const optable[] = {
 
 
 static void
-interpret_pict(void) {
+processOpcode(word const opcode, 
+              struct canvas * const canvasP,
+              blitList *      const blitListP,
+              unsigned int    const version) {
+
+    if (opcode < 0xa2) {
+        stage = optable[opcode].name;
+        if (verbose) {
+            if (streq(stage, "reserved"))
+                pm_message("reserved opcode=0x%x", opcode);
+            else
+                pm_message("Opcode: %s", optable[opcode].name);
+        }
+
+        if (optable[opcode].impl != NULL)
+            (*optable[opcode].impl)(canvasP, blitListP, version);
+        else if (optable[opcode].len >= 0)
+            skip(optable[opcode].len);
+        else {
+            switch (optable[opcode].len) {
+            case WORD_LEN: {
+                word const len = read_word();
+                skip(len);
+                } break;
+            default:
+                pm_error("can't do length %u", optable[opcode].len);
+            }
+        }
+    } else if (opcode == 0xc00) {
+        if (verbose)
+            pm_message("HeaderOp");
+        stage = "HeaderOp";
+        skip(24);
+    } else if (opcode >= 0xa2 && opcode <= 0xaf) {
+        stage = "skipping reserved";
+        if (verbose)
+            pm_message("%s 0x%x", stage, opcode);
+        skip(read_word());
+    } else if (opcode >= 0xb0 && opcode <= 0xcf) {
+        /* just a reserved opcode, no data */
+        if (verbose)
+            pm_message("reserved 0x%x", opcode);
+    } else if (opcode >= 0xd0 && opcode <= 0xfe) {
+        stage = "skipping reserved";
+        if (verbose)
+            pm_message("%s 0x%x", stage, opcode);
+        skip(read_long());
+    } else if (opcode >= 0x100 && opcode <= 0x7fff) {
+        stage = "skipping reserved";
+        if (verbose)
+            pm_message("%s 0x%x", stage, opcode);
+        skip((opcode >> 7) & 255);
+    } else if (opcode >= 0x8000 && opcode <= 0x80ff) {
+        /* just a reserved opcode */
+        if (verbose)
+            pm_message("reserved 0x%x", opcode);
+    } else if (opcode >= 0x8100) {
+        stage = "skipping reserved";
+        if (verbose)
+            pm_message("%s 0x%x", stage, opcode);
+        skip(read_long());
+    } else
+        pm_error("This program does not understand opcode 0x%04x", opcode);
+}
+
+
+
+static void
+interpret_pict(FILE * const ofP) {
+
     byte ch;
     word picSize;
     word opcode;
-    word len;
     unsigned int version;
     int i;
-    struct rgbPlanes planes;
+    struct canvas canvas;
+    blitList blitList;
+
+    initBlitList(&blitList);
 
     for (i = 0; i < 64; i++)
         pen_pat.pix[i] = bkpat.pix[i] = fillpat.pix[i] = 1;
@@ -3618,20 +4191,26 @@ interpret_pict(void) {
     picSize = read_word();
 
     if (verbose)
-        pm_message("picture size = %d (0x%x)", picSize, picSize);
+        pm_message("picture size = %u (0x%x)", picSize, picSize);
 
     stage = "reading picture frame";
     read_rect(&picFrame);
 
     if (verbose) {
         dumpRect("Picture frame:", picFrame);
-        pm_message("Picture size is %d x %d",
-            picFrame.right - picFrame.left,
-            picFrame.bottom - picFrame.top);
+        pm_message("Picture size is %u x %u",
+                   picFrame.right - picFrame.left,
+                   picFrame.bottom - picFrame.top);
     }
 
-    if (!fullres)
-        allocPlanes(&planes);
+    if (!fullres) {
+        rowlen = picFrame.right  - picFrame.left;
+        collen = picFrame.bottom - picFrame.top;
+
+        allocPlanes(rowlen, collen, &canvas.planes);
+
+        clip_rect = picFrame;
+    }
 
     while ((ch = read_byte()) == 0)
         ;
@@ -3657,71 +4236,35 @@ interpret_pict(void) {
     if (verbose)
         pm_message("PICT version %u", version);
 
-    while((opcode = get_op(version)) != 0xff) {
-        if (opcode < 0xa2) {
-            stage = optable[opcode].name;
-            if (verbose) {
-                if (STREQ(stage, "reserved"))
-                    pm_message("reserved opcode=0x%x", opcode);
-                else
-                    pm_message("Opcode: %s", optable[opcode].name);
-            }
-
-            if (optable[opcode].impl != NULL)
-                (*optable[opcode].impl)(version);
-            else if (optable[opcode].len >= 0)
-                skip(optable[opcode].len);
-            else switch (optable[opcode].len) {
-            case WORD_LEN:
-                len = read_word();
-                skip(len);
-                break;
-            default:
-                pm_error("can't do length %u", optable[opcode].len);
-            }
-        } else if (opcode == 0xc00) {
-            if (verbose)
-                pm_message("HeaderOp");
-            stage = "HeaderOp";
-            skip(24);
-        } else if (opcode >= 0xa2 && opcode <= 0xaf) {
-            stage = "skipping reserved";
-            if (verbose)
-                pm_message("%s 0x%x", stage, opcode);
-            skip(read_word());
-        } else if (opcode >= 0xb0 && opcode <= 0xcf) {
-            /* just a reserved opcode, no data */
-            if (verbose)
-                pm_message("reserved 0x%x", opcode);
-        } else if (opcode >= 0xd0 && opcode <= 0xfe) {
-            stage = "skipping reserved";
-            if (verbose)
-                pm_message("%s 0x%x", stage, opcode);
-            skip(read_long());
-        } else if (opcode >= 0x100 && opcode <= 0x7fff) {
-            stage = "skipping reserved";
-            if (verbose)
-                pm_message("%s 0x%x", stage, opcode);
-            skip((opcode >> 7) & 255);
-        } else if (opcode >= 0x8000 && opcode <= 0x80ff) {
-            /* just a reserved opcode */
-            if (verbose)
-                pm_message("reserved 0x%x", opcode);
-        } else if (opcode >= 0x8100) {
-            stage = "skipping reserved";
-            if (verbose)
-                pm_message("%s 0x%x", stage, opcode);
-            skip(read_long());
-        } else
-            pm_error("This program does not understand opcode 0x%04x", opcode);
-    }
+    while((opcode = get_op(version)) != 0xff)
+        processOpcode(opcode, &canvas, fullres ? &blitList : NULL, version);
     
-    if (fullres)
-        do_blits(&planes);
+    if (fullres) {
+        if (blitList.unblittableText)
+            pm_message("Warning: text is omitted from the output because "
+                       "we don't know how to do text with -fullres.");
+        doBlitList(&canvas, &blitList);
+    }
+    outputPpm(ofP, canvas.planes);
+
+    freePlanes(canvas.planes);
+}
+
+
 
-    outputPpm(planes);
+static void
+loadDefaultFontDir(void) {
+/*----------------------------------------------------------------------------
+   Load the fonts from the font directory file "fontdir" (in the current
+   directory), if it exists.
+-----------------------------------------------------------------------------*/
+    struct stat statbuf;
+    int rc;
 
-    freePlanes(planes);
+    rc = stat("fontdir", &statbuf);
+    
+    if (rc == 0)
+        load_fontdir("fontdir");
 }
 
 
@@ -3762,8 +4305,6 @@ main(int argc, char * argv[]) {
         ++argn;
     }
 
-    load_fontdir("fontdir");
-
     if (argn < argc) {
         ifp = pm_openr(argv[argn]);
         ++argn;
@@ -3773,12 +4314,17 @@ main(int argc, char * argv[]) {
     if (argn != argc)
         pm_usage(usage);
 
+    loadDefaultFontDir();
+
     if (header) {
         stage = "Reading 512 byte header";
+        /* Note that the "header" in PICT is entirely comment! */
         skip(512);
     }
 
-    interpret_pict();
+    interpret_pict(stdout);
+
+    pm_close(stdout);
 
     return 0;
 }
diff --git a/converter/ppm/ppmtoarbtxt.c b/converter/ppm/ppmtoarbtxt.c
index fe466ea5..df859c84 100644
--- a/converter/ppm/ppmtoarbtxt.c
+++ b/converter/ppm/ppmtoarbtxt.c
@@ -24,6 +24,10 @@ typedef enum {
     WIDTH, HEIGHT, POSX, POSY
 } SKL_OBJ_TYP;
 
+typedef enum {
+    OBJTYP_ICOLOR, OBJTYP_FCOLOR, OBJTYP_INT, OBJTYP_BDATA
+} SKL_OBJ_CLASS;
+
 /* Maximum size for a format string ("%d" etc.) */
 #define MAXFORMAT 16
 
@@ -158,257 +162,328 @@ save_bin_data(int    const ndat,
 
 
 
+static SKL_OBJ *
+save_icol_data(SKL_OBJ_TYP  const ctyp,
+               const char * const format,
+               int          const icolmin,
+               int          const icolmax) {
 /* Save integer color data in Object */
-static SKL_OBJ *save_icol_data (ctyp,format,icolmin,icolmax)
-SKL_OBJ_TYP ctyp;
-char *format;
-int icolmin, icolmax;
 
-{SKL_OBJ *obj;
+    SKL_OBJ * objP;
 
- obj = (SKL_OBJ *)malloc (sizeof (SKL_OBJ));
- if (obj != NULL)
- {
-   obj->otyp = ctyp;
-   strcpy (obj->odata.icol_data.icformat,format);
-   obj->odata.icol_data.icolmin = icolmin;
-   obj->odata.icol_data.icolmax = icolmax;
- }
- return (obj);
+    MALLOCVAR(objP);
+
+    if (objP) {
+        objP->otyp = ctyp;
+        strcpy(objP->odata.icol_data.icformat, format);
+        objP->odata.icol_data.icolmin = icolmin;
+        objP->odata.icol_data.icolmax = icolmax;
+    }
+    return objP;
 }
 
 
+
+static SKL_OBJ *
+save_fcol_data(SKL_OBJ_TYP  const ctyp,
+               const char * const format,
+               double       const fcolmin,
+               double       const fcolmax) {
 /* Save float color data in Object */
-static SKL_OBJ *save_fcol_data (ctyp,format,fcolmin,fcolmax)
-SKL_OBJ_TYP ctyp;
-char *format;
-double fcolmin, fcolmax;
 
-{SKL_OBJ *obj;
+    SKL_OBJ * objP;
 
- obj = (SKL_OBJ *)malloc (sizeof (SKL_OBJ));
- if (obj != NULL)
- {
-   obj->otyp = ctyp;
-   strcpy (obj->odata.fcol_data.fcformat,format);
-   obj->odata.fcol_data.fcolmin = fcolmin;
-   obj->odata.fcol_data.fcolmax = fcolmax;
- }
- return (obj);
+    MALLOCVAR(objP);
+
+    if (objP) {
+        objP->otyp = ctyp;
+        strcpy(objP->odata.fcol_data.fcformat, format);
+        objP->odata.fcol_data.fcolmin = fcolmin;
+        objP->odata.fcol_data.fcolmax = fcolmax;
+    }
+    return objP;
 }
 
 
+
+static SKL_OBJ *
+save_i_data(SKL_OBJ_TYP  const ctyp,
+            const char * const format) {
+
 /* Save universal data in Object */
-static SKL_OBJ *save_i_data (ctyp,format)
-SKL_OBJ_TYP ctyp;
-char *format;
 
-{SKL_OBJ *obj;
+    SKL_OBJ * objP;
 
- obj = (SKL_OBJ *)malloc (sizeof (SKL_OBJ));
- if (obj != NULL)
- {
-   obj->otyp = ctyp;
-   strcpy (obj->odata.i_data.iformat,format);
- }
- return (obj);
+    MALLOCVAR(objP);
+    if (objP) {
+        objP->otyp = ctyp;
+        strcpy(objP->odata.i_data.iformat, format);
+    }
+    return objP;
 }
 
 
-/* Read skeleton file */
-static int read_skeleton (filename,maxskl,nskl,skl)
-char *filename;
-int maxskl,*nskl;
-SKL_OBJ **skl;
 
-{FILE *sklfile;
- int slen, objlen, chr, n_odata;
- int icolmin,icolmax;
- double fcolmin,fcolmax;
- SKL_OBJ_TYP otyp;
- char line[MAX_LINE_BUF+MAX_OBJ_BUF+16];
- char objstr[MAX_OBJ_BUF],typstr[MAX_OBJ_BUF];
- char formstr[MAX_OBJ_BUF];
- char meta1 = '#', meta2 = '(', meta3 = ')';
+static char const escape = '#';
 
-#define SAVE_BIN(slen,line) \
- { if ((skl[*nskl] = save_bin_data (slen,line)) != NULL) (*nskl)++; \
-   slen = 0; }
 
-#define ADD_STR(slen,line,addlen,addstr) \
- {int count=0; line[slen++] = meta1; line[slen++] = meta2; \
-  while (count++ < addlen) line[slen++] = addstr[count]; }
 
- if ((sklfile = fopen (filename,"r")) == NULL)
-   return (-1);
+static SKL_OBJ_TYP
+interpretObjType(const char * const typstr) {
 
- /* Parse skeleton file */
- *nskl = 0;
+    SKL_OBJ_TYP otyp;
 
- slen = 0;
- while ((chr = getc (sklfile)) != EOF)   /* Up to end of skeleton file */
- {
-   if (*nskl >= maxskl) return (-1);
+    /* Check for integer colors */
+    if      (streq(typstr, "ired")  ) otyp = IRED;
+    else if (streq(typstr, "igreen")) otyp = IGREEN;
+    else if (streq(typstr, "iblue") ) otyp = IBLUE;
+    else if (streq(typstr, "ilum")  ) otyp = ILUM;
+    /* Check for real colors */
+    else if (streq(typstr, "fred")  ) otyp = FRED;
+    else if (streq(typstr, "fgreen")) otyp = FGREEN;
+    else if (streq(typstr, "fblue") ) otyp = FBLUE;
+    else if (streq(typstr, "flum")  ) otyp = FLUM;
+    /* Check for integer data */
+    else if (streq(typstr, "width") ) otyp = WIDTH;
+    else if (streq(typstr, "height")) otyp = HEIGHT;
+    else if (streq(typstr, "posx")  ) otyp = POSX;
+    else if (streq(typstr, "posy")  ) otyp = POSY;
+    else                              otyp = BDATA;
 
-   if (slen+1 >= MAX_LINE_BUF)   /* Buffer finished ? Save as binary object */
-   {
-     SAVE_BIN (slen,line);
-   }
+    return otyp;
+}
 
-   if (chr != meta1)      /* Look for start of replacement string */
-   {
-     line[slen++] = chr;
-     continue;
-   }
 
-   if ((chr = getc (sklfile)) == EOF)
-   {
-     line[slen++] = meta1;
-     break;
-   }
-   if (chr != meta2) /* '(' ? Otherwise no replacement */
-   {
-     line[slen++] = meta1;
-     line[slen++] = chr;
-     continue;
-   }
 
-   objlen = 0;
-   for (;;)   /* Read replacement string up to ')' */
-   {
-     if (objlen == sizeof (objstr)-1) break; /* ')' not found */
-     if ((chr = getc (sklfile)) == EOF) break;
-     if (chr == meta3) break;
-     objstr[objlen++] = chr;
-   }
-   objstr[objlen] = '\0'; /* Now objstr keeps data without metas */
+static SKL_OBJ_CLASS
+objClass(SKL_OBJ_TYP const otyp) {
 
-   if (chr != meta3)    /* Object not found ? */
-   {
-     ADD_STR (slen,line,objlen,objstr);   /* Save what we already read */
-     if (chr == EOF) break;
-     continue;
-   }
+    switch (otyp) {
+    case IRED:
+    case IGREEN:
+    case IBLUE:
+    case ILUM:
+        return OBJTYP_ICOLOR;
 
-   typstr[0] = '\0';           /* Get typ of data */
-   sscanf (objstr,"%s",typstr);
-
-                   /* Check for integer colors */
-   if      (STREQ(typstr,"ired")  ) otyp = IRED;
-   else if (STREQ(typstr,"igreen")) otyp = IGREEN;
-   else if (STREQ(typstr,"iblue") ) otyp = IBLUE;
-   else if (STREQ(typstr,"ilum")  ) otyp = ILUM;
-                   /* Check for real colors */
-   else if (STREQ(typstr,"fred")  ) otyp = FRED;
-   else if (STREQ(typstr,"fgreen")) otyp = FGREEN;
-   else if (STREQ(typstr,"fblue") ) otyp = FBLUE;
-   else if (STREQ(typstr,"flum")  ) otyp = FLUM;
-                   /* Check for integer data */
-   else if (STREQ(typstr,"width") ) otyp = WIDTH;
-   else if (STREQ(typstr,"height")) otyp = HEIGHT;
-   else if (STREQ(typstr,"posx")  ) otyp = POSX;
-   else if (STREQ(typstr,"posy")  ) otyp = POSY;
-   else                                    otyp = BDATA;
-
-   if ((otyp == IRED) || (otyp == IGREEN) || (otyp == IBLUE) || (otyp == ILUM))
-   {
-     n_odata = sscanf (objstr,"%*s%s%d%d",formstr,&icolmin,&icolmax);
-
-     if (n_odata == EOF)  /* No arguments specified ? Use defaults */
-     {
-       strcpy (formstr,"%d"); icolmin = 0; icolmax = 255;
-     }
-     else if (n_odata != 3)  /* Wrong specification */
-     {
-       otyp = BDATA;
-     }
-   }
+    case FRED:
+    case FGREEN:
+    case FBLUE:
+    case FLUM:
+        return OBJTYP_FCOLOR;
 
-   if ((otyp == FRED) || (otyp == FGREEN) || (otyp == FBLUE) || (otyp == FLUM))
-   {
-     n_odata = sscanf (objstr,"%*s%s%lf%lf",formstr,&fcolmin,&fcolmax);
-
-     if (n_odata == EOF)  /* No arguments specified ? Use defaults */
-     {
-       strcpy (formstr,"%f"); fcolmin = 0.0; fcolmax = 1.0;
-     }
-     else if (n_odata != 3)  /* Wrong specification */
-     {
-       otyp = BDATA;
-     }
-   }
+    case WIDTH:
+    case HEIGHT:
+    case POSX:
+    case POSY:
+        return OBJTYP_INT;
+    case BDATA:
+        return OBJTYP_BDATA;
+    }
+    return 999; /* quiet compiler warning */
+}
 
-   if (   (otyp == WIDTH) || (otyp == HEIGHT)
-       || (otyp == POSX) || (otyp == POSY))
-   {
-     n_odata = sscanf (objstr,"%*s%s",formstr);
-
-     if (n_odata == EOF)  /* No arguments specified ? Use defaults */
-     {
-       strcpy (formstr,"%d");
-     }
-     else if (n_odata != 1)  /* Wrong specification */
-     {
-       otyp = BDATA;
-     }
-   }
 
-   if (otyp != BDATA)   /* Got an object definition ? */
-   {
-     if (slen > 0)      /* Save what we already found */
-     {
-       SAVE_BIN (slen,line);
-     }
-   }
 
-   /* Now process the object in objstr */
-   switch (otyp)
-   {
-     case BDATA:   /* Bad object definition ? Save as text */
-       ADD_STR (slen,line,objlen,objstr);
-       break;
+static void
+addImpostorReplacementSeq(char *         const line,
+                          unsigned int   const startCursor,
+                          const char *   const seqContents,
+                          unsigned int   const seqContentsLen,
+                          unsigned int * const newCursorP) {
+/*----------------------------------------------------------------------------
+   Add to line line[], at position 'startCursor', text that looks like a
+   replacement sequence but doesn't have the proper contents (the
+   stuff between the parentheses) to be one.  For example,
 
-     case IRED:
-     case IGREEN:
-     case IBLUE:
-     case ILUM:
-       skl[*nskl] = save_icol_data (otyp,formstr,icolmin,icolmax);
-       if (skl[*nskl] != NULL) (*nskl)++;
-       break;
+     "#(fread x)"
 
-     case FRED:
-     case FGREEN:
-     case FBLUE:
-     case FLUM:
-       skl[*nskl] = save_fcol_data (otyp,formstr,fcolmin,fcolmax);
-       if (skl[*nskl] != NULL) (*nskl)++;
-       break;
+   seqContents[] is the contents; 'seqContentsLen' its length.
 
-     case WIDTH:
-     case HEIGHT:
-     case POSX:
-     case POSY:
-       skl[*nskl] = save_i_data (otyp,formstr);
-       if (skl[*nskl] != NULL) (*nskl)++;
-       break;
-   }
- } /* EOF of skeleton file */
+   Return as *newCursorP where the line[] cursor ends up after adding
+   the sequence.
+-----------------------------------------------------------------------------*/
+    unsigned int cursor;
+    unsigned int i;
 
- if (slen > 0)      /* Drop finishing newline character */
- {
-   if (line[slen-1] == '\n') slen--;
- }
+    cursor = startCursor;
 
- if (slen > 0)      /* Something left ? */
- {
-   SAVE_BIN (slen,line);   /* Save it */
- }
+    line[cursor++] = escape;
+    line[cursor++] = '(';
 
- fclose (sklfile);
- return (0);
+    for (i = 0; i < seqContentsLen; ++i)
+        line[cursor++] = seqContents[i];
+
+    line[cursor++] = ')';
+
+    *newCursorP = cursor;
 }
 
 
+
+static int
+read_skeleton(const char *   const filename,
+              unsigned int   const maxskl,
+              unsigned int * const nsklP,
+              SKL_OBJ **     const skl) {
+/*----------------------------------------------------------------------------
+  Read skeleton file
+-----------------------------------------------------------------------------*/
+    FILE * sklfile;
+    unsigned int slen;
+    unsigned int objlen;
+    int chr;
+    SKL_OBJ_TYP otyp;
+    char line[MAX_LINE_BUF+MAX_OBJ_BUF+16];
+    char objstr[MAX_OBJ_BUF],typstr[MAX_OBJ_BUF];
+    unsigned int nskl;
+
+#define SAVE_BIN(slen,line) \
+    { if (slen > 0 && (skl[nskl] = save_bin_data(slen,line)) != NULL) ++nskl; \
+      slen = 0; }
+
+    sklfile = pm_openr(filename);
+
+    /* Parse skeleton file */
+    nskl = 0;  /* initial value */
+
+    slen = 0;
+    while ((chr = getc (sklfile)) != EOF) {  /* Up to end of skeleton file */
+        if (nskl >= maxskl)
+            return -1;
+
+        if (slen+1 >= MAX_LINE_BUF) {
+            /* Buffer finished.  Save as binary object */
+            SAVE_BIN(slen,line);
+        }
+
+        if (chr != escape) {
+            /* Not a replacement sequence; just a literal character */
+            line[slen++] = chr;
+            continue;
+        }
+
+        chr = getc(sklfile);
+        if (chr == EOF) {
+            /* Not a valid replacement sequence */
+            line[slen++] = escape;
+            break;
+        }
+        if (chr != '(') {
+            /* Not a valid replacement sequence */
+            line[slen++] = escape;
+            line[slen++] = chr;
+            continue;
+        }
+        /* Read replacement string up through ')'.  Put contents of
+           parentheses in objstr[].
+        */
+        for (objlen = 0; objlen < sizeof(objstr)-1; ++objlen) {
+            chr = getc(sklfile);
+            if (chr == EOF) break;
+            if (chr == ')') break;
+            objstr[objlen] = chr;
+        }
+        objstr[objlen] = '\0';
+
+        if (chr != ')') {
+            /* Not valid replacement sequence */
+            unsigned int i;
+            line[slen++] = escape;
+            line[slen++] = chr;
+            for (i = 0; i < objlen; ++i)
+                line[slen++] = objstr[i];
+            if (chr == EOF)
+                break;
+            continue;
+        }
+
+        typstr[0] = '\0';           /* Get typ of data */
+        sscanf(objstr, "%s", typstr);
+
+        otyp = interpretObjType(typstr);
+
+        switch (objClass(otyp)) {
+        case OBJTYP_ICOLOR: {
+            int icolmin, icolmax;
+            char formstr[MAX_OBJ_BUF];
+            int n_odata;
+
+            n_odata = sscanf(objstr, "%*s%s%d%d", formstr, &icolmin, &icolmax);
+
+            if (n_odata == 3) {
+                SAVE_BIN(slen, line);
+                skl[nskl] = save_icol_data(otyp, formstr, icolmin, icolmax);
+                if (skl[nskl] != NULL)
+                    ++nskl;
+            } else if (n_odata == EOF) {
+                /* No arguments specified.  Use defaults */
+                SAVE_BIN(slen, line);
+                skl[nskl] = save_icol_data(otyp, "%d", 0, 255);
+                if (skl[nskl] != NULL)
+                    ++nskl;
+            } else
+                addImpostorReplacementSeq(line, slen, objstr, objlen, &slen);
+        } break;
+        case OBJTYP_FCOLOR: {
+            double fcolmin, fcolmax;
+            char formstr[MAX_OBJ_BUF];
+            int n_odata;
+
+            n_odata = sscanf(objstr, "%*s%s%lf%lf", formstr,
+                             &fcolmin, &fcolmax);
+
+            if (n_odata == 3) {
+                SAVE_BIN(slen, line);
+                skl[nskl] = save_fcol_data(otyp, formstr, fcolmin, fcolmax);
+                if (skl[nskl] != NULL)
+                    ++nskl;
+            } else if (n_odata == EOF) {
+                /* No arguments specified.  Use defaults */
+                SAVE_BIN(slen, line);
+                skl[nskl] = save_fcol_data(otyp, "%f", 0.0, 1.0);
+                if (skl[nskl] != NULL)
+                    ++nskl;
+            } else
+                addImpostorReplacementSeq(line, slen, objstr, objlen, &slen);
+        } break;
+
+        case OBJTYP_INT: {
+            char formstr[MAX_OBJ_BUF];
+            int const n_odata = sscanf(objstr, "%*s%s", formstr);
+
+            if (n_odata == 1) {
+                SAVE_BIN(slen, line);
+                skl[nskl] = save_i_data(otyp, formstr);
+                if (skl[nskl] != NULL)
+                    ++nskl;
+            } else if (n_odata == EOF) {
+                /* No arguments specified.  Use defaults */
+                SAVE_BIN(slen, line);
+                skl[nskl] = save_i_data(otyp, "%d");
+                if (skl[nskl] != NULL)
+                    ++nskl;
+            } else
+                addImpostorReplacementSeq(line, slen, objstr, objlen, &slen);
+        } break;
+        case OBJTYP_BDATA:
+            addImpostorReplacementSeq(line, slen, objstr, objlen, &slen);
+        }
+    } /* EOF of skeleton file */
+
+    if (slen >= 1 && line[slen-1] == '\n')
+        /* Drop finishing newline character */
+        --slen;
+
+    SAVE_BIN(slen, line);  /* Save whatever is left */
+
+    *nsklP = nskl;
+
+    fclose(sklfile);
+    return 0;
+}
+
+
+
 int main( argc, argv )
 int argc;
 char* argv[];
@@ -419,7 +494,7 @@ char* argv[];
  pixval maxval,red,green,blue;
  double dmaxval;
  int argn, rows, cols, format, row;
- int head_nskl,body_nskl,tail_nskl;
+ unsigned int head_nskl,body_nskl,tail_nskl;
  SKL_OBJ *head_skl[MAX_SKL_HEAD_OBJ];
  SKL_OBJ *body_skl[MAX_SKL_BODY_OBJ];
  SKL_OBJ *tail_skl[MAX_SKL_TAIL_OBJ];
diff --git a/converter/ppm/ppmtobmp.c b/converter/ppm/ppmtobmp.c
index 635464dd..c295f70c 100644
--- a/converter/ppm/ppmtobmp.c
+++ b/converter/ppm/ppmtobmp.c
@@ -18,15 +18,24 @@
 
 #include <assert.h>
 #include <string.h>
-#include "bmp.h"
-#include "ppm.h"
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
 #include "shhopt.h"
+#include "bmp.h"
 #include "bitio.h"
+#include "ppm.h"
 
 #define MAXCOLORS 256
 
 enum colortype {TRUECOLOR, PALETTE};
 
+struct rgb {
+    unsigned char red;
+    unsigned char grn;
+    unsigned char blu;
+};
+
 typedef struct {
 /*----------------------------------------------------------------------------
    A color map for a BMP file.
@@ -34,13 +43,13 @@ typedef struct {
     unsigned int count;
         /* Number of colors in the map.  The first 'count' elements of these
            arrays are defined; all others are not.
+
+           At most MAXCOLORS.
         */
     colorhash_table cht;
 
-    /* Indices in the following arrays are the same as in 'cht', above. */
-    unsigned char red[MAXCOLORS];
-    unsigned char grn[MAXCOLORS];
-    unsigned char blu[MAXCOLORS];
+    /* Indices in the following array are the same as in 'cht', above. */
+    struct rgb bmpMap[MAXCOLORS];
 } colorMap;
 
 
@@ -54,7 +63,7 @@ freeColorMap(const colorMap * const colorMapP) {
 
 
 
-static struct cmdline_info {
+struct cmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -62,63 +71,71 @@ static struct cmdline_info {
     int class;  /* C_WIN or C_OS2 */
     unsigned int bppSpec;
     unsigned int bpp;
-} cmdline;
+    const char * mapfile;
+};
 
 
 static void
-parse_command_line(int argc, char ** argv,
-                   struct cmdline_info *cmdline_p) {
+parseCommandLine(int argc, const char ** argv,
+                 struct cmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that many of the strings that this function returns in the
    *cmdline_p structure are actually in the supplied argv array.  And
    sometimes, one of these strings is actually just a suffix of an entry
    in argv!
 -----------------------------------------------------------------------------*/
-    optEntry *option_def = malloc(100*sizeof(optEntry));
+    optEntry * option_def;
         /* Instructions to OptParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
 
-    unsigned int windowsSpec, os2Spec;
+    unsigned int windowsSpec, os2Spec, mapfileSpec;
 
     unsigned int option_def_index;
+    
+    MALLOCARRAY(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENTRY */
     OPTENT3('w', "windows",   OPT_FLAG, NULL, &windowsSpec,            0);
     OPTENT3('o', "os2",       OPT_FLAG, NULL, &os2Spec,                0);
-    OPTENT3(0,   "bpp",       OPT_UINT, &cmdline_p->bpp, 
-            &cmdline_p->bppSpec,      0);
+    OPTENT3(0,   "bpp",       OPT_UINT, &cmdlineP->bpp, 
+            &cmdlineP->bppSpec,      0);
+    OPTENT3(0,   "mapfile",   OPT_STRING, &cmdlineP->mapfile, 
+            &mapfileSpec,             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);
+    optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
 
     if (windowsSpec && os2Spec) 
         pm_error("Can't specify both -windows and -os2 options.");
     else if (windowsSpec) 
-        cmdline_p->class = C_WIN;
+        cmdlineP->class = C_WIN;
     else if (os2Spec)
-        cmdline_p->class = C_OS2;
+        cmdlineP->class = C_OS2;
     else 
-        cmdline_p->class = C_WIN;
+        cmdlineP->class = C_WIN;
 
 
-    if (cmdline_p->bppSpec) {
-        if (cmdline_p->bpp != 1 && cmdline_p->bpp != 4 && 
-            cmdline_p->bpp != 8 && cmdline_p->bpp != 24)
-        pm_error("Invalid -bpp value specified: %u.  The only values valid\n"
+    if (cmdlineP->bppSpec) {
+        if (cmdlineP->bpp != 1 && cmdlineP->bpp != 4 && 
+            cmdlineP->bpp != 8 && cmdlineP->bpp != 24)
+        pm_error("Invalid -bpp value specified: %u.  The only values valid "
                  "in the BMP format are 1, 4, 8, and 24 bits per pixel",
-                 cmdline_p->bpp);
+                 cmdlineP->bpp);
     }
 
+    if (!mapfileSpec)
+        cmdlineP->mapfile = NULL;
+
     if (argc - 1 == 0)
-        cmdline_p->input_filename = strdup("-");  /* he wants stdin */
+        cmdlineP->input_filename = strdup("-");  /* he wants stdin */
     else if (argc - 1 == 1)
-        cmdline_p->input_filename = strdup(argv[1]);
+        cmdlineP->input_filename = strdup(argv[1]);
     else 
-        pm_error("Too many arguments.  The only argument accepted\n"
+        pm_error("Too many arguments.  The only argument accepted "
                  "is the input file specificaton");
 
 }
@@ -243,7 +260,7 @@ BMPwriteinfoheader(FILE *        const fp,
 
 
 static int
-BMPwritergb(FILE * const fp, 
+BMPwriteRgb(FILE * const fp, 
             int    const class, 
             pixval const R, 
             pixval const G, 
@@ -264,7 +281,7 @@ BMPwritergb(FILE * const fp,
         PutByte(fp, R);
         return 3;
     default:
-        pm_error(er_internal, "BMPwritergb");
+        pm_error(er_internal, "BMPwriteRgb");
     }
     return -1;
 }
@@ -272,101 +289,118 @@ BMPwritergb(FILE * const fp,
 
 
 static int
-BMPwritecolormap(FILE *           const ifP, 
+BMPwriteColormap(FILE *           const ifP, 
                  int              const class, 
                  int              const bpp,
                  const colorMap * const colorMapP) {
 /*----------------------------------------------------------------------------
   Return the number of bytes written, or -1 on error.
 -----------------------------------------------------------------------------*/
-    long const ncolors = (1 << bpp);
+    unsigned int const ncolors = (1 << bpp);
 
-    unsigned int  nbyte;
-    unsigned int  i;
+    unsigned int nbyte;
+    unsigned int i;
 
-    nbyte = 0;
-    for (i = 0; i < colorMapP->count; ++i)
-        nbyte += BMPwritergb(ifP, class,
-                             colorMapP->red[i],
-                             colorMapP->grn[i],
-                             colorMapP->blu[i]);
+    assert(ncolors <= MAXCOLORS);
+    assert(ncolors <= ARRAY_SIZE(colorMapP->bmpMap));
 
+    nbyte = 0;
+    for (i = 0; i < colorMapP->count; ++i) {
+        const struct rgb * const mapEntryP = &colorMapP->bmpMap[i];
+        nbyte += BMPwriteRgb(ifP, class,
+                             mapEntryP->red, mapEntryP->grn, mapEntryP->blu);
+    }
     for (; i < ncolors; ++i)
-        nbyte += BMPwritergb(ifP, class, 0, 0, 0);
+        nbyte += BMPwriteRgb(ifP, class, 0, 0, 0);
 
     return nbyte;
 }
 
 
 
-static int
-BMPwriterow_palette(FILE *          const fp, 
+static void
+lookupColor(colorhash_table const cht,
+            pixel           const color,
+            unsigned int *  const colorIndexP) {
+
+    int rc;
+
+    rc = ppm_lookupcolor(cht, &color);
+
+    if (rc < 0)
+        pm_error("Color (%u,%u,%u) is not in the provided palette",
+                 PPM_GETR(color), PPM_GETG(color), PPM_GETB(color));
+    else
+        *colorIndexP = rc;
+}
+
+
+
+static void
+bmpWriteRow_palette(FILE *          const fp, 
                     const pixel *   const row, 
-                    unsigned long   const cx, 
+                    unsigned int    const cols,
                     unsigned short  const bpp, 
-                    colorhash_table const cht) {
+                    colorhash_table const cht,
+                    unsigned int *  const nBytesP) {
 /*----------------------------------------------------------------------------
-  Return the number of bytes written, or -1 on error.
+   Write a row to the raster in paletted format.
+
+   Return the number of bytes written as *nBytesP.
 -----------------------------------------------------------------------------*/
-    BITSTREAM    b;
-    int retval;
+    BITSTREAM b;
     
     b = pm_bitinit(fp, "w");
     if (b == NULL)
-        retval = -1;
+        pm_error("Failed to initialize output file for output");
     else {
+        int rc;
         unsigned int nbyte;
-        unsigned int x;
-        bool         error;
+        unsigned int col;
         
         nbyte = 0;      /* initial value */
-        error = FALSE;  /* initial value */
         
-        for (x = 0; x < cx && !error; ++x) {
+        for (col = 0; col < cols; ++col) {
+            unsigned int colorIndex;
             int rc;
-            rc = pm_bitwrite(b, bpp, ppm_lookupcolor(cht, &row[x]));
+
+            lookupColor(cht, row[col], &colorIndex);
+
+            rc = pm_bitwrite(b, bpp, colorIndex);
             if (rc == -1)
-                error = TRUE;
+                pm_error("Failed in writing a pixel "
+                         "to the raster in the output file");
             else
                 nbyte += rc;
         }
-        if (error)
-            retval = -1;
-        else {
-            int rc;
 
-            rc = pm_bitfini(b);
-            if (rc == -1)
-                retval = -1;
-            else {
-                nbyte += rc;
+        rc = pm_bitfini(b);
+
+        nbyte += rc;
                 
-                /* Make sure we write a multiple of 4 bytes.  */
-                while (nbyte % 4 != 0) {
-                    PutByte(fp, 0);
-                    ++nbyte;
-                }
-                retval = nbyte;
-            }
+        /* Make sure we write a multiple of 4 bytes.  */
+        while (nbyte % 4 != 0) {
+            PutByte(fp, 0);
+            ++nbyte;
         }
+        *nBytesP = nbyte;
     }
-    return retval;
 }
 
 
 
-static int
-BMPwriterow_truecolor(FILE *        const fp, 
-                      const pixel * const row, 
-                      unsigned long const cols,
-                      pixval        const maxval) {
+static void
+bmpWriteRow_truecolor(FILE *         const fp, 
+                      const pixel *  const row, 
+                      unsigned long  const cols,
+                      pixval         const maxval,
+                      unsigned int * const nBytesP) {
 /*----------------------------------------------------------------------------
   Write a row of a truecolor BMP image to the file 'fp'.  The row is 
   'row', which is 'cols' columns long.
 
-  Return the number of bytes written.
 
-  On error, issue error message and exit program.
+  Return the number of bytes written as *nBytesP.
 -----------------------------------------------------------------------------*/
     /* This works only for 24 bits per pixel.  To implement this for the
        general case (which is only hypothetical -- this program doesn't
@@ -380,7 +414,7 @@ BMPwriterow_truecolor(FILE *        const fp,
     int col;  
         
     nbyte = 0;  /* initial value */
-    for (col = 0; col < cols; col++) {
+    for (col = 0; col < cols; ++col) {
         /* We scale to the BMP maxval, which is always 255. */
         PutByte(fp, PPM_GETB(row[col]) * 255 / maxval);
         PutByte(fp, PPM_GETG(row[col]) * 255 / maxval);
@@ -393,18 +427,18 @@ BMPwriterow_truecolor(FILE *        const fp,
      */
     while (nbyte % 4) {
         PutByte(fp, 0);
-        nbyte++;
+        ++nbyte;
     }
     
-    return nbyte;
+    *nBytesP = nbyte;
 }
 
 
 
 static int
 BMPwritebits(FILE *          const fp, 
-             unsigned long   const cx, 
-             unsigned long   const cy, 
+             unsigned long   const cols, 
+             unsigned long   const rows,
              enum colortype  const colortype,
              unsigned short  const cBitCount, 
              const pixel **  const pixels, 
@@ -413,29 +447,29 @@ BMPwritebits(FILE *          const fp,
 /*----------------------------------------------------------------------------
   Return the number of bytes written, or -1 on error.
 -----------------------------------------------------------------------------*/
-    int  nbyte;
-    long y;
+    unsigned int nbyte;
+    int row;
 
     if (cBitCount > 24)
-        pm_error("cannot handle cBitCount: %d", cBitCount);
+        pm_error("cannot handle cBitCount: %hu", cBitCount);
 
     nbyte = 0;  /* initial value */
 
     /* The picture is stored bottom line first, top line last */
 
-    for (y = cy - 1; y >= 0; --y) {
-        int rc;
+    for (row = rows - 1; row >= 0; --row) {
+        unsigned int nBytesThisRow;
+
         if (colortype == PALETTE)
-            rc = BMPwriterow_palette(fp, pixels[y], cx, 
-                                     cBitCount, cht);
+            bmpWriteRow_palette(fp, pixels[row], cols, 
+                                cBitCount, cht, &nBytesThisRow);
         else 
-            rc = BMPwriterow_truecolor(fp, pixels[y], cx, maxval);
+            bmpWriteRow_truecolor(fp, pixels[row], cols, maxval,
+                                  &nBytesThisRow);
 
-        if (rc == -1)
-            pm_error("couldn't write row %ld", y);
-        if (rc % 4 != 0)
-            pm_error("row had bad number of bytes: %d", rc);
-        nbyte += rc;
+        if (nBytesThisRow % 4 != 0)
+            pm_error("row had bad number of bytes: %u", nBytesThisRow);
+        nbyte += nBytesThisRow;
     }
 
     return nbyte;
@@ -444,10 +478,10 @@ BMPwritebits(FILE *          const fp,
 
 
 static void
-BMPEncode(FILE *           const ifP, 
+bmpEncode(FILE *           const ifP, 
           int              const class, 
           enum colortype   const colortype,
-          int              const bpp,
+          unsigned int     const bpp,
           int              const x, 
           int              const y, 
           const pixel **   const pixels, 
@@ -459,25 +493,25 @@ BMPEncode(FILE *           const ifP,
     unsigned long nbyte;
 
     if (colortype == PALETTE)
-        pm_message("Writing %d bits per pixel with a color palette", bpp);
+        pm_message("Writing %u bits per pixel with a color palette", bpp);
     else
-        pm_message("Writing %d bits per pixel truecolor (no palette)", bpp);
+        pm_message("Writing %u bits per pixel truecolor (no palette)", bpp);
 
     nbyte = 0;  /* initial value */
     nbyte += BMPwritefileheader(ifP, class, bpp, x, y);
     nbyte += BMPwriteinfoheader(ifP, class, bpp, x, y);
     if (colortype == PALETTE)
-        nbyte += BMPwritecolormap(ifP, class, bpp, colorMapP);
+        nbyte += BMPwriteColormap(ifP, class, bpp, colorMapP);
 
     if (nbyte != (BMPlenfileheader(class)
                   + BMPleninfoheader(class)
                   + BMPlencolormap(class, bpp, 0)))
-        pm_error(er_internal, "BMPEncode 1");
+        pm_error(er_internal, "BmpEncode 1");
 
     nbyte += BMPwritebits(ifP, x, y, colortype, bpp, pixels, maxval,
                           colorMapP->cht);
     if (nbyte != BMPlenfile(class, bpp, -1, x, y))
-        pm_error(er_internal, "BMPEncode 2");
+        pm_error(er_internal, "BmpEncode 2");
 }
 
 
@@ -487,18 +521,18 @@ makeBilevelColorMap(colorMap * const colorMapP) {
 
     colorMapP->count  = 2;
     colorMapP->cht    = NULL;
-    colorMapP->red[0] = 0;
-    colorMapP->grn[0] = 0;
-    colorMapP->blu[0] = 0;
-    colorMapP->red[1] = 255;
-    colorMapP->grn[1] = 255;
-    colorMapP->blu[1] = 255;
+    colorMapP->bmpMap[0].red = 0;
+    colorMapP->bmpMap[0].grn = 0;
+    colorMapP->bmpMap[0].blu = 0;
+    colorMapP->bmpMap[1].red = 255;
+    colorMapP->bmpMap[1].grn = 255;
+    colorMapP->bmpMap[1].blu = 255;
 }
 
 
 
 static void
-BMPEncodePBM(FILE *           const ifP, 
+bmpEncodePbm(FILE *           const ifP, 
              int              const class, 
              int              const cols, 
              int              const rows, 
@@ -508,7 +542,7 @@ BMPEncodePBM(FILE *           const ifP,
 -----------------------------------------------------------------------------*/
     /* Note:
        Only PBM input uses this routine.  Color images represented by 1 bpp via
-       color palette use the general BMPEncode().
+       color palette use the general bmpEncode().
     */
     unsigned int const adjustedCols = (cols + 31) / 32 * 32;
     unsigned int const packedBytes  = adjustedCols / 8;
@@ -526,12 +560,12 @@ BMPEncodePBM(FILE *           const ifP,
 
     makeBilevelColorMap(&bilevelColorMap);
 
-    nbyte += BMPwritecolormap(ifP, class, 1, &bilevelColorMap);
+    nbyte += BMPwriteColormap(ifP, class, 1, &bilevelColorMap);
 
     if (nbyte != (BMPlenfileheader(class)
                   + BMPleninfoheader(class)
                   + BMPlencolormap(class, 1, 0)))
-        pm_error(er_internal, "BMPEncodePBM 1");
+        pm_error(er_internal, "bmpEncodePBM 1");
    
     for (row = 0; row < rows; ++row){
         size_t bytesWritten;
@@ -548,23 +582,129 @@ BMPEncodePBM(FILE *           const ifP,
     }
 
     if (nbyte != BMPlenfile(class, 1, -1, cols, rows))
-        pm_error(er_internal, "BMPEncodePBM 2");
+        pm_error(er_internal, "bmpEncodePbm 2");
 }
 
 
 
 static void
-analyze_colors(const pixel **    const pixels, 
-               int               const cols, 
-               int               const rows, 
-               pixval            const maxval, 
-               int *             const minimum_bpp_p,
-               colorMap *        const colorMapP) {
+makeHashFromBmpMap(const struct rgb * const bmpMap,
+                   unsigned int       const nColors,
+                   colorhash_table *  const chtP) {
+
+    colorhist_vector chv;
+    unsigned int i;
+
+    MALLOCARRAY_NOFAIL(chv, nColors);
+
+    for (i = 0; i < nColors; ++i) {
+        const struct rgb * const mapEntryP = &bmpMap[i];
+
+        PPM_ASSIGN(chv[i].color,
+                   mapEntryP->red, mapEntryP->grn, mapEntryP->blu);
+    }
+
+    *chtP = ppm_colorhisttocolorhash(chv, nColors);
+
+    ppm_freecolorhist(chv);
+}
+
+
+
+static unsigned int
+minBmpBitsForColorCount(unsigned int const colorCount) {
+
+    unsigned int const minbits = pm_maxvaltobits(colorCount - 1);
+
+    /* Only 1, 4, 8, and 24 are defined in the BMP spec we
+       implement and other bpp's have in fact been seen to confuse
+       viewers.  There is an extended BMP format that has 16 bpp
+       too, but this program doesn't know how to generate that
+       (see Bmptopnm.c, though).  
+    */
+    if (minbits == 1)
+        return 1;
+    else if (minbits <= 4)
+        return 4;
+    else if (minbits <= 8)
+        return 8;
+    else
+        return 24;
+}
+
+
+
+static void
+getMapFile(const char *   const mapFileName,
+           unsigned int * const minimumBppP,
+           colorMap *     const colorMapP) {
+/*----------------------------------------------------------------------------
+   Get the color map (palette) for the BMP from file 'mapFileName'.
+
+   Return the color map as *colormapP.
+
+   Return as *minimumBppP the minimum number of bits per pixel it will
+   take to represent all the colors in the map in the BMP format.
+-----------------------------------------------------------------------------*/
+
+    FILE * mapFileP;
+    int cols, rows;
+    pixval maxval;
+    pixel ** pixels;
+    unsigned int row;
+    unsigned int count;
+
+    mapFileP = pm_openr(mapFileName);
+
+    pixels = ppm_readppm(mapFileP, &cols, &rows, &maxval);
+
+    if (cols * rows > MAXCOLORS)
+        pm_error("The colormap file you gave (-mapfile) has too "
+                 "many entries for a BMP.  A BMP can have at most "
+                 "%u colors; the file has %u pixels, each of which "
+                 "represents an entry in the color map.",
+                 MAXCOLORS, cols * rows);
+
+    count = 0; /* initial value */
+    
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+        for (col = 0; col < cols; ++col) {
+            pixel        const color     = pixels[row][col];
+            struct rgb * const mapEntryP = &colorMapP->bmpMap[count++];
+
+            assert(count <= ARRAY_SIZE(colorMapP->bmpMap));
+
+            mapEntryP->red = PPM_GETR(color) * 255 / maxval;
+            mapEntryP->grn = PPM_GETG(color) * 255 / maxval;
+            mapEntryP->blu = PPM_GETB(color) * 255 / maxval;
+        }
+    }
+    ppm_freearray(pixels, rows);
+
+    colorMapP->count = count;
+
+    makeHashFromBmpMap(colorMapP->bmpMap, colorMapP->count, &colorMapP->cht);
+
+    *minimumBppP = minBmpBitsForColorCount(count);
+
+    pm_close(mapFileP);
+}
+
+
+
+static void
+analyzeColors(const pixel **    const pixels, 
+              int               const cols, 
+              int               const rows, 
+              pixval            const maxval, 
+              unsigned int *    const minimumBppP,
+              colorMap *        const colorMapP) {
 /*----------------------------------------------------------------------------
   Look at the colors in the image 'pixels' and compute values to use in
   representing those colors in a BMP image.  
 
-  First of all, count the distinct colors.  Return as *minimum_bpp_p
+  First of all, count the distinct colors.  Return as *minimumBppP
   the minimum number of bits per pixel it will take to represent all
   the colors in BMP format.
 
@@ -589,37 +729,23 @@ analyze_colors(const pixel **    const pixels,
     colorMapP->count = colorCount;
     if (chv == NULL) {
         pm_message("More than %u colors found", MAXCOLORS);
-        *minimum_bpp_p = 24;
+        *minimumBppP = 24;
         colorMapP->cht = NULL;
     } else {
-        unsigned int const minbits = pm_maxvaltobits(colorMapP->count - 1);
-
         unsigned int i;
 
         pm_message("%u colors found", colorMapP->count);
 
-        /* Only 1, 4, 8, and 24 are defined in the BMP spec we
-           implement and other bpp's have in fact been seen to confuse
-           viewers.  There is an extended BMP format that has 16 bpp
-           too, but this program doesn't know how to generate that
-           (see Bmptopnm.c, though).  
-        */
-        if (minbits == 1)
-            *minimum_bpp_p = 1;
-        else if (minbits <= 4)
-            *minimum_bpp_p = 4;
-        else if (minbits <= 8)
-            *minimum_bpp_p = 8;
-        else
-            *minimum_bpp_p = 24;
+        *minimumBppP = minBmpBitsForColorCount(colorMapP->count);
 
         /*
          * Now scale the maxval to 255 as required by BMP format.
          */
         for (i = 0; i < colorMapP->count; ++i) {
-            colorMapP->red[i] = (pixval) PPM_GETR(chv[i].color) * 255 / maxval;
-            colorMapP->grn[i] = (pixval) PPM_GETG(chv[i].color) * 255 / maxval;
-            colorMapP->blu[i] = (pixval) PPM_GETB(chv[i].color) * 255 / maxval;
+            struct rgb * const mapEntryP = &colorMapP->bmpMap[i];
+            mapEntryP->red = (pixval) PPM_GETR(chv[i].color) * 255 / maxval;
+            mapEntryP->grn = (pixval) PPM_GETG(chv[i].color) * 255 / maxval;
+            mapEntryP->blu = (pixval) PPM_GETB(chv[i].color) * 255 / maxval;
         }
     
         /* And make a hash table for fast lookup. */
@@ -631,38 +757,52 @@ analyze_colors(const pixel **    const pixels,
 
 
 static void
-choose_colortype_bpp(struct cmdline_info const cmdline,
-                     unsigned int        const colors, 
-                     unsigned int        const minimum_bpp,
-                     enum colortype *    const colortype_p, 
-                     unsigned int *      const bits_per_pixel_p) {
+chooseColortypeBpp(bool             const userRequestsBpp,
+                   unsigned int     const requestedBpp,
+                   unsigned int     const minimumBpp,
+                   enum colortype * const colortypeP, 
+                   unsigned int *   const bitsPerPixelP) {
+/*----------------------------------------------------------------------------
+   Determine whether the BMP raster should contain RGB values or palette
+   indices and how many bits is should have for each pixel.
 
-    if (!cmdline.bppSpec) {
+   'userRequestsBpp' says the user has requested a particular number of
+   bits per pixel.  'requestedBpp' is his request, and we assume it's a
+   valid value for a BMP.
+
+   'colors' is how many colors are in the image.
+
+   'minimumBpp' is the minimum number of bits it takes to represent all
+   the colors in the image.  We assume it is valid for a BMP.
+
+   We return our choices as *colortypeP and *bitsPerPixelP.
+-----------------------------------------------------------------------------*/
+    if (!userRequestsBpp) {
         /* User has no preference as to bits per pixel.  Choose the
            smallest number possible for this image.
         */
-        *bits_per_pixel_p = minimum_bpp;
+        *bitsPerPixelP = minimumBpp;
     } else {
-        if (cmdline.bpp < minimum_bpp)
+        if (requestedBpp < minimumBpp)
             pm_error("There are too many colors in the image to "
-                     "represent in the\n"
-                     "number of bits per pixel you requested: %d.\n"
-                     "You may use Ppmquant to reduce the number of "
+                     "represent in the "
+                     "number of bits per pixel you requested: %d.  "
+                     "You may use Pnmquant to reduce the number of "
                      "colors in the image.",
-                     cmdline.bpp);
+                     requestedBpp);
         else
-            *bits_per_pixel_p = cmdline.bpp;
+            *bitsPerPixelP = requestedBpp;
     }
 
-    assert(*bits_per_pixel_p == 1 || 
-           *bits_per_pixel_p == 4 || 
-           *bits_per_pixel_p == 8 || 
-           *bits_per_pixel_p == 24);
+    assert(*bitsPerPixelP == 1 || 
+           *bitsPerPixelP == 4 || 
+           *bitsPerPixelP == 8 || 
+           *bitsPerPixelP == 24);
 
-    if (*bits_per_pixel_p > 8) 
-        *colortype_p = TRUECOLOR;
+    if (*bitsPerPixelP > 8) 
+        *colortypeP = TRUECOLOR;
     else {
-        *colortype_p = PALETTE;
+        *colortypeP = PALETTE;
     }
 }
 
@@ -676,12 +816,12 @@ doPbm(FILE *       const ifP,
       int          const class,
       FILE *       const ofP) {
     
-    /*  In the PBM case the raster is read directly from the input by 
-        pbm_readpbmrow_packed.  The raster format is almost identical,
-        except that BMP specifies rows to be zero-filled to 32 bit borders 
-        and that in BMP the bottom row comes first in order.
+    /* We read the raster directly from the input with
+        pbm_readpbmrow_packed().  The raster format is almost
+        identical, except that BMP specifies rows to be zero-filled to
+        32 bit borders and that in BMP the bottom row comes first in
+        order.
     */
-
     int const CHARBITS = (sizeof(unsigned char)*8); 
     int const colChars = pbm_packed_bytes(cols);
     int const adjustedCols = (cols+31) /32 * 32;
@@ -709,7 +849,7 @@ doPbm(FILE *       const ifP,
                 thisRow[i] = ~thisRow[i]; /* flip all pixels */
         }
         /* This may seem unnecessary, because the color palette 
-           (RGB[] in BMPEncodePBM) can be inverted for the same effect.
+           (RGB[] in bmpEncodePbm) can be inverted for the same effect.
            However we take this precaution, for there is indication that
            some BMP viewers may get confused with that.
         */
@@ -721,25 +861,28 @@ doPbm(FILE *       const ifP,
         }
     }
 
-    BMPEncodePBM(ofP, class, cols, rows, bitrow);
+    bmpEncodePbm(ofP, class, cols, rows, bitrow);
 }            
 
 
 
 static void
-doPgmPpm(FILE * const ifP,
+doPgmPpm(FILE *       const ifP,
          unsigned int const cols,
          unsigned int const rows,
          pixval       const maxval,
          int          const ppmFormat,
          int          const class,
+         bool         const userRequestsBpp,
+         unsigned int const requestedBpp,
+         const char * const mapFileName,
          FILE *       const ofP) {
 
-    /* PGM and PPM.  The input image is read into a PPM array, scanned
-       for color analysis and converted to a BMP raster.
-       Logic works for PBM.
+    /* PGM and PPM.  We read the input image into a PPM array, scan it
+       to analyze the colors, and convert it to a BMP raster.  Logic
+       works for PBM.
     */
-    int minimumBpp;
+    unsigned int minimumBpp;
     unsigned int bitsPerPixel;
     enum colortype colortype;
     unsigned int row;
@@ -752,13 +895,16 @@ doPgmPpm(FILE * const ifP,
     for (row = 0; row < rows; ++row)
         ppm_readppmrow(ifP, pixels[row], cols, maxval, ppmFormat);
     
-    analyze_colors((const pixel**)pixels, cols, rows, maxval, 
-                   &minimumBpp, &colorMap);
+    if (mapFileName)
+        getMapFile(mapFileName, &minimumBpp, &colorMap);
+    else
+        analyzeColors((const pixel**)pixels, cols, rows, maxval, 
+                      &minimumBpp, &colorMap);
     
-    choose_colortype_bpp(cmdline, colorMap.count, minimumBpp, &colortype, 
-                         &bitsPerPixel);
+    chooseColortypeBpp(userRequestsBpp, requestedBpp, minimumBpp,
+                       &colortype, &bitsPerPixel);
     
-    BMPEncode(stdout, class, colortype, bitsPerPixel,
+    bmpEncode(ofP, class, colortype, bitsPerPixel,
               cols, rows, (const pixel**)pixels, maxval, &colorMap);
     
     freeColorMap(&colorMap);
@@ -767,17 +913,19 @@ doPgmPpm(FILE * const ifP,
 
 
 int
-main(int argc, char **argv) {
+main(int           argc,
+     const char ** argv) {
 
+    struct cmdlineInfo cmdline;
     FILE * ifP;
     int rows;
     int cols;
     pixval maxval;
     int ppmFormat;
 
-    ppm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
-    parse_command_line(argc, argv, &cmdline);
+    parseCommandLine(argc, argv, &cmdline);
 
     ifP = pm_openr(cmdline.input_filename);
     
@@ -786,7 +934,9 @@ main(int argc, char **argv) {
     if (PPM_FORMAT_TYPE(ppmFormat) == PBM_TYPE)
         doPbm(ifP, cols, rows, ppmFormat, cmdline.class, stdout);
     else
-        doPgmPpm(ifP, cols, rows, maxval, ppmFormat, cmdline.class, stdout);
+        doPgmPpm(ifP, cols, rows, maxval, ppmFormat,
+                 cmdline.class, cmdline.bppSpec, cmdline.bpp, cmdline.mapfile,
+                 stdout);
 
     pm_close(ifP);
     pm_close(stdout);
diff --git a/converter/ppm/ppmtogif.c b/converter/ppm/ppmtogif.c
index 21ac1989..93feaa95 100644
--- a/converter/ppm/ppmtogif.c
+++ b/converter/ppm/ppmtogif.c
@@ -1,101 +1,63 @@
-/* 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).
+
+   The only significant ways Pamtogif are not backward compatible with
+   old Ppmtogif are:
 
-/* 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.
+     - Pamtogif does not have a -alpha option.
+
+     - Pamtogif requires a user-specififed map file (-mapfile) to
+       match the input in depth.
 */
+#define _BSD_SOURCE   /* Make sure strdup() is in string.h */
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
+
 #include <assert.h>
 #include <string.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
+#include "pm_c_util.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 *inputFileName;  /* Name 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 +84,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");
 }
 
 
@@ -191,12 +153,12 @@ parseCommandLine(int argc, char ** argv,
         handleLatex2htmlHack();
 
     if (argc-1 == 0) 
-        cmdlineP->input_filespec = "-";
+        cmdlineP->inputFileName = "-";
     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];
+        cmdlineP->inputFileName = argv[1];
 
     if (cmdlineP->alpha_filespec && cmdlineP->transparent)
         pm_error("You cannot specify both -alpha and -transparent.");
@@ -204,1362 +166,257 @@ 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) {
+openPnmremapStream(const char * const inputFileName,
+                   const char * const mapFileName,
+                   bool         const verbose,
+                   FILE **      const pnmremapPipeP) {
 /*----------------------------------------------------------------------------
-   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.
+   Create a process to run the image in file inputFileName[] through
+   Pnmremap, remapping it to the colors in mapFileName[].  Have it
+   write its output to a pipe and return as *pnmremapPipeP the other
+   end of that pipe.
 -----------------------------------------------------------------------------*/
-    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];
-}
-
+    FILE * pnmremapPipe;
+    const char * pnmremapCommand;
 
+    assert(inputFileName != NULL);
+    assert(mapFileName != NULL);
 
-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 */
-};
+    asprintfN(&pnmremapCommand, "pnmremap -mapfile='%s' %s",
+              mapFileName, inputFileName);
 
+    if (verbose)
+        pm_message("Preprocessing Pamtogif input with shell command '%s'",
+                   pnmremapCommand);
 
+    pnmremapPipe = popen(pnmremapCommand, "r");
 
-static struct pixelCursor pixelCursor;
-    /* Current location in the input pixels.  */
-
+    if (pnmremapPipe == NULL)
+        pm_error("Shell command '%s', via popen(), to prepare the input "
+                 "for Pamtogif, failed.", pnmremapCommand);
+    else
+        *pnmremapPipeP = pnmremapPipe;
 
-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;
+    strfree(pnmremapCommand);
 }
 
 
 
-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;
+static const char *
+pamtogifCommand(const char *       const arg0,
+                struct cmdlineInfo const cmdline) {
 
-    int colorindex;
+    const char * const pamtogifName = "pamtogif";
 
-    if (alpha && alpha[y][x] < alphaThreshold)
-        colorindex = cmapP->transparent;
-    else {
-        int presortColorindex;
+    const char * retval;
 
-        presortColorindex = ppm_lookupcolor(cmapP->cht, &pixels[y][x]);
-        if (presortColorindex == -1)
-            presortColorindex = 
-                closestcolor(pixels[y][x], inputMaxval, cmapP);
-        colorindex = cmapP->perm[presortColorindex];
-    }
-    *retvalP = colorindex;
-}
+    const char * commandVerb;
+    const char * transparentOpt;
+    const char * commentOpt;
 
+    if (strchr(arg0, '/')) {
+        const char * const arg0DirName = dirname(arg0);
+        const char * progName;
 
+        struct stat statbuf;
 
-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;
-        }
-    }
-}
+        asprintfN(&progName, "%s/%s", arg0DirName, pamtogifName);
 
-
-
-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) {
+            commandVerb = strdup(pamtogifName);
 
-        const int length_this_segment = MIN(255, strlen(segment));
+        strfree(arg0DirName);
+    } else
+        commandVerb = strdup(pamtogifName);
 
-        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");
-}
-
-
-
-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];
-
-    if (codeBufferP->curBits > 0)
-        codeBufferP->curAccum |= ((long)code << codeBufferP->curBits);
+    if (cmdline.transparent)
+        asprintfN(&transparentOpt, "-transparent=%s", cmdline.transparent);
     else
-        codeBufferP->curAccum = code;
-
-    codeBufferP->curBits += codeBufferP->n_bits;
+        transparentOpt = strdup("");
 
-    while (codeBufferP->curBits >= 8) {
-        byteBuffer_out(codeBufferP->byteBufferP,
-                       codeBufferP->curAccum & 0xff);
-        codeBufferP->curAccum >>= 8;
-        codeBufferP->curBits -= 8;
-    }
-
-    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",
+              commandVerb,
+              cmdline.alphacolor,
+              cmdline.interlace ? "-interlace" : "",
+              cmdline.sort ? "-sort" : "",
+              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(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);
-}
+    unsigned int row;
+    struct pam outPam;
+    tuple * tuplerow;
 
+    tuplerow = pnm_allocpamrow(inPamP);
 
-
-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'.
-
-   Use the colormap 'cmapP' to generate the raster ('pixels' is 
-   composed of RGB samples; the GIF raster is colormap indices).
-
-   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;
-    }
-}
-
-
-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);
-}
-
-
-
-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 */
+        pnm_writepamrow(&outPam, tuplerow);
     }
+    pnm_freepamrow(tuplerow);
 }
 
 
 
 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 */
-
-    if (gWidth > 65535)
-        pm_error("Image width %u too large for GIF format.  (Max 65535)",
-                 gWidth);  
-    
-    if (gHeight > 65535)
-        pm_error("Image height %u too large for GIF format.  (Max 65535)",
-                 gHeight);  
-
-    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);
-
-    pm_close(ifP);
+    if (cmdline.mapfile)
+        openPnmremapStream(cmdline.inputFileName, cmdline.mapfile,
+                           cmdline.verbose, &ifP);
+    else
+        ifP = pm_openr(cmdline.inputFileName);
+        
+    command = pamtogifCommand(argv[0], cmdline);
 
-    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. */
+    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 fcc6053f..d296f498 100644
--- a/converter/ppm/ppmtoilbm.c
+++ b/converter/ppm/ppmtoilbm.c
@@ -439,14 +439,14 @@ compute_ham_cmap(cols, rows, maxval, maxcolors, colorsP, hbits)
                     tmp = hmap[i].b - b; dist += tmp * tmp;
 
                     if( dist <= maxdist ) {
-                        int sum = hmap[i].count + hmap[col].count;
-
-                        hmap[i].r = (hmap[i].r * hmap[i].count + 
-                                     r * hmap[col].count + sum/2)/sum;
-                        hmap[i].g = (hmap[i].g * hmap[i].count + 
-                                     g * hmap[col].count + sum/2)/sum;
-                        hmap[i].b = (hmap[i].b * hmap[i].count + 
-                                     b * hmap[col].count + sum/2)/sum;
+                        unsigned int sum = hmap[i].count + hmap[col].count;
+
+                        hmap[i].r = ROUNDDIV(hmap[i].r * hmap[i].count + 
+                                             r * hmap[col].count, sum);
+                        hmap[i].g = ROUNDDIV(hmap[i].g * hmap[i].count + 
+                                             g * hmap[col].count, sum);
+                        hmap[i].b = ROUNDDIV(hmap[i].b * hmap[i].count + 
+                                             b * hmap[col].count, sum);
                         hmap[i].count = sum;
 
                         hmap[col] = hmap[i];    /* temp store */
@@ -641,20 +641,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;
@@ -882,16 +871,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;
@@ -1020,16 +1001,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;
@@ -1167,18 +1140,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;
@@ -1789,12 +1752,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" );
@@ -1824,12 +1782,12 @@ static int *
 make_val_table(oldmaxval, newmaxval)
     int oldmaxval, newmaxval;
 {
-    int i;
-    int *table;
+    unsigned int i;
+    int * table;
 
     MALLOCARRAY_NOFAIL(table, oldmaxval + 1);
-    for(i = 0; i <= oldmaxval; i++ )
-        table[i] = (i * newmaxval + oldmaxval/2) / oldmaxval;
+    for (i = 0; i <= oldmaxval; ++i)
+        table[i] = ROUNDDIV(i * newmaxval, oldmaxval);
 
     return table;
 }
diff --git a/converter/ppm/ppmtoleaf.c b/converter/ppm/ppmtoleaf.c
index fa5fdaf5..dcff0985 100644
--- a/converter/ppm/ppmtoleaf.c
+++ b/converter/ppm/ppmtoleaf.c
@@ -1,4 +1,4 @@
-/* ppmtoleaf.c - read a portable pixmap and produce a ileaf img file
+/* ppmtoleaf.c - read a PPM and produce a ileaf img file
  *
  * Copyright (C) 1994 by Bill O'Donnell.
  *
@@ -15,57 +15,60 @@
  */
 
 #include <stdio.h>
+
 #include "ppm.h"
 
 #define MAXCOLORS 256
 
-pixel **pixels;
+pixel ** pixels;
 colorhash_table cht;
 
-int Red[MAXCOLORS], Green[MAXCOLORS], Blue[MAXCOLORS];
+static int Red[MAXCOLORS], Green[MAXCOLORS], Blue[MAXCOLORS];
 
 
 
 static int
-colorstobpp( colors )
-int colors;
-{
+colorstobpp(unsigned int const colors) {
+
     int bpp;
     
-    if ( colors <= 2 )
-	bpp = 1;
-    else if ( colors <= 256 )
-	bpp = 8;
+    if (colors <= 2)
+        bpp = 1;
+    else if (colors <= 256)
+        bpp = 8;
     else
-	bpp = 24;
+        bpp = 24;
+
     return bpp;
 }
 
 
 
 static int
-GetPixel( x, y )
-int x, y;
-{
+GetPixel(int const x,
+         int const y) {
+
     int color;
     
-    color = ppm_lookupcolor( cht, &pixels[y][x] );
+    color = ppm_lookupcolor(cht, &pixels[y][x]);
+    
     return color;
 }
 
 
 
-/* OK, this routine is not wicked efficient, but it is simple to follow
-   and it works. */
+
 static void
-leaf_writeimg(width, height, depth, ncolors, maxval)
-int width;
-int height;
-int depth;
-int ncolors;
-{
-    int i,row,col;
-    
+leaf_writeimg(unsigned int const width,
+              unsigned int const height,
+              unsigned int const depth,
+              unsigned int const ncolors,
+              pixval       const maxval) {
+
+    /* OK, this routine is not wicked efficient, but it is simple to follow
+       and it works.
+    */
+
     /* NOTE: byte order in ileaf img file fmt is big-endian, always! */
     
     /* magic */
@@ -115,136 +118,142 @@ int ncolors;
     
     /* format, mono/gray = 0x20000000, RGB=0x29000000 */
     if (depth == 1)
-	fputc(0x20, stdout);
+        fputc(0x20, stdout);
     else
-	fputc(0x29, stdout);
+        fputc(0x29, stdout);
+
     fputc(0x00, stdout);
     fputc(0x00, stdout);
     fputc(0x00, stdout);
     
     /* colormap size */
-    if (depth == 8)
-    {
-	fputc((unsigned char)((ncolors >> 8) & 0x00ff), stdout);
-	fputc((unsigned char)(ncolors  & 0x00ff), stdout);
-	for (i=0; i<256; i++)
-	    fputc((unsigned char) Red[i]*255/maxval, stdout);
-	for (i=0; i<256; i++)
-	    fputc((unsigned char) Green[i]*255/maxval, stdout);
-	for (i=0; i<256; i++)
-	    fputc((unsigned char) Blue[i]*255/maxval, stdout);
-	
-	for (row=0; row<height; row++) 
-	{
-	    for (col=0; col<width; col++) 
-		fputc(GetPixel(col, row), stdout);
-	    if (width % 2)
-		fputc(0x00, stdout); /* pad to 2-bytes */
-	}
+    if (depth == 8) {
+        unsigned int i;
+        unsigned int row;
+
+        fputc((unsigned char)((ncolors >> 8) & 0x00ff), stdout);
+        fputc((unsigned char)(ncolors  & 0x00ff), stdout);
+        for (i = 0; i < 256; ++i)
+            fputc((unsigned char) Red[i]*255/maxval, stdout);
+        for (i=0; i < 256; ++i)
+            fputc((unsigned char) Green[i]*255/maxval, stdout);
+        for (i = 0; i < 256; ++i)
+            fputc((unsigned char) Blue[i]*255/maxval, stdout);
+    
+        for (row=0; row < height; ++row) {
+            unsigned int col;
+            for (col = 0; col < width; ++col) 
+                fputc(GetPixel(col, row), stdout);
+            if ((width % 2) != 0)
+                fputc(0x00, stdout); /* pad to 2-bytes */
+        }
     } else if (depth == 1) {
-	/* mono image */
-	/* no colormap */
-	fputc(0x00, stdout);
-	fputc(0x00, stdout);
-
-	for (row=0; row<height; row++) 
-	{
-	    unsigned char bits = 0;
-	    for (col=0; col<width; col++) {
-		if (GetPixel(col,row))
-		    bits |= (unsigned char) (0x0080 >> (col % 8));
-		if (((col + 1) % 8) == 0)  {
-		    fputc(bits, stdout);
-		    bits = 0;
-		}
-	    }
-	    if ((width % 8) != 0)
-		fputc(bits, stdout);
-	    if ((width % 16) && (width % 16) <= 8)
-		fputc(0x00, stdout);  /* 16 bit pad */
-	}
+        /* mono image */
+        /* no colormap */
+
+        unsigned int row;
+
+        fputc(0x00, stdout);
+        fputc(0x00, stdout);
+
+        for (row = 0; row < height; ++row) {
+            unsigned char bits;
+            unsigned int col;
+            bits = 0;
+            for (col = 0; col < width; ++col) {
+                if (GetPixel(col,row))
+                    bits |= (unsigned char) (0x0080 >> (col % 8));
+                if (((col + 1) % 8) == 0)  {
+                    fputc(bits, stdout);
+                    bits = 0;
+                }
+            }
+            if ((width % 8) != 0)
+                fputc(bits, stdout);
+            if ((width % 16) && (width % 16) <= 8)
+                fputc(0x00, stdout);  /* 16 bit pad */
+        }
     } else {
-	/* no colormap, direct or true color (24 bit) image */
-	fputc(0x00, stdout);
-	fputc(0x00, stdout);
-	
-	for (row=0; row<height; row++) 
-	{
-	    for (col=0; col<width; col++) 
-		fputc(pixels[row][col].r * 255 / maxval, stdout);
-	    if (width % 2)
-		fputc(0x00, stdout); /* pad to 2-bytes */
-	    for (col=0; col<width; col++) 
-		fputc(pixels[row][col].g * 255 / maxval, stdout);
-	    if (width % 2)
-		fputc(0x00, stdout); /* pad to 2-bytes */
-	    for (col=0; col<width; col++) 
-		fputc(pixels[row][col].b * 255 / maxval, stdout);
-	    if (width % 2)
-		fputc(0x00, stdout); /* pad to 2-bytes */
-	}
+        /* no colormap, direct or true color (24 bit) image */
+
+        unsigned int row;
+
+        fputc(0x00, stdout);
+        fputc(0x00, stdout);
+        
+        for (row = 0; row < height; ++row) {
+            unsigned int col;
+            for (col = 0; col < width; ++col) 
+                fputc(pixels[row][col].r * 255 / maxval, stdout);
+            if (width % 2 != 0)
+                fputc(0x00, stdout); /* pad to 2-bytes */
+            for (col = 0; col < width; ++col) 
+                fputc(pixels[row][col].g * 255 / maxval, stdout);
+            if (width % 2 != 0)
+                fputc(0x00, stdout); /* pad to 2-bytes */
+            for (col = 0; col < width; ++col) 
+                fputc(pixels[row][col].b * 255 / maxval, stdout);
+            if (width % 2 != 0)
+                fputc(0x00, stdout); /* pad to 2-bytes */
+        }
     }
 }
 
 
 
 int
-main( argc, argv )
-int argc;
-char *argv[];
-{
-    FILE *ifd;
-    int argn, rows, cols, colors, i, BitsPerPixel;
+main(int argc, const char * argv[]) {
+
+    FILE * ifP;
+    int argn;
+    int rows, cols;
+    unsigned int BitsPerPixel;
+    int colors;
     pixval maxval;
     colorhist_vector chv;
     const char * const usage = "[ppmfile]";
     
-    ppm_init(&argc, argv);
+    pm_proginit(&argc, argv);
     
     argn = 1;
     
-    if ( argn < argc )
-    {
-	ifd = pm_openr( argv[argn] );
-	argn++;
+    if (argn < argc) {
+        ifP = pm_openr(argv[argn]);
+        argn++;
     } else
-	ifd = stdin;
+        ifP = stdin;
     
-    if ( argn != argc )
-	pm_usage( usage );
+    if (argn != argc)
+        pm_usage(usage);
     
-    pixels = ppm_readppm( ifd, &cols, &rows, &maxval );
+    pixels = ppm_readppm(ifP, &cols, &rows, &maxval);
     
-    pm_close( ifd );
+    pm_close(ifP);
     
     /* Figure out the colormap. */
-    fprintf( stderr, "(Computing colormap..." );
-    fflush( stderr );
-    chv = ppm_computecolorhist( pixels, cols, rows, MAXCOLORS, &colors );
-    if ( chv != (colorhist_vector) 0 )
-    {
-	fprintf( stderr, "  Done.  %d colors found.)\n", colors );
-	
-	for ( i = 0; i < colors; i++ )
-	{
-	    Red[i] = (int) PPM_GETR( chv[i].color );
-	    Green[i] = (int) PPM_GETG( chv[i].color );
-	    Blue[i] = (int) PPM_GETB( chv[i].color );
-	}
-	BitsPerPixel = colorstobpp( colors );
-	
-	/* And make a hash table for fast lookup. */
-	cht = ppm_colorhisttocolorhash( chv, colors );
-	ppm_freecolorhist( chv );
+    pm_message("Computing colormap...");
+    chv = ppm_computecolorhist(pixels, cols, rows, MAXCOLORS, &colors);
+    if (chv) {
+        unsigned int i;
+
+        pm_message("... Done.  %u colors found.", colors);
+    
+        for (i = 0; i < colors; ++i) {
+            Red[i]   = (int) PPM_GETR( chv[i].color);
+            Green[i] = (int) PPM_GETG( chv[i].color);
+            Blue[i]  = (int) PPM_GETB( chv[i].color);
+        }
+        BitsPerPixel = colorstobpp(colors);
+    
+        /* And make a hash table for fast lookup. */
+        cht = ppm_colorhisttocolorhash(chv, colors);
+        ppm_freecolorhist(chv);
     } else {
-	BitsPerPixel = 24;
-	fprintf( stderr, "  Done.  24-bit true color %d color image.)\n", colors );
+        BitsPerPixel = 24;
+        pm_message("  ... Done.  24-bit true color %u color image.", colors);
     }
     
     leaf_writeimg(cols, rows, BitsPerPixel, colors, maxval);
     
-    return( 0 );
+    return 0;
 }
-
-
-
diff --git a/converter/ppm/ppmtomitsu.c b/converter/ppm/ppmtomitsu.c
index 3934ae45..e59f09b3 100644
--- a/converter/ppm/ppmtomitsu.c
+++ b/converter/ppm/ppmtomitsu.c
@@ -1,10 +1,10 @@
-/* ppmtomitsu.c - read a portable pixmap and produce output for the
+/* ppmtomitsu.c - read a PPM image and produce output for the
 **                Mitsubishi S340-10 Thermo-Sublimation Printer
 **                (or the S3410-30 parallel interface)
 **
 ** Copyright (C) 1992,93 by S.Petra Zeidler
 ** Minor modifications by Ingo Wilken:
-x**  - mymalloc() and check_and_rotate() functions for often used
+**  - mymalloc() and check_and_rotate() functions for often used
 **    code fragments.  Reduces code size by a few KB.
 **  - use pm_error() instead of fprintf(stderr)
 **  - localized allocation of colorhastable
@@ -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,458 @@ static int frametransferinit(cols, rows, sharpness, enlarge, copy, medias)
         SHARPNESS(SP_USER);
     }
     check_and_rotate(cols, rows, enlarge, medias);
-    return;
 }
 
 
-#ifdef __STDC__
+
 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;
-    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);
+doLookupTableColors(colorhist_vector const table,
+                    unsigned int     const nColor,
+                    hashinfo *       const colorhashtable) {
+                
+    unsigned int colval;
+    for (colval = 0; colval < nColor; ++colval) {
+        struct hashinfo * const hashchain =
+            &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;
         }
-        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 = %d x %d", medias.maxrows, medias.maxcols);
+}
+
+
+
+static void
+doLookupTableGrays(colorhist_vector const table,
+                   unsigned int     const nColor,
+                   hashinfo *       const colorhashtable) {
+
+    unsigned int colval;
+    for (colval = 0; colval < nColor; ++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;
         }
-        HPIXELS(cols);
-        VPIXELS(rows);
-        HPIXELSOFF((medias.maxcols/enlarge - cols)/2);
-        VPIXELSOFF((medias.maxrows/enlarge - rows)/2);
     }
 }
 
+
+
+static void
+generateLookupTable(colorhist_vector const table,
+                    unsigned int     const nColor,
+                    unsigned int     const cols,
+                    unsigned int     const rows,
+                    int              const format,
+                    int              const sharpness,
+                    int              const enlarge,
+                    int              const copy,
+                    struct mediasize const medias,
+                    hashinfo **      const colorhashtableP) {
+/*----------------------------------------------------------------------------
+   Write to the output file the palette (color lookup table) indicated by
+   'table' and generate a hash table to use with it: *colorhashtableP.
+
+   Also write the various properties 'sharpness', 'enlarge', 'copy', and
+   'medias' to the output file.
+-----------------------------------------------------------------------------*/
+    hashinfo * colorhashtable;
+
+    lookuptableinit(sharpness, enlarge, copy, medias);
+
+    /* Initialize the hash table to empty */
+
+    MALLOCARRAY_NOFAIL(colorhashtable, HASHSIZE);
+    {
+        unsigned int i;
+        for (i = 0; i < HASHSIZE; ++i) {
+            colorhashtable[i].flag = -1;
+                    colorhashtable[i].next = NULL;
+        }
+    }
+
+    switch(PPM_FORMAT_TYPE(format)) {
+    case PPM_TYPE:
+        doLookupTableColors(table, nColor, colorhashtable);
+        break;
+    default:
+        doLookupTableGrays(table, nColor, colorhashtable);
+    }
+    lookuptabledata(cols, rows, enlarge, medias);
+
+    *colorhashtableP = colorhashtable;
+}
+
+
+
+static void
+writeColormapRaster(pixel **         const pixels,
+                    unsigned int     const cols,
+                    unsigned int     const rows,
+                    hashinfo *       const colorhashtable) {
+/*----------------------------------------------------------------------------
+   Write a colormapped raster: write the pixels pixels[][] (dimensions cols x
+   rows) as indices into the colormap (palette; lookup table) indicated by
+   'colorhashtable'.
+-----------------------------------------------------------------------------*/
+    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);
+        }
+    }
+}
+
+
+
+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 nColor) {
+
+    hashinfo * colorhashtable;
+
+    pm_message("found %u colors - using the lookuptable-method", nColor);
+
+    generateLookupTable(table, nColor, cols, rows, format,
+                        sharpness, enlarge, copy, medias,
+                        &colorhashtable);
+
+    writeColormapRaster(pixels, cols, rows, colorhashtable);
+
+    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;
+    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;
+    }
+
+    ppm_readppminit(ifP, &cols, &rows, &maxval, &format);
+    
+    if (tiny) {
+        doTiny(ifP, cols, rows, maxval, format,
+               sharpness, enlarge, copy, medias);
+
+    } else {
+        pixel ** pixels;
+        int nColor;
+        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, 
+                                     &nColor);
+        if (table)
+            useLookupTable(pixels, table, sharpness, enlarge, copy, medias,
+                           cols, rows, format, nColor);
+        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..f574d927
--- /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 3201293405 310
+./ppmtomitsu ../../testgrid.pbm | cksum 
+echo Test 4.  Should print 3354679572 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 4e0ad8d6..a1004fdd 100644
--- a/converter/ppm/ppmtompeg/Makefile
+++ b/converter/ppm/ppmtompeg/Makefile
@@ -5,7 +5,7 @@ endif
 SUBDIR = converter/ppm/ppmtompeg
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
 ifeq ($(JPEGLIB),NONE)
   # 'nojpeg' is a module that implements all the jpeg access routines as
@@ -18,11 +18,12 @@ else
   JPEGLIBX = $(JPEGLIB)
 endif
 
-INCLUDES = -I$(SRCDIR)/$(SUBDIR)/headers 
+COMP_INCLUDES = -I$(SRCDIR)/$(SUBDIR)/headers 
 
+EXTERN_INCLUDES =
 ifneq ($(JPEGHDR_DIR),NONE)
   ifneq ($(JPEGHDR_DIR)x,x)
-    INCLUDES += -I$(JPEGHDR_DIR)
+    EXTERN_INCLUDES += -I$(JPEGHDR_DIR)
   endif
 endif
 
@@ -38,17 +39,31 @@ 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
+	specifics.o rate.o opts.o input.o
 ifeq ($(OMIT_NETWORK),y)
-  MP_PARALLEL_OBJS = noparallel.o
+  MP_OTHER_OBJS += noparallel.o
+else
+  MP_OTHER_OBJS += parallel.o psocket.o
+endif
+ifeq ($(MSVCRT),Y)
+  MP_OTHER_OBJS += gethostname_win32.o
 else
-  MP_PARALLEL_OBJS = parallel.o psocket.o
+  MP_OTHER_OBJS += gethostname.o
 endif
+
 NONMAIN_OBJS = $(MP_BASE_OBJS) $(MP_OTHER_OBJS) $(MP_ENCODE_OBJS) \
-	      $(MP_PARALLEL_OBJS) $(JPEG_MODULE).o
+	      	$(JPEG_MODULE).o
 OBJECTS = ppmtompeg.o $(NONMAIN_OBJS)
 MERGE_OBJECTS = ppmtompeg.o2 $(NONMAIN_OBJS)
 MP_INCLUDE = mproto.h mtypes.h huff.h bitio.h
@@ -61,7 +76,7 @@ SCRIPTS =
 .PHONY: all
 all: ppmtompeg
 
-include $(SRCDIR)/Makefile.common
+include $(SRCDIR)/common.mk
 
 ifeq ($(NEED_RUNTIME_PATH),Y)
   LIBOPTR = -runtime
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/combine.c b/converter/ppm/ppmtompeg/combine.c
index 52cc646d..8e0d3281 100644
--- a/converter/ppm/ppmtompeg/combine.c
+++ b/converter/ppm/ppmtompeg/combine.c
@@ -35,8 +35,8 @@
 #include <errno.h>
 #include <unistd.h>
 
-#include "ppm.h"
 #include "nstring.h"
+#include "nsleep.h"
 
 #include "mtypes.h"
 #include "frames.h"
@@ -111,11 +111,9 @@ appendSpecifiedGopFiles(struct inputSource * const inputSourceP,
              ++nAttempts) {
 
             ifP = fopen(fileName, "rb");
-            if (ifP == NULL) {
+            if (ifP == NULL)
                 pm_message("ERROR:  Couldn't read file '%s'.  retry %u", 
                            fileName, nAttempts);
-                sleep(1);
-            }
         }
         if (ifP) {
             if (!realQuiet)
diff --git a/converter/ppm/ppmtompeg/file.c b/converter/ppm/ppmtompeg/file.c
index ae741962..223170a4 100644
--- a/converter/ppm/ppmtompeg/file.c
+++ b/converter/ppm/ppmtompeg/file.c
@@ -19,17 +19,6 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  */
 
-/*  
- *  $Header: /n/picasso/project/mm/mpeg/mpeg_dist/mpeg_encode/RCS/file.c,v 1.2 1993/06/30 20:06:09 keving Exp $
- *  $Log: file.c,v $
- * Revision 1.2  1993/06/30  20:06:09  keving
- * nothing
- *
- * Revision 1.1  1993/06/03  21:08:08  keving
- * nothing
- *
- */
-
 #include "tk.h"
 
 #include "all.h"
@@ -40,11 +29,10 @@
 #include <time.h>
 #include <string.h>
 #include <dirent.h>
-#include <strings.h>
 
 #define MAX_FILES   1000
-#define MAX_NAME_LEN	256
-#define MAX_STRING_LEN	MAX_NAME_LEN
+#define MAX_NAME_LEN    256
+#define MAX_STRING_LEN  MAX_NAME_LEN
 
 typedef int boolean;
 #define TRUE 1
@@ -52,77 +40,76 @@ typedef int boolean;
 
 extern char currentPath[MAXPATHLEN];
 
-char	globString[1024];
+char globString[1024];
 
-static DIR *dfd;
+static DIR * dfd;
 
-void	ResetPath(void);
+void ResetPath(void);
 int ListDirectory(ClientData nulldata, Tcl_Interp *interp, int argc,
-		  char **argv);
+                  char **argv);
 int ChangeDirectory(ClientData nulldata, Tcl_Interp *interp, int argc,
-		  char **argv);
-void	SortFiles(int numStrings, char strings[MAX_FILES][MAX_NAME_LEN],
-		  boolean *dirList, int permute[]);
+                    char **argv);
+void SortFiles(int numStrings, char strings[MAX_FILES][MAX_NAME_LEN],
+               boolean *dirList, int permute[]);
+
+static void UpdatePath(Tcl_Interp *interp, char *directory);
+static boolean MatchesGlob(char *string, char *glob);
 
-static void	UpdatePath(Tcl_Interp *interp, char *directory);
-static boolean	MatchesGlob(char *string, char *glob);
 
 
+void
+ResetPath() {
 
-void	ResetPath()
-{
-    if ( getwd(currentPath) == 0 )
-    {
-	fprintf(stderr, "Error getting pathname!!!\n");
-	exit(1);
+    if (getwd(currentPath) == 0) {
+        fprintf(stderr, "Error getting pathname!!!\n");
+        exit(1);
     }
 
     strcpy(&currentPath[strlen(currentPath)], "/");
 
     dfd = opendir(currentPath);
-    if ( dfd == NULL )
-    {
-	fprintf(stderr, "can't open '%s'\n", currentPath);
-	exit(1);
+    if (dfd == NULL) {
+        fprintf(stderr, "can't open '%s'\n", currentPath);
+        exit(1);
     }
 }
 
 
-static void	UpdatePath(Tcl_Interp *interp, char *directory)
-{
+
+static void
+UpdatePath(Tcl_Interp *interp, char *directory) {
+
     int length;
     char *charPtr;
 
     length = strlen(currentPath);
 
-    if ( strcmp(directory, "./") == 0 )
-	return /* nothing */ ;
-    else if ( strcmp(directory, "../") == 0 )
-    {
-	/* delete backwards up to '/' */
-
-	if ( length < 2 )
-	{
-	    fprintf(stderr, "Error:  backing up from root directory!!!\n");
-	    exit(1);
-	}
-
-	charPtr = &currentPath[length-2];
-	while ( (charPtr != currentPath) && (*charPtr != '/') )
-	    charPtr--;
-	charPtr++;	/* leave the '/' */
-	*charPtr = '\0';
-    }
-    else
-    {
-	strcpy(&currentPath[length], directory);
+    if (streq(directory, "./"))
+        return /* nothing */ ;
+    else if (streq(directory, "../")) {
+        /* delete backwards up to '/' */
+
+        if (length < 2) {
+            fprintf(stderr, "Error:  backing up from root directory!!!\n");
+            exit(1);
+        }
+
+        charPtr = &currentPath[length-2];
+        while ((charPtr != currentPath) && (*charPtr != '/'))
+            --charPtr;
+        ++charPtr;  /* leave the '/' */
+        *charPtr = '\0';
+    } else {
+        strcpy(&currentPath[length], directory);
     }
 }
 
 
-int ChangeDirectory(ClientData nulldata, Tcl_Interp *interp, int argc,
-		  char **argv)
-{
+
+int
+ChangeDirectory(ClientData nulldata, Tcl_Interp *interp, int argc,
+                char **argv) {
+
     char *directory = argv[1];
 
     UpdatePath(interp, directory);
@@ -130,82 +117,74 @@ int ChangeDirectory(ClientData nulldata, Tcl_Interp *interp, int argc,
     fprintf(stdout, "Opening directory: '%s'\n", currentPath);
 
     dfd = opendir(currentPath);
-    if ( dfd == NULL )
-    {
-	fprintf(stderr, "can't open '%s'\n", currentPath);
-	return TCL_OK;	/* shouldn't, really */
+    if (dfd == NULL) {
+        fprintf(stderr, "can't open '%s'\n", currentPath);
+        return TCL_OK;  /* shouldn't, really */
     }
-
+    
     return TCL_OK;
 }
 
 
-int ListDirectory(ClientData nulldata, Tcl_Interp *interp, int argc,
-		  char **argv)
-{
-    struct dirent *dp;
+
+int
+ListDirectory(ClientData nulldata, Tcl_Interp *interp, int argc,
+              char **argv) {
+
+    struct dirent * dp;
     struct stat stbuf;
     char command[256];
     char fileName[MAX_FILES][MAX_NAME_LEN];
     boolean dirList[MAX_FILES];
     int permute[MAX_FILES];
-    int	fileCount = 0;
-    register int index;
+    int fileCount = 0;
+    int index;
     char fullName[MAXPATHLEN];
-    char    *restPtr;
+    char * restPtr;
 
     sprintf(command, "ShowCurrentDirectory %s", currentPath);
     Tcl_Eval(interp, command, 0, (char **) NULL);
 
-    if ( dfd == NULL )
-    {
-	fprintf(stderr, "TRIED TO LIST NULL DIRECTORY\n");
+    if (dfd == NULL) {
+        fprintf(stderr, "TRIED TO LIST NULL DIRECTORY\n");
 
-	return TCL_OK;
+        return TCL_OK;
     }
 
-/* check if root directory */
-    if ( strlen(currentPath) != 1 )
-    {
-	sprintf(fileName[fileCount], "../");
-	dirList[fileCount] = TRUE;
-	fileCount++;
+    /* check if root directory */
+    if (strlen(currentPath) != 1) {
+        sprintf(fileName[fileCount], "../");
+        dirList[fileCount] = TRUE;
+        ++fileCount;
     }
 
     strcpy(fullName, currentPath);
     restPtr = &fullName[strlen(fullName)];
 
-    while ( (dp = readdir(dfd)) != NULL )
-    {
-	strcpy(restPtr, dp->d_name);
-	stat(fullName, &stbuf);
-
-	if ( dp->d_name[0] != '.' )
-	{
-	    if ( S_ISDIR(stbuf.st_mode) )
-	    {
-		sprintf(fileName[fileCount], "%s/", dp->d_name);
-		dirList[fileCount] = TRUE;
-		fileCount++;
-	    }
-	    else
-	    {
-		if ( MatchesGlob(dp->d_name, globString) )
-		{
-		    strcpy(fileName[fileCount], dp->d_name);
-		    dirList[fileCount] = FALSE;
-		    fileCount++;
-		}
-	    }
-	}
+    while ((dp = readdir(dfd)) != NULL) {
+        strcpy(restPtr, dp->d_name);
+        stat(fullName, &stbuf);
+        
+        if (dp->d_name[0] != '.') {
+            if (S_ISDIR(stbuf.st_mode)) {
+                sprintf(fileName[fileCount], "%s/", dp->d_name);
+                dirList[fileCount] = TRUE;
+                ++fileCount;
+            } else {
+                if (MatchesGlob(dp->d_name, globString)) {
+                    strcpy(fileName[fileCount], dp->d_name);
+                    dirList[fileCount] = FALSE;
+                    ++fileCount;
+                }
+            }
+        }
     }
 
     SortFiles(fileCount, fileName, dirList, permute);
 
-    for ( index = 0; index < fileCount; index++ )
-    {
-	sprintf(command, "AddBrowseFile %s", fileName[permute[index]]);
-	Tcl_Eval(interp, command, 0, (char **) NULL);
+    for (index = 0; index < fileCount; ++index) {
+        sprintf(command, "AddBrowseFile %s", fileName[permute[index]]);
+        Tcl_Eval(interp, command, 0, (char **) NULL);
     }
 
     closedir(dfd);
@@ -214,108 +193,110 @@ int ListDirectory(ClientData nulldata, Tcl_Interp *interp, int argc,
 }
 
 
-void	SortFiles(int numStrings, char strings[MAX_FILES][MAX_NAME_LEN],
-		  boolean *dirList, int permute[])
-{
-    register int i, j;
-    int temp;
-    int	numDirs;
-    int	ptr;
 
-    for ( i = 0; i < numStrings; i++ )
-	permute[i] = i;
+void
+SortFiles(int numStrings, char strings[MAX_FILES][MAX_NAME_LEN],
+          boolean *dirList, int permute[]) {
+
+    int i;
+    int numDirs;
+    int ptr;
+
+    for (i = 0; i < numStrings; ++i)
+        permute[i] = i;
 
     /* put all directories at front */
     numDirs = 0;
     ptr = numStrings-1;
-    while ( numDirs != ptr )
-    {
-	/* go past dirs */
-	while ( (numDirs < ptr) && (dirList[permute[numDirs]]) )
-	    numDirs++;
-
-	/* go past non-dirs */
-	while ( (numDirs < ptr) && (! dirList[permute[ptr]]) )
-	    ptr--;
-
-	if ( numDirs != ptr )
-	{
-	    temp = permute[numDirs];
-	    permute[numDirs] = ptr;
-	    permute[ptr] = temp;
-	}
+    while (numDirs != ptr) {
+        /* go past dirs */
+        while ((numDirs < ptr) && (dirList[permute[numDirs]]))
+            ++numDirs;
+
+        /* go past non-dirs */
+        while ((numDirs < ptr) && (! dirList[permute[ptr]]))
+            --ptr;
+
+        if (numDirs != ptr) {
+            int const temp = permute[numDirs];
+            permute[numDirs] = ptr;
+            permute[ptr] = temp;
+        }
     }
 
-    if ( dirList[permute[numDirs]] )
-	numDirs++;
-
-    for ( i = 0; i < numDirs; i++ )
-	for ( j = i+1; j < numDirs; j++ )
-	{
-	    if ( strcmp(&strings[permute[j]][0], &strings[permute[i]][0]) < 0 )
-	    {
-		temp = permute[j];
-		permute[j] = permute[i];
-		permute[i] = temp;
-	    }
-	}
-
-    for ( i = numDirs; i < numStrings; i++ )
-	for ( j = i+1; j < numStrings; j++ )
-	{
-	    if ( strcmp(&strings[permute[j]][0], &strings[permute[i]][0]) < 0 )
-	    {
-		temp = permute[j];
-		permute[j] = permute[i];
-		permute[i] = temp;
-	    }
-	}
+    if (dirList[permute[numDirs]])
+        ++numDirs;
+
+    for (i = 0; i < numDirs; ++i) {
+        int j;
+        for (j = i + 1; j < numDirs; ++j) {
+            if (strcmp(&strings[permute[j]][0], &strings[permute[i]][0]) < 0) {
+                int const temp = permute[j];
+                permute[j] = permute[i];
+                permute[i] = temp;
+            }
+        }
+    }
+    for (i = numDirs; i < numStrings; ++i) {
+        int j;
+        for (j = i + 1; j < numStrings; ++j) {
+            if (strcmp(&strings[permute[j]][0], &strings[permute[i]][0]) < 0) {
+                int const temp = permute[j];
+                permute[j] = permute[i];
+                permute[i] = temp;
+            }
+        }
+    }
 }
 
 
-int SetBrowseGlob (ClientData nulldata, Tcl_Interp *interp,
-		   int argc, char **argv)
-{
-    if (argc == 2 )
-    {
-	strcpy(globString, argv[1]);
 
-	fprintf(stdout, "GLOB:  %s\n", globString);
+int
+SetBrowseGlob(ClientData nulldata, Tcl_Interp *interp,
+              int argc, char **argv) {
+
+    if (argc == 2) {
+        strcpy(globString, argv[1]);
+
+        fprintf(stdout, "GLOB:  %s\n", globString);
 
-	return TCL_OK;
+        return TCL_OK;
     }
 
-	Tcl_AppendResult (interp, 
-            "wrong args: should be \"", argv[0]," string\"", (char *) NULL);
-	return TCL_ERROR;
+    Tcl_AppendResult(interp, 
+                     "wrong args: should be \"", argv[0]," string\"",
+                     NULL);
+    return TCL_ERROR;
 }
 
 
-static boolean	MatchesGlob(char *string, char *glob)
-{
-    char    *stringRight, *globRight;
 
-    while ( (*glob != '\0') && (*glob != '*') )	    /* match left side */
-    {
-	if ( (*string == '\0') || (*string != *glob) )
-	    return FALSE;
-	string++;
-	glob++;
+static boolean
+MatchesGlob(char *string, char *glob) {
+
+    char * stringRight;
+    char * globRight;
+
+    while ((*glob != '\0') && (*glob != '*')) {
+        /* match left side */
+        if ((*string == '\0') || (*string != *glob))
+            return FALSE;
+        ++string;
+        ++glob;
     }
 
-    if ( *glob == '\0' )	/* no star */
-	return TRUE;
+    if (*glob == '\0')    /* no star */
+        return TRUE;
 
     /* now match right side */
     stringRight = &string[strlen(string)-1];
     globRight = &glob[strlen(glob)-1];
 
-    while ( *globRight != '*' )
-    {
-	if ( (stringRight < string) || (*stringRight != *globRight) )
-	    return FALSE;
-	globRight--;
-	stringRight--;
+    while (*globRight != '*') {
+        if ((stringRight < string) || (*stringRight != *globRight))
+            return FALSE;
+        --globRight;
+        --stringRight;
     }
 
     return TRUE;
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/gethostname_win32.c b/converter/ppm/ppmtompeg/gethostname_win32.c
new file mode 100644
index 00000000..383f4e55
--- /dev/null
+++ b/converter/ppm/ppmtompeg/gethostname_win32.c
@@ -0,0 +1,404 @@
+/* define this macro for activating debugging version */
+/* #define GETHOSTNAME_LOCAL_DEBUG     1*/
+
+#include <windows.h>
+#include <tchar.h>
+#include <stdarg.h>
+
+#ifndef GETHOSTNAME_LOCAL_DEBUG
+#include "pm.h"
+#include "gethostname.h"
+#endif
+
+#define BUFSIZE 80
+
+typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);
+typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD);
+
+typedef struct {
+    char  str[256];
+    int   level;
+} push_string_t;
+
+static void
+pushString(push_string_t *p, const char *fmt, ...)
+{
+    va_list args;
+
+    va_start(args, fmt);
+    p->level += _vsnprintf(p->str + p->level, sizeof(p->str)-p->level, fmt, args);
+    va_end(args);
+}
+
+#if _WIN32_WINNT < 0x0600
+/*
+ * Reference available here:
+ *
+ * GetProductInfo() Function
+ * http://msdn2.microsoft.com/en-us/library/ms724358.aspx
+ */
+#define PRODUCT_BUSINESS                        0x00000006  /* Business Edition */
+#define PRODUCT_BUSINESS_N                      0x00000010  /* Business Edition */
+#define PRODUCT_CLUSTER_SERVER                  0x00000012  /* Cluster Server Edition */
+#define PRODUCT_DATACENTER_SERVER               0x00000008  /* Server Datacenter Edition (full installation) */
+#define PRODUCT_DATACENTER_SERVER_CORE          0x0000000C  /* Server Datacenter Edition (core installation) */
+#define PRODUCT_ENTERPRISE                      0x00000004  /* Enterprise Edition */
+#define PRODUCT_ENTERPRISE_N                    0x0000001B  /* Enterprise Edition */
+#define PRODUCT_ENTERPRISE_SERVER               0x0000000A  /* Server Enterprise Edition (full installation) */
+#define PRODUCT_ENTERPRISE_SERVER_CORE          0x0000000E  /* Server Enterprise Edition (core installation) */
+#define PRODUCT_ENTERPRISE_SERVER_IA64          0x0000000F  /* Server Enterprise Edition for Itanium-based Systems */
+#define PRODUCT_HOME_BASIC                      0x00000002  /* Home Basic Edition */
+#define PRODUCT_HOME_BASIC_N                    0x00000005  /* Home Basic Edition */
+#define PRODUCT_HOME_PREMIUM                    0x00000003  /* Home Premium Edition */
+#define PRODUCT_HOME_PREMIUM_N                  0x0000001A  /* Home Premium Edition */
+#define PRODUCT_HOME_SERVER                     0x00000013  /* Home Server Edition */
+#define PRODUCT_SERVER_FOR_SMALLBUSINESS        0x00000018  /* Server for Small Business Edition */
+#define PRODUCT_SMALLBUSINESS_SERVER            0x00000009  /* Small Business Server */
+#define PRODUCT_SMALLBUSINESS_SERVER_PREMIUM    0x00000019  /* Small Business Server Premium Edition */
+#define PRODUCT_STANDARD_SERVER                 0x00000007  /* Server Standard Edition (full installation) */
+#define PRODUCT_STANDARD_SERVER_CORE            0x0000000D  /* Server Standard Edition (core installation) */
+#define PRODUCT_STARTER                         0x0000000B  /* Starter Edition */
+#define PRODUCT_STORAGE_ENTERPRISE_SERVER       0x00000017  /* Storage Server Enterprise Edition */
+#define PRODUCT_STORAGE_EXPRESS_SERVER          0x00000014  /* Storage Server Express Edition */
+#define PRODUCT_STORAGE_STANDARD_SERVER         0x00000015  /* Storage Server Standard Edition */
+#define PRODUCT_STORAGE_WORKGROUP_SERVER        0x00000016  /* Storage Server Workgroup Edition */
+#define PRODUCT_UNDEFINED                       0x00000000  /* An unknown product */
+#define PRODUCT_ULTIMATE                        0x00000001  /* Ultimate Edition */
+#define PRODUCT_ULTIMATE_N                      0x0000001C  /* Ultimate Edition */
+#define PRODUCT_WEB_SERVER                      0x00000011  /* Web Server Edition (full installation) */
+#define PRODUCT_WEB_SERVER_CORE                 0x0000001D  /* Web Server Edition (core installation) */
+#endif
+
+static BOOL
+get_string_version(push_string_t *str)
+{
+    OSVERSIONINFOEX osvi;
+    SYSTEM_INFO si;
+    PGPI pGPI;
+    PGNSI pGNSI;
+    BOOL bOsVersionInfoEx;
+    DWORD dwType;
+
+    ZeroMemory(&si, sizeof(SYSTEM_INFO));
+    ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
+
+    /*
+     * Try calling GetVersionEx using the OSVERSIONINFOEX structure.
+     * If that fails, try using the OSVERSIONINFO structure.
+     */
+    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+    if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) )
+    {
+        osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
+        if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) ) 
+            return FALSE;
+    }
+
+    /* Call GetNativeSystemInfo if supported or GetSystemInfo otherwise. */
+    pGNSI = (PGNSI)
+            GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), 
+            "GetNativeSystemInfo");
+    if (NULL != pGNSI)
+        pGNSI(&si);
+    else
+        GetSystemInfo(&si);
+
+    switch (osvi.dwPlatformId)
+    {
+    /* Test for the Windows NT product family. */
+    case VER_PLATFORM_WIN32_NT:
+        /* Test for the specific product. */
+        if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0)
+        {
+            if (osvi.wProductType == VER_NT_WORKSTATION)
+                pushString(str, "Windows Vista ");
+            else
+                pushString(str, "Windows Server 2008 ");
+
+            pGPI = (PGPI) GetProcAddress(
+                GetModuleHandle(TEXT("kernel32.dll")),
+                "GetProductInfo");
+
+            pGPI( 6, 0, 0, 0, &dwType);
+            switch (dwType)
+            {
+            case PRODUCT_ULTIMATE:
+                pushString(str, "Ultimate Edition");
+                break;
+            case PRODUCT_HOME_PREMIUM:
+                pushString(str, "Home Premium Edition");
+                break;
+            case PRODUCT_HOME_BASIC:
+                pushString(str, "Home Basic Edition");
+                break;
+            case PRODUCT_ENTERPRISE:
+                pushString(str, "Enterprise Edition");
+                break;
+            case PRODUCT_BUSINESS:
+                pushString(str, "Business Edition");
+                break;
+            case PRODUCT_STARTER:
+                pushString(str, "Starter Edition");
+                break;
+            case PRODUCT_CLUSTER_SERVER:
+                pushString(str, "Cluster Server Edition");
+                break;
+            case PRODUCT_DATACENTER_SERVER:
+                pushString(str, "Datacenter Edition");
+                break;
+            case PRODUCT_DATACENTER_SERVER_CORE:
+                pushString(str, "Datacenter Edition (core installation)");
+                break;
+            case PRODUCT_ENTERPRISE_SERVER:
+                pushString(str, "Enterprise Edition");
+                break;
+            case PRODUCT_ENTERPRISE_SERVER_CORE:
+                pushString(str, "Enterprise Edition (core installation)");
+                break;
+            case PRODUCT_ENTERPRISE_SERVER_IA64:
+                pushString(str, "Enterprise Edition for Itanium-based Systems");
+                break;
+            case PRODUCT_SMALLBUSINESS_SERVER:
+                pushString(str, "Small Business Server");
+                break;
+            case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:
+                pushString(str, "Small Business Server Premium Edition");
+                break;
+            case PRODUCT_STANDARD_SERVER:
+                pushString(str, "Standard Edition");
+                break;
+            case PRODUCT_STANDARD_SERVER_CORE:
+                pushString(str, "Standard Edition (core installation)");
+                break;
+            case PRODUCT_WEB_SERVER:
+                pushString(str, "Web Server Edition");
+                break;
+            }
+            if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64)
+                pushString(str,  ", 64-bit");
+            else
+            if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_INTEL)
+                pushString(str, ", 32-bit");
+            else
+                /* space for optional build number */
+                pushString(str, " ");
+        }
+        else
+        if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 )
+        {
+            if( GetSystemMetrics(SM_SERVERR2) )
+                pushString(str, "Microsoft Windows Server 2003 \"R2\" ");
+            else
+            if ( osvi.wSuiteMask==VER_SUITE_STORAGE_SERVER )
+                pushString(str, "Windows Storage Server 2003 ");
+            else
+            if( osvi.wProductType == VER_NT_WORKSTATION &&
+                si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64)
+                pushString(str, "Microsoft Windows XP Professional x64 Edition ");
+            else
+                pushString(str, "Microsoft Windows Server 2003, ");
+
+            /* Test for the server type. */
+            if ( osvi.wProductType != VER_NT_WORKSTATION )
+            {
+                switch (si.wProcessorArchitecture)
+                {
+                case PROCESSOR_ARCHITECTURE_IA64:
+                    if (osvi.wSuiteMask & VER_SUITE_DATACENTER)
+                       pushString(str, "Datacenter Edition for Itanium-based Systems ");
+                    else
+                    if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
+                       pushString(str, "Enterprise Edition for Itanium-based Systems ");
+                    break;
+
+                case PROCESSOR_ARCHITECTURE_AMD64:
+                    if (osvi.wSuiteMask & VER_SUITE_DATACENTER)
+                        pushString(str, "Datacenter x64 Edition ");
+                    else
+                    if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
+                        pushString(str, "Enterprise x64 Edition ");
+                    else
+                        pushString(str, "Standard x64 Edition ");
+                    break;
+
+                default:
+                    if ( osvi.wSuiteMask & VER_SUITE_COMPUTE_SERVER)
+                        pushString(str, "Compute Cluster Edition ");
+                    else
+                    if ( osvi.wSuiteMask & VER_SUITE_DATACENTER)
+                        pushString(str, "Datacenter Edition ");
+                    else
+                    if ( osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
+                        pushString(str, "Enterprise Edition ");
+                    else
+                    if ( osvi.wSuiteMask & VER_SUITE_BLADE)
+                        pushString(str, "Web Edition ");
+                    else
+                        pushString(str, "Standard Edition ");
+                    break;
+                }
+            }
+        }
+        else
+        if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 )
+        {
+            pushString(str, "Microsoft Windows XP ");
+            if( osvi.wSuiteMask & VER_SUITE_PERSONAL )
+                pushString(str, "Home Edition ");
+            else
+                pushString(str, "Professional ");
+        }
+        else
+        if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 )
+        {
+            pushString(str, "Microsoft Windows 2000 ");
+            if (osvi.wProductType == VER_NT_WORKSTATION)
+                pushString(str, "Professional ");
+            else 
+            if (osvi.wSuiteMask & VER_SUITE_DATACENTER)
+                pushString(str, "Datacenter Server ");
+            else
+            if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
+                pushString(str, "Advanced Server ");
+            else
+                pushString(str, "Server ");
+        } else
+        if ( osvi.dwMajorVersion <= 4 )
+            pushString(str, "Microsoft Windows NT ");
+
+        /* Test for specific product on Windows NT 4.0 SP6 and later. */
+        if (bOsVersionInfoEx)
+        {
+            /* Test for the workstation type. */
+            switch (osvi.wProductType)
+            {
+            case VER_NT_WORKSTATION:
+                if (si.wProcessorArchitecture!=PROCESSOR_ARCHITECTURE_AMD64 &&
+                    osvi.dwMajorVersion == 4)
+                    pushString(str, "Workstation 4.0 ");
+                break;
+
+            case VER_NT_SERVER:
+            case VER_NT_DOMAIN_CONTROLLER:
+                if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
+                    pushString(str, "Server 4.0, Enterprise Edition ");
+                else
+                    pushString(str, "Server 4.0 ");
+                break;
+            }
+        }
+        /* Test for specific product on Windows NT 4.0 SP5 and earlier */
+        else  
+        {
+            HKEY hKey;
+            TCHAR szProductType[BUFSIZE];
+            DWORD dwBufLen=BUFSIZE*sizeof(TCHAR);
+            LONG lRet;
+
+            lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+                TEXT("SYSTEM\\CurrentControlSet\\Control\\ProductOptions"),
+                0, KEY_QUERY_VALUE, &hKey);
+            if (lRet != ERROR_SUCCESS)
+                return FALSE;
+
+            lRet = RegQueryValueEx(hKey, TEXT("ProductType"), NULL, NULL,
+                (LPBYTE) szProductType, &dwBufLen);
+            RegCloseKey( hKey );
+
+            if ((lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE*sizeof(TCHAR)))
+                return FALSE;
+
+            if (lstrcmpi(TEXT("WINNT"), szProductType) == 0)
+                pushString(str, "Workstation ");
+            else
+            if (lstrcmpi(TEXT("LANMANNT"), szProductType) == 0)
+                pushString(str, "Server ");
+            else
+            if (lstrcmpi( TEXT("SERVERNT"), szProductType) == 0)
+                pushString(str, "Advanced Server ");
+            else
+                pushString(str, "%d.%d ", osvi.dwMajorVersion, osvi.dwMinorVersion);
+        }
+
+        /* Display service pack (if any) and build number. */
+        if (osvi.dwMajorVersion == 4 && 
+            lstrcmpi(osvi.szCSDVersion, TEXT("Service Pack 6")) == 0)
+        { 
+            HKEY hKey;
+            LONG lRet;
+
+            /* Test for SP6 versus SP6a. */
+            lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+                TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009"),
+                0, KEY_QUERY_VALUE, &hKey );
+            if( lRet == ERROR_SUCCESS )
+                pushString(str, "Service Pack 6a (Build %d)\n", osvi.dwBuildNumber & 0xFFFF );         
+            else
+                /* Windows NT 4.0 prior to SP6a */
+                pushString(str, "%s (Build %d)\n", osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF);
+
+             RegCloseKey( hKey );
+        }
+        else /* not Windows NT 4.0 */
+            pushString(str, "%s (Build %d)\n", osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF);
+
+        break;
+
+    /* Test for the Windows Me/98/95. */
+    case VER_PLATFORM_WIN32_WINDOWS:
+        if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
+        {
+            pushString(str, "Microsoft Windows 95");
+            if (osvi.szCSDVersion[1]=='C' || osvi.szCSDVersion[1]=='B')
+                pushString(str, " OSR2");
+        }
+        else
+        if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
+        {
+            pushString(str, "Microsoft Windows 98");
+            if (osvi.szCSDVersion[1]=='A' || osvi.szCSDVersion[1]=='B')
+                pushString(str, " SE");
+        } 
+        else
+        if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
+            pushString(str, "Microsoft Windows Millennium Edition\n");
+        break;
+
+    case VER_PLATFORM_WIN32s:
+        pushString(str, "Microsoft Win32s\n");
+        break;
+    }
+    return TRUE; 
+}
+
+const char *
+GetHostName(void)
+{
+/*----------------------------------------------------------------------------
+   Return the host name of this system.
+-----------------------------------------------------------------------------*/
+    push_string_t str;
+
+    ZeroMemory(&str, sizeof(str));
+    if (!get_string_version(&str)) {
+#ifndef GETHOSTNAME_LOCAL_DEBUG
+        pm_error("Unable to find out host name.");
+#endif
+        pushString(&str, "unknown");
+    }
+    return (const char *)_strdup(str.str);
+}
+
+#ifdef GETHOSTNAME_LOCAL_DEBUG
+int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst,
+                   LPSTR lpsCmdLine, int nCmdShow)
+{
+    char *hostName = (char *)GetHostName();
+
+    /* compile as ascii only (not UNICODE) */
+    MessageBox(NULL, hostName, TEXT("GetHostName"), MB_OK);
+    free(hostName);
+
+    return 0;
+}
+#endif
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/byteorder.h b/converter/ppm/ppmtompeg/headers/byteorder.h
index 0070252a..e2d8030c 100644
--- a/converter/ppm/ppmtompeg/headers/byteorder.h
+++ b/converter/ppm/ppmtompeg/headers/byteorder.h
@@ -72,6 +72,8 @@
 #else
     /* let in.h handle it, if possible */		   
 #include <sys/types.h>
+#if !defined(WIN32) || defined(__CYGWIN__)
 #include <netinet/in.h>
+#endif
 #endif /* FORCE_LITTLE_ENDIAN */
 #endif /* FORCE_BIG_ENDIAN */
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..f2bcf6ae 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 *
  *==================*/
@@ -399,7 +255,7 @@ extern int gopSize;
 extern int slicesPerFrame;
 extern int blocksPerSlice;
 extern int referenceFrame;
-extern int specificsOn;
+extern boolean specificsOn;
 extern int quietTime;       /* shut up for at least quietTime seconds;
                  * negative means shut up forever
                  */
@@ -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/param.h b/converter/ppm/ppmtompeg/headers/param.h
index 31be61ee..c7f57b44 100644
--- a/converter/ppm/ppmtompeg/headers/param.h
+++ b/converter/ppm/ppmtompeg/headers/param.h
@@ -1,30 +1,4 @@
-/*===========================================================================*
- * param.h								     *
- *									     *
- *	reading the parameter file					     *
- *									     *
- *===========================================================================*/
-
-/*
- * Copyright (c) 1995 The Regents of the University of California.
- * All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose, without fee, and without written agreement is
- * hereby granted, provided that the above copyright notice and the following
- * two paragraphs appear in all copies of this software.
- *
- * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
- * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
- * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- */
+/* COPYRIGHT information is at end of file */
 
 #include "pm_c_util.h"
 #include "ansi.h"
@@ -35,14 +9,21 @@
  * CONSTANTS *
  *===========*/
 
-#define MAX_MACHINES	    256
+#define MAX_MACHINES        256
 #ifndef MAXPATHLEN
 #define MAXPATHLEN  1024
 #endif
 
-#define	ENCODE_FRAMES	0
-#define COMBINE_GOPS	1
-#define COMBINE_FRAMES	2
+typedef enum {
+    ENCODE_FRAMES,
+        /* The regular, default function: Input is individual single unencoded
+           frames.
+        */
+    COMBINE_GOPS,
+        /* Input is pre-encoded GOPs */
+    COMBINE_FRAMES
+        /* Input is pre-encoded individual frames */
+} majorProgramFunction;
 
 
 struct params {
@@ -53,9 +34,9 @@ struct params {
 
 
 void
-ReadParamFile(const char *    const fileName, 
-              int             const function,
-              struct params * const paramP);
+ReadParamFile(const char *         const fileName, 
+              majorProgramFunction const function,
+              struct params *      const paramP);
 
 /*==================*
  * GLOBAL VARIABLES *
@@ -63,25 +44,47 @@ ReadParamFile(const char *    const fileName,
 
 /* All this stuff ought to be in a struct param instead */
 
-extern char	outputFileName[256];
-extern int	whichGOP;
+extern char outputFileName[256];
+extern int whichGOP;
 extern int numMachines;
-extern char	machineName[MAX_MACHINES][256];
-extern char	userName[MAX_MACHINES][256];
-extern char	executable[MAX_MACHINES][1024];
-extern char	remoteParamFile[MAX_MACHINES][1024];
-extern boolean	remote[MAX_MACHINES];
-extern char	currentPath[MAXPATHLEN];
-extern char	currentFramePath[MAXPATHLEN];
-extern char	currentGOPPath[MAXPATHLEN];
+extern char machineName[MAX_MACHINES][256];
+extern char userName[MAX_MACHINES][256];
+extern char executable[MAX_MACHINES][1024];
+extern char remoteParamFile[MAX_MACHINES][1024];
+extern boolean remote[MAX_MACHINES];
+extern char currentPath[MAXPATHLEN];
+extern char currentFramePath[MAXPATHLEN];
+extern char currentGOPPath[MAXPATHLEN];
 extern char inputConversion[1024];
 extern char yuvConversion[256];
-extern int  yuvWidth, yuvHeight;
-extern int  realWidth, realHeight;
+extern int yuvWidth, yuvHeight;
+extern int realWidth, realHeight;
 extern char ioConversion[1024];
 extern char slaveConversion[1024];
-extern FILE *bitRateFile;
+extern FILE * bitRateFile;
 extern boolean showBitRatePerFrame;
 extern boolean computeMVHist;
 extern const double VidRateNum[9];
 extern boolean keepTempFiles;
+
+
+/*
+ * Copyright (c) 1995 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
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/huff.h b/converter/ppm/ppmtompeg/huff.h
deleted file mode 100644
index 4d0b8840..00000000
--- a/converter/ppm/ppmtompeg/huff.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 1995 The Regents of the University of California.
- * All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose, without fee, and without written agreement is
- * hereby granted, provided that the above copyright notice and the following
- * two paragraphs appear in all copies of this software.
- *
- * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
- * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
- * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- */
-
-/*  
- *  $Header: /n/charlie-brown/project/mm/mpeg/mpeg_dist/mpeg_encode/RCS/huff.h,v 1.2 1995/01/19 23:08:28 eyhung Exp $
- */
-
-/*  
- *  THIS FILE IS MACHINE GENERATED!  DO NOT EDIT!
- */
-#define HUFF_MAXRUN	32
-#define HUFF_MAXLEVEL	41
-
-extern int huff_maxlevel[];
-extern uint32 *huff_table[];
-extern int *huff_bits[];
diff --git a/converter/ppm/ppmtompeg/iframe.c b/converter/ppm/ppmtompeg/iframe.c
index f4d7665a..7552f413 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                                                         *
  *                                       *
  *===========================================================================*/
 
@@ -43,11 +42,11 @@
  * HEADER FILES *
  *==============*/
 
+#include <time.h>  /* Defines CLOCKS_PER_SEC, if this system has clock() */
 
-#ifdef CLOCKS_PER_SEC
-#include <times.h>
-#else
-#include <sys/times.h>
+#ifndef CLOCKS_PER_SEC
+  /* System doesn't have clock(); we assume it has times() instead */
+  #include <sys/times.h>
 #endif
 
 #include <sys/types.h>
@@ -67,12 +66,14 @@
 #include "specifics.h"
 #include "opts.h"
 
+#include "iframe.h"
+
 /*==================*
  * STATIC VARIABLES *
  *==================*/
 
-static  int lastNumBits = 0;
-static  int lastIFrame = 0;
+static int lastNumBits = 0;
+static int lastIFrame = 0;
 static int numBlocks = 0;
 static int numBits;
 static int numFrames = 0;
@@ -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
@@ -994,69 +979,3 @@ int32 time_elapsed(void) {
     return timeBuffer.tms_utime + timeBuffer.tms_stime;
 #endif
 }
-
-
-
-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 b51cf083..a703cf39 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
@@ -52,6 +53,17 @@ extern void jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row,
 #define HEADER_SIZE 607   /*JFIF header size used on output images*/
 
 
+static int
+minDctVScaledSize(struct jpeg_decompress_struct const cinfo) {
+
+#if JPEG_LIB_VERSION >= 70
+    return cinfo.min_DCT_v_scaled_size;
+#else
+    return cinfo.min_DCT_scaled_size;
+#endif
+}
+
+
 
 /*=======================================================================*
  *                                                                       *
@@ -416,11 +428,7 @@ ReadJPEG(MpegFrame * const mf,
      */
   
     /* set parameters for decompression */
-#ifdef JPEG4
-    cinfo.want_raw_output = TRUE;
-#else
     cinfo.raw_data_out = TRUE;
-#endif
     cinfo.out_color_space = JCS_YCbCr;
   
     /* calculate image output dimensions */
@@ -466,13 +474,7 @@ ReadJPEG(MpegFrame * const mf,
     /* Make an 8-row-high sample array that will go away when done
        with image
     */
-#ifdef JPEG4
-    buffer_height = 8;  /* could be 2, 4,8 rows high */
-#elif JPEG_LIB_VERSION >= 70
-    buffer_height = cinfo.max_v_samp_factor * cinfo.min_DCT_v_scaled_size;
-#else
-    buffer_height = cinfo.max_v_samp_factor * cinfo.min_DCT_scaled_size;
-#endif
+    buffer_height = cinfo.max_v_samp_factor * minDctVScaledSize(cinfo);
   
     for(cp=0,compptr = cinfo.comp_info;cp<cinfo.num_components;
         cp++,compptr++) {
@@ -496,11 +498,7 @@ ReadJPEG(MpegFrame * const mf,
 
     while (cinfo.output_scanline < cinfo.output_height) {
 
-#ifdef JPEG4
-        (void) jpeg_read_raw_scanlines(&cinfo, scanarray, buffer_height);
-#else
         (void) jpeg_read_raw_data(&cinfo, scanarray, buffer_height);
-#endif
 
         /* alter subsample ratio's if neccessary */
         if ((h_samp[0]==2) && (h_samp[1]==1) && (h_samp[2]==1) &&
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..6557f377 100644
--- a/converter/ppm/ppmtompeg/mpeg.c
+++ b/converter/ppm/ppmtompeg/mpeg.c
@@ -43,8 +43,8 @@
 #endif
 #include <sys/stat.h>
 
-#include "ppm.h"
 #include "nstring.h"
+#include "nsleep.h"
 
 #include "mtypes.h"
 #include "frames.h"
@@ -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);
@@ -1662,7 +1680,7 @@ ReadDecodedRefFrame(MpegFrame *  const frameP,
     }
 
     if ((fpointer = fopen(fileName, "rb")) == NULL) {
-        sleep(1);
+        sleepN(1000);
         if ((fpointer = fopen(fileName, "rb")) == NULL) {
             fprintf(stderr, "Cannot open %s\n", fileName);
             exit(1);
diff --git a/converter/ppm/ppmtompeg/noparallel.c b/converter/ppm/ppmtompeg/noparallel.c
index b27934fb..6e6449a4 100644
--- a/converter/ppm/ppmtompeg/noparallel.c
+++ b/converter/ppm/ppmtompeg/noparallel.c
@@ -164,7 +164,7 @@ void
 CombineServer(int          const numFrames, 
               const char * const masterHostName, 
               int          const masterPortNum,
-              const char * const outputFileName) {
+              const char*  const outputFileName) {
 
     pm_error("This version of Ppmtompeg cannot run combine server because "
              "it does not have socket capability.");
diff --git a/converter/ppm/ppmtompeg/parallel.c b/converter/ppm/ppmtompeg/parallel.c
index 021e6d2b..e13bf221 100644
--- a/converter/ppm/ppmtompeg/parallel.c
+++ b/converter/ppm/ppmtompeg/parallel.c
@@ -41,6 +41,7 @@
 
 #include "mallocvar.h"
 #include "nstring.h"
+#include "nsleep.h"
 
 #include "pm.h"
 
@@ -128,7 +129,7 @@ boolean niceProcesses = FALSE;
 boolean forceIalign = FALSE;
 int     machineNumber = -1;
 boolean remoteIO = FALSE;
-bool separateConversion;
+boolean separateConversion;
     /* The I/O server will convert from the input format to the base format,
        and the slave will convert from the base format to the YUV internal
        format.  If false, the I/O server assumes the input format is the
@@ -630,7 +631,7 @@ static int safe_fork(command)       /* fork child process and remember its PID *
  *
  *===========================================================================*/
 void
-SetIOConvert(bool const separate) {
+SetIOConvert(boolean const separate) {
     separateConversion = separate;
 }
 
@@ -648,8 +649,7 @@ SetIOConvert(bool const separate) {
  *
  *===========================================================================*/
 void
-SetParallelPerfect(val)
-boolean val;
+SetParallelPerfect(boolean val)
 {
     parallelPerfect = val;
 }
@@ -1209,7 +1209,7 @@ openInputFile(const char * const fileName,
             pm_message("ERROR  Couldn't read frame file '%s' errno = %d (%s)"
                        "attempt %d", 
                        fileName, errno, strerror(errno), attempts);
-            sleep(1);
+            sleepN(1000);
         }
         ++attempts;
     }
diff --git a/converter/ppm/ppmtompeg/param.c b/converter/ppm/ppmtompeg/param.c
index 69e38a6c..a145d33c 100644
--- a/converter/ppm/ppmtompeg/param.c
+++ b/converter/ppm/ppmtompeg/param.c
@@ -665,66 +665,66 @@ processParamLine(char const input[],
 
     switch(input[0]) {
     case 'A':
-        if (STRNEQ(input, "ASPECT_RATIO", 12)) {
+        if (strneq(input, "ASPECT_RATIO", 12)) {
             aspectRatio = GetAspectRatio(SkipSpacesTabs(&input[12]));
             optionSeen[OPTION_ASPECT_RATIO] = TRUE;
         }
         break;
         
     case 'B':
-        if (STRNEQ(input, "BQSCALE", 7)) {
+        if (strneq(input, "BQSCALE", 7)) {
             SetBQScale(atoi(SkipSpacesTabs(&input[7])));
             optionSeen[OPTION_BQSCALE] = TRUE;
-        } else if (STRNEQ(input, "BASE_FILE_FORMAT", 16)) {
+        } else if (strneq(input, "BASE_FILE_FORMAT", 16)) {
             const char * arg = SkipSpacesTabs(&input[16]);
             SetFileFormat(arg);
-            if (STRNEQ(arg, "YUV", 3) || STREQ(arg, "Y"))
+            if (strneq(arg, "YUV", 3) || streq(arg, "Y"))
                 *yuvUsedP = TRUE;
             optionSeen[OPTION_BASE_FORMAT] = TRUE;
-        } else if (STRNEQ(input, "BSEARCH_ALG", 11)) {
+        } else if (strneq(input, "BSEARCH_ALG", 11)) {
             SetBSearchAlg(SkipSpacesTabs(&input[11]));
             optionSeen[OPTION_BSEARCH_ALG] = TRUE;
-        } else if (STRNEQ(input, "BIT_RATE", 8)) {
+        } else if (strneq(input, "BIT_RATE", 8)) {
             setBitRate(SkipSpacesTabs(&input[8]));
             optionSeen[OPTION_BIT_RATE] = TRUE;
-        } else if (STRNEQ(input, "BUFFER_SIZE", 11)) {
+        } else if (strneq(input, "BUFFER_SIZE", 11)) {
             setBufferSize(SkipSpacesTabs(&input[11]));
             optionSeen[OPTION_BUFFER_SIZE] = TRUE;                  
         }
         break;
 
     case 'C':
-        if (STRNEQ(input, "CDL_FILE", 8)) {
+        if (strneq(input, "CDL_FILE", 8)) {
             strcpy(specificsFile, SkipSpacesTabs(&input[8]));
             specificsOn = TRUE;
             optionSeen[OPTION_SPECIFICS] = TRUE;
-        } else if (STRNEQ(input, "CDL_DEFINES", 11)) {
+        } else if (strneq(input, "CDL_DEFINES", 11)) {
             strcpy(specificsDefines, SkipSpacesTabs(&input[11]));
             optionSeen[OPTION_DEFS_SPECIFICS] = TRUE;
         }
         break;
 
     case 'F':
-        if (STRNEQ(input, "FRAME_INPUT_DIR", 15)) {
+        if (strneq(input, "FRAME_INPUT_DIR", 15)) {
             const char * const arg = SkipSpacesTabs(&input[15]);
-            if (STRNCASEEQ(arg, "stdin", 5))
+            if (strncaseeq(arg, "stdin", 5))
                 SetStdinInput(frameInputSourceP);
 
             strcpy(currentFramePath, arg);
-        } else if (STRNEQ(input, "FRAME_INPUT", 11)) {
+        } else if (strneq(input, "FRAME_INPUT", 11)) {
             ReadInputFileNames(fpointer, "FRAME_END_INPUT", 
                                frameInputSourceP->stdinUsed ? 
                                NULL : frameInputSourceP);
             optionSeen[OPTION_FRAME_INPUT] = TRUE;
-        } else if (STRNEQ(input, "FORCE_I_ALIGN", 13)) {
+        } else if (strneq(input, "FORCE_I_ALIGN", 13)) {
             forceIalign = TRUE;
-        } else if (STRNEQ(input, "FORCE_ENCODE_LAST_FRAME", 23)) {
+        } else if (strneq(input, "FORCE_ENCODE_LAST_FRAME", 23)) {
             /* NO-OP.  We used to drop trailing B frames by default and you
                needed this option to change the last frame to I so you could
                encode all the frames.  Now we just do that all the time.  
                Why wouldn't we?
             */
-        } else if (STRNEQ(input, "FRAME_RATE", 10)) {
+        } else if (strneq(input, "FRAME_RATE", 10)) {
             frameRate = GetFrameRate(SkipSpacesTabs(&input[10]));
             frameRateRounded = (int) VidRateNum[frameRate];
             if ((frameRate % 3) == 1)
@@ -734,21 +734,21 @@ processParamLine(char const input[],
         break;
         
     case 'G':
-        if (STRNEQ(input, "GOP_SIZE", 8)) {
+        if (strneq(input, "GOP_SIZE", 8)) {
             SetGOPSize(atoi(SkipSpacesTabs(&input[8])));
             optionSeen[OPTION_GOP] = TRUE;
-        } else if (STRNEQ(input, "GOP_INPUT_DIR", 13)) {
+        } else if (strneq(input, "GOP_INPUT_DIR", 13)) {
             const char * const arg = SkipSpacesTabs(&input[13]);
-            if (STRNCASEEQ(arg, "stdin", 5))
+            if (strncaseeq(arg, "stdin", 5))
                 SetStdinInput(gopInputSourceP);
 
             strcpy(currentGOPPath, arg);
-        } else if (STRNEQ(input, "GOP_INPUT", 9)) {
+        } else if (strneq(input, "GOP_INPUT", 9)) {
             ReadInputFileNames(fpointer, "GOP_END_INPUT", 
                                gopInputSourceP->stdinUsed ? 
                                NULL : gopInputSourceP);
             optionSeen[OPTION_GOP_INPUT] = TRUE;
-        } else if (STRNEQ(input, "GAMMA", 5)) {
+        } else if (strneq(input, "GAMMA", 5)) {
             GammaCorrection = TRUE;
             sscanf(SkipSpacesTabs(&input[5]), "%f", &GammaValue);
             optionSeen[OPTION_GAMMA] = TRUE;
@@ -756,27 +756,27 @@ processParamLine(char const input[],
         break;
         
     case 'I':
-        if (STRNEQ(input, "IQSCALE", 7)) {
+        if (strneq(input, "IQSCALE", 7)) {
             SetIQScale(atoi(SkipSpacesTabs(&input[7])));
             optionSeen[OPTION_IQSCALE] = TRUE;
-        } else if (STRNEQ(input, "INPUT_DIR", 9)) {
+        } else if (strneq(input, "INPUT_DIR", 9)) {
             const char * const arg = SkipSpacesTabs(&input[9]);
-            if (STRNCASEEQ(arg, "stdin", 5))
+            if (strncaseeq(arg, "stdin", 5))
                 SetStdinInput(inputSourceP);
             strcpy(currentPath, arg);
             optionSeen[OPTION_INPUT_DIR] = TRUE;
-        } else if (STRNEQ(input, "INPUT_CONVERT", 13)) {
+        } else if (strneq(input, "INPUT_CONVERT", 13)) {
             strcpy(inputConversion, SkipSpacesTabs(&input[13]));
             optionSeen[OPTION_INPUT_CONVERT] = TRUE;
-        } else if (STREQ(input, "INPUT")) {
+        } else if (streq(input, "INPUT")) {
             ReadInputFileNames(fpointer, "END_INPUT", 
                                inputSourceP->stdinUsed ?
                                NULL : inputSourceP);
             optionSeen[OPTION_INPUT] = TRUE;
-        } else if (STRNEQ(input, "IO_SERVER_CONVERT", 17)) {
+        } else if (strneq(input, "IO_SERVER_CONVERT", 17)) {
             strcpy(ioConversion, SkipSpacesTabs(&input[17]));
             optionSeen[OPTION_IO_CONVERT] = TRUE;
-        } else if (STRNEQ(input, "IQTABLE", 7)) {
+        } else if (strneq(input, "IQTABLE", 7)) {
             processIqtable(fpointer);
 
             optionSeen[OPTION_IQTABLE] = TRUE;
@@ -784,12 +784,12 @@ processParamLine(char const input[],
         break;
 
     case 'K':
-        if (STRNEQ(input, "KEEP_TEMP_FILES", 15))
+        if (strneq(input, "KEEP_TEMP_FILES", 15))
             keepTempFiles = TRUE;
         break;
         
     case 'N':
-      if (STRNEQ(input, "NIQTABLE", 8)) {
+      if (strneq(input, "NIQTABLE", 8)) {
           readNiqTable(fpointer);
 
           optionSeen[OPTION_NIQTABLE] = TRUE;
@@ -797,7 +797,7 @@ processParamLine(char const input[],
       break;
 
     case 'O':
-        if (STRNEQ(input, "OUTPUT", 6)) {
+        if (strneq(input, "OUTPUT", 6)) {
             const char * const arg = SkipSpacesTabs(&input[6]);
             if ( whichGOP == -1 )
                 strcpy(outputFileName, arg);
@@ -809,45 +809,45 @@ processParamLine(char const input[],
         break;
         
     case 'P':
-        if (STRNEQ(input, "PATTERN", 7)) {
+        if (strneq(input, "PATTERN", 7)) {
             SetFramePattern(SkipSpacesTabs(&input[7]));
             optionSeen[OPTION_PATTERN] = TRUE;
-        } else if (STRNEQ(input, "PIXEL", 5)) {
+        } else if (strneq(input, "PIXEL", 5)) {
             SetPixelSearch(SkipSpacesTabs(&input[5]));
             optionSeen[OPTION_PIXEL] = TRUE;
-        } else if (STRNEQ(input, "PQSCALE", 7)) {
+        } else if (strneq(input, "PQSCALE", 7)) {
             SetPQScale(atoi(SkipSpacesTabs(&input[7])));
             optionSeen[OPTION_PQSCALE] = TRUE;
-        } else if (STRNEQ(input, "PSEARCH_ALG", 11)) {
+        } else if (strneq(input, "PSEARCH_ALG", 11)) {
             SetPSearchAlg(SkipSpacesTabs(&input[11]));
             optionSeen[OPTION_PSEARCH_ALG] = TRUE;
-        } else if (STRNEQ(input, "PARALLEL_TEST_FRAMES", 20)) {
+        } else if (strneq(input, "PARALLEL_TEST_FRAMES", 20)) {
             SetParallelPerfect(FALSE);
             parallelTestFrames = atoi(SkipSpacesTabs(&input[20]));
-        } else if (STRNEQ(input, "PARALLEL_TIME_CHUNKS", 20)) {
+        } else if (strneq(input, "PARALLEL_TIME_CHUNKS", 20)) {
             SetParallelPerfect(FALSE);
             parallelTimeChunks = atoi(SkipSpacesTabs(&input[20]));
-        } else if (STRNEQ(input, "PARALLEL_CHUNK_TAPER", 20)) {
+        } else if (strneq(input, "PARALLEL_CHUNK_TAPER", 20)) {
             SetParallelPerfect(FALSE);
             parallelTimeChunks = -1;
-        } else if (STRNEQ(input, "PARALLEL_PERFECT", 16)) {
+        } else if (strneq(input, "PARALLEL_PERFECT", 16)) {
             SetParallelPerfect(TRUE);
-        } else if (STRNEQ(input, "PARALLEL", 8)) {
+        } else if (strneq(input, "PARALLEL", 8)) {
             ReadMachineNames(fpointer);
             optionSeen[OPTION_PARALLEL] = TRUE;
         }
         break;
         
     case 'R':
-        if (STRNEQ(input, "RANGE", 5)) {
+        if (strneq(input, "RANGE", 5)) {
             processRanges(SkipSpacesTabs(&input[5]));
             optionSeen[OPTION_RANGE] = TRUE;
-        } else if (STRNEQ(input, "REFERENCE_FRAME", 15)) {
+        } else if (strneq(input, "REFERENCE_FRAME", 15)) {
             SetReferenceFrameType(SkipSpacesTabs(&input[15]));
             optionSeen[OPTION_REF_FRAME] = TRUE;
-        } else if (STRNEQ(input, "RSH", 3)) {
+        } else if (strneq(input, "RSH", 3)) {
             SetRemoteShell(SkipSpacesTabs(&input[3]));
-        } else if (STRNEQ(input, "RESIZE", 6)) {
+        } else if (strneq(input, "RESIZE", 6)) {
             const char * const arg = SkipSpacesTabs(&input[6]);
             sscanf(arg, "%dx%d", &outputWidth, &outputHeight);
             outputWidth &= ~(DCTSIZE * 2 - 1);
@@ -857,22 +857,22 @@ processParamLine(char const input[],
         break;
 
     case 'S':
-        if (STRNEQ(input, "SLICES_PER_FRAME", 16)) {
+        if (strneq(input, "SLICES_PER_FRAME", 16)) {
             SetSlicesPerFrame(atoi(SkipSpacesTabs(&input[16])));
             optionSeen[OPTION_SPF] = TRUE;
-        } else if (STRNEQ(input, "SLAVE_CONVERT", 13)) {
+        } else if (strneq(input, "SLAVE_CONVERT", 13)) {
             strcpy(slaveConversion, SkipSpacesTabs(&input[13]));
             optionSeen[OPTION_SLAVE_CONVERT] = TRUE;
-        } else if (STRNEQ(input, "SPECIFICS_FILE", 14)) {
+        } else if (strneq(input, "SPECIFICS_FILE", 14)) {
             strcpy(specificsFile, SkipSpacesTabs(&input[14]));
             specificsOn = TRUE;
             optionSeen[OPTION_SPECIFICS] = TRUE;
-        } else if (STRNEQ(input, "SPECIFICS_DEFINES", 16)) {
+        } else if (strneq(input, "SPECIFICS_DEFINES", 16)) {
             strcpy(specificsDefines, SkipSpacesTabs(&input[17]));
             optionSeen[OPTION_DEFS_SPECIFICS] = TRUE;
-        } else if (STRNEQ(input, "SEQUENCE_SIZE", 13)) {
+        } else if (strneq(input, "SEQUENCE_SIZE", 13)) {
             mult_seq_headers = atoi(SkipSpacesTabs(&input[13]));
-        } else if (STRNEQ(input, "SIZE", 4)) {
+        } else if (strneq(input, "SIZE", 4)) {
             const char * const arg = SkipSpacesTabs(&input[4]);
             sscanf(arg, "%dx%d", &yuvWidth, &yuvHeight);
             realWidth = yuvWidth;
@@ -883,42 +883,42 @@ processParamLine(char const input[],
         break;
 
     case 'T':
-        if (STRNEQ(input, "TUNE", 4)) {
+        if (strneq(input, "TUNE", 4)) {
             tuneingOn = TRUE;
             ParseTuneParam(SkipSpacesTabs(&input[4]));
         }
         break;
 
     case 'U':
-        if (STRNEQ(input, "USER_DATA", 9)) {
+        if (strneq(input, "USER_DATA", 9)) {
             strcpy(userDataFileName, SkipSpacesTabs(&input[9]));
             optionSeen[OPTION_USER_DATA] = TRUE;
         }
         break;
         
     case 'W':
-        if (STRNEQ(input, "WARN_UNDERFLOW", 14))
+        if (strneq(input, "WARN_UNDERFLOW", 14))
             paramP->warnUnderflow = TRUE;
-        if (STRNEQ(input, "WARN_OVERFLOW", 13))
+        if (strneq(input, "WARN_OVERFLOW", 13))
             paramP->warnOverflow = TRUE;
         break;
         
     case 'Y':
-        if (STRNEQ(input, "YUV_SIZE", 8)) {
+        if (strneq(input, "YUV_SIZE", 8)) {
             const char * const arg = SkipSpacesTabs(&input[8]);
             sscanf(arg, "%dx%d", &yuvWidth, &yuvHeight);
             realWidth = yuvWidth;
             realHeight = yuvHeight;
             Fsize_Validate(&yuvWidth, &yuvHeight);
             optionSeen[OPTION_YUV_SIZE] = TRUE;
-        } else if (STRNEQ(input, "Y_SIZE", 6)) {
+        } else if (strneq(input, "Y_SIZE", 6)) {
             const char * const arg = SkipSpacesTabs(&input[6]);
             sscanf(arg, "%dx%d", &yuvWidth, &yuvHeight);
             realWidth = yuvWidth;
             realHeight = yuvHeight;
             Fsize_Validate(&yuvWidth, &yuvHeight);
             optionSeen[OPTION_YUV_SIZE] = TRUE;
-        } else if (STRNEQ(input, "YUV_FORMAT", 10)) {
+        } else if (strneq(input, "YUV_FORMAT", 10)) {
             strcpy(yuvConversion,  SkipSpacesTabs(&input[10]));
             optionSeen[OPTION_YUV_FORMAT] = TRUE;
         }
@@ -928,26 +928,21 @@ processParamLine(char const input[],
 
 
 
-/*===========================================================================*
- *
- * ReadParamFile
- *
- *	read the parameter file
- *	function is ENCODE_FRAMES, COMBINE_GOPS, or COMBINE_FRAMES, and
- *	    will slightly modify the procedure's behavior as to what it
- *	    is looking for in the parameter file
- *
- * SIDE EFFECTS:    sets parameters accordingly, as well as machine info for
- *		    parallel execution and input file names
- *
- *===========================================================================*/
 void
-ReadParamFile(const char *    const fileName, 
-              int             const function,
-              struct params * const paramP) {
+ReadParamFile(const char *         const fileName, 
+              majorProgramFunction const function,
+              struct params *      const paramP) {
+/*----------------------------------------------------------------------------
+   Read the parameter file 'fileName' as *paramP.
 
-  FILE *fpointer;
-  char    buffer[256];
+   'function' slightly modifies our behavior as to what it is looking for
+   in the parameter file.
+
+   As a side effect, set machine info for parallel execution and input
+   file names
+-----------------------------------------------------------------------------*/
+  FILE * fpointer;
+  char buffer[256];
   bool yuvUsed;
   struct inputSource * inputSourceP;
       /* Contents of INPUT section */
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/ppmtompeg.c b/converter/ppm/ppmtompeg/ppmtompeg.c
index 2296e2cb..f53ffea9 100644
--- a/converter/ppm/ppmtompeg/ppmtompeg.c
+++ b/converter/ppm/ppmtompeg/ppmtompeg.c
@@ -33,7 +33,6 @@
 #define _BSD_SOURCE   /* Make sure strdup() is in string.h */
 
 #include <assert.h>
-#include <sys/utsname.h>
 
 #include "all.h"
 #include "mtypes.h"
@@ -98,7 +97,7 @@ void init_fdct _ANSI_ARGS_((void));
 
 struct cmdlineInfo {
     bool         childProcess;
-    int          function;
+    majorProgramFunction function;
     const char * masterHostname;
     int          masterPortNumber;
     unsigned int outputFrames;
@@ -130,36 +129,33 @@ parseArgs(int     const argc,
     
     /* parse the arguments */
     idx = 1;
-    while ( idx < argc-1 ) {
-        if ( argv[idx][0] != '-' )
+    while (idx < argc-1) {
+        if (argv[idx][0] != '-')
             pm_error("argument '%s', which must be an option because "
                      "it is not the last argument, "
                      "does not start with '-'", argv[idx]);
 
-        if ( strcmp(argv[idx], "-stat") == 0 ) {
-            if ( idx+1 < argc-1 ) {
+        if (streq(argv[idx], "-stat")) {
+            if (idx+1 < argc-1) {
                 SetStatFileName(argv[idx+1]);
                 idx += 2;
-            } else {
+            } else
                 pm_error("Invalid -stat option");
-            }
-        } else if ( strcmp(argv[idx], "-gop") == 0 ) {
-            if ((cmdlineP->function != ENCODE_FRAMES) || 
-                (cmdlineP->specificFrames))
+        } else if (streq(argv[idx], "-gop")) {
+            if (cmdlineP->function != ENCODE_FRAMES || 
+                cmdlineP->specificFrames)
                 pm_error("Invalid -gop option");
             
-            if ( idx+1 < argc-1 ) {
+            if (idx+1 < argc-1) {
                 whichGOP = atoi(argv[idx+1]);
                 idx += 2;
-            } else {
+            } else
                 pm_error("Invalid -gop option");
-            }
-        } else if ( strcmp(argv[idx], "-frames") == 0 ) {
-            if ( (cmdlineP->function != ENCODE_FRAMES) || (whichGOP != -1) ) {
+        } else if (streq(argv[idx], "-frames")) {
+            if (cmdlineP->function != ENCODE_FRAMES || whichGOP != -1)
                 pm_error("invalid -frames option");
-            }
 
-            if ( idx+2 < argc-1 ) {
+            if (idx+2 < argc-1) {
                 int const frameStart = atoi(argv[idx+1]);
                 int const frameEnd = atoi(argv[idx+2]);
 
@@ -177,23 +173,23 @@ parseArgs(int     const argc,
                 idx += 3;
             } else
                 pm_error("-frames needs to be followed by two values");
-        } else if (strcmp(argv[idx], "-combine_gops") == 0) {
-            if ((cmdlineP->function != ENCODE_FRAMES) || (whichGOP != -1) || 
-                (cmdlineP->specificFrames)) {
+        } else if (streq(argv[idx], "-combine_gops")) {
+            if (cmdlineP->function != ENCODE_FRAMES || whichGOP != -1 || 
+                cmdlineP->specificFrames) {
                 pm_error("Invalid -combine_gops option");
             }
 
             cmdlineP->function = COMBINE_GOPS;
-            idx++;
-        } else if (strcmp(argv[idx], "-combine_frames") == 0) {
-            if ((cmdlineP->function != ENCODE_FRAMES) || (whichGOP != -1) ||
-                (cmdlineP->specificFrames))
+            ++idx;
+        } else if (streq(argv[idx], "-combine_frames")) {
+            if (cmdlineP->function != ENCODE_FRAMES || whichGOP != -1 ||
+                cmdlineP->specificFrames)
                 pm_error("Invalid -combine_frames option");
 
             cmdlineP->function = COMBINE_FRAMES;
-            idx++;
-        } else if ( strcmp(argv[idx], "-child") == 0 ) {
-            if ( idx+7 < argc-1 ) {
+            ++idx;
+        } else if (streq(argv[idx], "-child")) {
+            if (idx+7 < argc-1) {
                 int combinePortNumber;
                     /* This used to be important information, when the child
                        notified the combine server.  Now the master notifies
@@ -215,104 +211,94 @@ parseArgs(int     const argc,
 
             cmdlineP->childProcess = TRUE;
             idx += 8;
-        } else if ( strcmp(argv[idx], "-io_server") == 0 ) {
-            if ( idx+2 < argc-1 ) {
-                cmdlineP->masterHostname = argv[idx+1];
+        } else if (streq(argv[idx], "-io_server")) {
+            if (idx+2 < argc-1) {
+                cmdlineP->masterHostname   = argv[idx+1];
                 cmdlineP->masterPortNumber = atoi(argv[idx+2]);
-            } else {
+            } else
                 pm_error("Invalid -io_server option");
-            }
 
             ioServer = TRUE;
             idx += 3;
-        } else if ( strcmp(argv[idx], "-output_server") == 0 ) {
-            if ( idx+3 < argc-1 ) {
-                cmdlineP->masterHostname = argv[idx+1];
+        } else if (streq(argv[idx], "-output_server")) {
+            if (idx+3 < argc-1) {
+                cmdlineP->masterHostname   = argv[idx+1];
                 cmdlineP->masterPortNumber = atoi(argv[idx+2]);
-                cmdlineP->outputFrames = atoi(argv[idx+3]);
-            } else {
+                cmdlineP->outputFrames     = atoi(argv[idx+3]);
+            } else
                 pm_error("-output_server option requires 3 option values.  "
-                         "You specified %d", argc-1 - idx);
-            }
+                         "You specified %u", argc-1 - idx);
 
             outputServer = TRUE;
             idx += 4;
-        } else if ( strcmp(argv[idx], "-decode_server") == 0 ) {
-            if ( idx+3 < argc-1 ) {
-                cmdlineP->masterHostname = argv[idx+1];
+        } else if (streq(argv[idx], "-decode_server")) {
+            if (idx+3 < argc-1) {
+                cmdlineP->masterHostname   = argv[idx+1];
                 cmdlineP->masterPortNumber = atoi(argv[idx+2]);
-                cmdlineP->outputFrames = atoi(argv[idx+3]);
-            } else {
+                cmdlineP->outputFrames     = atoi(argv[idx+3]);
+            } else
                 pm_error("Invalid -decode_server option");
-            }
 
             cmdlineP->function = COMBINE_FRAMES;
             decodeServer = TRUE;
             idx += 4;
-        } else if ( strcmp(argv[idx], "-nice") == 0 ) {
+        } else if (streq(argv[idx], "-nice")) {
             niceProcesses = TRUE;
             idx++;
-        } else if ( strcmp(argv[idx], "-max_machines") == 0 ) {
-            if ( idx+1 < argc-1 ) {
+        } else if (streq(argv[idx], "-max_machines")) {
+            if (idx+1 < argc-1) {
                 cmdlineP->maxMachines = atoi(argv[idx+1]);
-            } else {
+            } else
                 pm_error("Invalid -max_machines option");
-            }
 
             idx += 2;
-        } else if ( strcmp(argv[idx], "-quiet") == 0 ) {
-            if ( idx+1 < argc-1 ) {
+        } else if (streq(argv[idx], "-quiet")) {
+            if (idx+1 < argc-1)
                 quietTime = atoi(argv[idx+1]);
-            } else {
+            else
                 pm_error("Invalid -quiet option");
-            }
 
             idx += 2;
-        } else if ( strcmp(argv[idx], "-realquiet") == 0 ) {
+        } else if (streq(argv[idx], "-realquiet")) {
             realQuiet = TRUE;
-            idx++;
-        } else if (( strcmp(argv[idx], "-float_dct") == 0 ) ||
-                   ( strcmp(argv[idx], "-float-dct") == 0 )) {
+            ++idx;
+        } else if (streq(argv[idx], "-float_dct") ||
+                   streq(argv[idx], "-float-dct")) {
             pureDCT = TRUE;
             init_idctref();
             init_fdct();
-            idx++;
-        } else if ( strcmp(argv[idx], "-no_frame_summary") == 0 ) {
-            if ( idx < argc-1 ) {
+            ++idx;
+        } else if (streq(argv[idx], "-no_frame_summary")) {
+            if (idx < argc-1)
                 noFrameSummaryOption = TRUE;
-            } else {
+            else
                 pm_error("Invalid -no_frame_summary option");
-            }
-
-            idx++;
-        } else if ( strcmp(argv[idx], "-snr") == 0 ) {
+            ++idx;
+        } else if (streq(argv[idx], "-snr")) {
             printSNR = TRUE;
-            idx++;
-        } else if ( strcmp(argv[idx], "-mse") == 0 ) {
-            printSNR =  printMSE = TRUE;
-            idx++;
-        } else if ( strcmp(argv[idx], "-debug_sockets") == 0 ) {
+            ++idx;
+        } else if (streq(argv[idx], "-mse")) {
+            printSNR = printMSE = TRUE;
+            ++idx;
+        } else if (streq(argv[idx], "-debug_sockets")) {
             debugSockets = TRUE;
-            idx++;
-        } else if ( strcmp(argv[idx], "-debug_machines") == 0 ) {
+            ++idx;
+        } else if (streq(argv[idx], "-debug_machines")) {
             debugMachines = TRUE;
-            idx++;
-        } else if ( strcmp(argv[idx], "-bit_rate_info") == 0 ) {
-            if ( idx+1 < argc-1 ) {
+            ++idx;
+        } else if (streq(argv[idx], "-bit_rate_info")) {
+            if (idx+1 < argc-1) {
                 bitRateInfoOption = TRUE;
                 SetBitRateFileName(argv[idx+1]);
                 idx += 2;
-            } else {
+            } else
                 pm_error("Invalid -bit_rate_info option");
-            }
-        } else if ( strcmp(argv[idx], "-mv_histogram") == 0 ) {
+        } else if (streq(argv[idx], "-mv_histogram")) {
             computeMVHist = TRUE;
-            idx++;
-        } else {
+            ++idx;
+        } else
             pm_error("Unrecognized option: '%s'", argv[idx]);
-        }
     }
-
     cmdlineP->paramFileName = argv[argc-1];
 }
 
@@ -686,8 +672,8 @@ main(int argc, char **argv) {
         DecodeServer(cmdline.outputFrames, outputFileName, 
                      cmdline.masterHostname, cmdline.masterPortNumber);
     } else {
-        if ((!cmdline.specificFrames) &&
-            ((numMachines == 0) || (cmdline.function != ENCODE_FRAMES)) ) {
+        if (!cmdline.specificFrames &&
+            (numMachines == 0 || cmdline.function != ENCODE_FRAMES) ) {
             ofP = fopen(outputFileName, "wb");
             if (ofP == NULL)
                 pm_error("Could not open output file!");
@@ -695,7 +681,7 @@ main(int argc, char **argv) {
             ofP = NULL;
         
         if (cmdline.function == ENCODE_FRAMES) {
-            if ((numMachines == 0) || (cmdline.specificFrames)) {
+            if (numMachines == 0 || cmdline.specificFrames) {
                 encodeFrames(params.inputSourceP,
                              cmdline.childProcess, 
                              cmdline.masterHostname, cmdline.masterPortNumber,
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/rate.c b/converter/ppm/ppmtompeg/rate.c
index 3940956c..1a44cb95 100644
--- a/converter/ppm/ppmtompeg/rate.c
+++ b/converter/ppm/ppmtompeg/rate.c
@@ -50,7 +50,6 @@
 
 #include <assert.h>
 #include <sys/types.h>
-#include <sys/times.h>
 
 #include "ppm.h"
 #include "nstring.h"
diff --git a/converter/ppm/ppmtompeg/specifics.c b/converter/ppm/ppmtompeg/specifics.c
index c7bbfb5b..38e8fc43 100644
--- a/converter/ppm/ppmtompeg/specifics.c
+++ b/converter/ppm/ppmtompeg/specifics.c
@@ -47,12 +47,6 @@
 #include <string.h>
 #include "prototypes.h"
 
-/*====================*
- * System Information *
- *====================*/
-
-#define CPP_LOC "/lib/cpp"
-
 /*==================*
  * GLOBAL VARIABLES *
  *==================*/
@@ -153,26 +147,27 @@ static char version = -1;
  *
  *================================================================
  */
-void Specifics_Init()
-{
-  char command[1100];
-  FILE *specificsFP;
-  
-  sprintf(command, "/bin/rm -f %s.cpp", specificsFile);
-  system(command);
-  sprintf(command, "%s -P %s %s %s.cpp",
-	  CPP_LOC, specificsDefines, specificsFile, specificsFile);
-  system(command);
-  strcat(specificsFile, ".cpp");
-  if ((specificsFP = fopen(specificsFile, "r")) == NULL) {
-    fprintf(stderr, "Error with specifics file, cannot open %s\n", specificsFile);
-    exit(1);
-  }
-  printf("Specifics file: %s\n", specificsFile);
-  Parse_Specifics_File(specificsFP);
-  sprintf(command, "/bin/rm -f %s.cpp", specificsFile);
-  system(command);
+void
+Specifics_Init() {
 
+    char command[1100];
+    FILE *specificsFP;
+  
+    sprintf(command, "rm -f %s.cpp", specificsFile);
+    system(command);
+    sprintf(command, "cpp -P %s %s %s.cpp",
+            specificsDefines, specificsFile, specificsFile);
+    system(command);
+    strcat(specificsFile, ".cpp");
+    if ((specificsFP = fopen(specificsFile, "r")) == NULL) {
+        fprintf(stderr, "Error with specifics file, cannot open %s\n",
+                specificsFile);
+        exit(1);
+    }
+    printf("Specifics file: %s\n", specificsFile);
+    Parse_Specifics_File(specificsFP);
+    sprintf(command, "rm -f %s.cpp", specificsFile);
+    system(command);
 }
 
 
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/ppmtopcx.c b/converter/ppm/ppmtopcx.c
index bdcfc5c7..edc44149 100644
--- a/converter/ppm/ppmtopcx.c
+++ b/converter/ppm/ppmtopcx.c
@@ -15,6 +15,7 @@
 */
 #include <assert.h>
 
+#include "pm_c_util.h"
 #include "ppm.h"
 #include "shhopt.h"
 #include "mallocvar.h"
diff --git a/converter/ppm/ppmtopict.c b/converter/ppm/ppmtopict.c
index e2428fb6..1b9f2d5c 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);
@@ -405,7 +398,7 @@ char *packed;
 		*p++ = counttochar(count);
 
 	packcols = p - packed;		/* how many did we write? */
-	if (cols > 250)
+	if (cols > 200)
 	{
 		putShort(fd, packcols);
 		oc = packcols + 2;
@@ -443,7 +436,7 @@ char *packed;
 	bzero(aux, cols); /* aux?? */
 #endif /*notdef*/
 	bc = cols + (cols + MAX_COUNT - 1) / MAX_COUNT;
-	if (bc > 250)
+	if (bc > 200)
 	{
 		putShort(fd, bc);
 		oc = bc + 2;
diff --git a/converter/ppm/ppmtopj.c b/converter/ppm/ppmtopj.c
index 5d449f7a..d116773f 100644
--- a/converter/ppm/ppmtopj.c
+++ b/converter/ppm/ppmtopj.c
@@ -121,7 +121,7 @@ char *argv[];
 		{
 		++argn;
 		for (r = 0; rmode[r] != NULL; r++)
-		     if (STREQ(rmode[r], argv[argn]))
+		     if (streq(rmode[r], argv[argn]))
 			 break;
 		if (rmode[r] != NULL)
 		    render_mode = r;
@@ -131,9 +131,9 @@ char *argv[];
 	    else if ( pm_keymatch(argv[argn],"-back",2) && argn + 1 < argc )
 		{
 		++argn;
-		if (STREQ(argv[argn], "dark"))
+		if (streq(argv[argn], "dark"))
 		    back_scale = C_BACK_SCALE_DARK;
-		else if (STREQ(argv[argn], "lite"))
+		else if (streq(argv[argn], "lite"))
 		    back_scale = C_BACK_SCALE_LIGHT;
 		else
 		    pm_usage(usage);
diff --git a/converter/ppm/ppmtopjxl.c b/converter/ppm/ppmtopjxl.c
index 72d299fd..91cd1a45 100644
--- a/converter/ppm/ppmtopjxl.c
+++ b/converter/ppm/ppmtopjxl.c
@@ -1,4 +1,4 @@
-/* ppmtopcl.c - convert portable pixmap into PCL language for HP PaintJet and
+/* ppmtopcl.c - convert PPM into PCL language for HP PaintJet and
  *              PaintJet XL color printers
  * AJCD 12/3/91
  * 
@@ -17,8 +17,8 @@
 #include <string.h>
 
 #include "pm_c_util.h"
-#include "ppm.h"
 #include "nstring.h"
+#include "ppm.h"
 
 #define MAXCOLORS 1024
 
@@ -106,318 +106,306 @@ putbits(b, n) {
       int xo = 0;
       int xc = 0;
       if (cnt+n > 8) {  /* overflowing current byte? */
-	 xc = cnt + n - 8;
-	 xo = (b & ~(-1 << xc)) << (8-xc);
-	 n -= xc;
-	 b >>= xc;
+     xc = cnt + n - 8;
+     xo = (b & ~(-1 << xc)) << (8-xc);
+     n -= xc;
+     b >>= xc;
       }
       cnt += n;
       out |= (b & ~(-1 << n)) << (8-cnt);
       if (cnt >= 8) {
-	 inrow[num++] = out;
-	 out = xo;
-	 cnt = xc;
+     inrow[num++] = out;
+     out = xo;
+     cnt = xc;
       }
    } else { /* flush row */
       int i;
       if (cnt) {
-	 inrow[num++] = out;
-	 out = cnt = 0;
+     inrow[num++] = out;
+     out = cnt = 0;
       }
       for (; num > 0 && inrow[num-1] == 0; num--); /* remove trailing zeros */
       printf("\033*b"); 
       if (num && !nopack) {            /* TIFF 4.0 packbits encoding */
-	 int start = 0;
-	 int next;
-	 runcnt[start] = 0;
-	 for (i = 1; i < num; i++) {
-	    if (inrow[i] == inrow[i-1]) {
-	       if (runcnt[start] <= 0 && runcnt[start] > -127)
-		  runcnt[start]--;
-	       else
-		  runcnt[start = i] = 0;
-	    } else {
-	       if (runcnt[start] >= 0 && runcnt[start] < 127)
-		  runcnt[start]++;
-	       else
-		  runcnt[start = i] = 0;
-	    }
-	 }
-	 start = 0;
-	 for (i = 0; i < num; i = next) {
-	    int count = runcnt[i];
-	    int from = i;
-	    if (count >= 0) { /* merge two-byte runs */
-	       for (;;) {
-		  next = i+1+runcnt[i];
-		  if(next >= num || runcnt[next] < 0 ||
-		     count+runcnt[next]+1 > 127)
-		     break;
-		  count += runcnt[next]+1;
-		  i = next;
-	       }
-	    }
-	    next =  i + 1 + ((runcnt[i] < 0) ? -runcnt[i] : runcnt[i]);
-	    if (next < num && count > 0 &&
-		runcnt[next] < 0 && runcnt[next] > -127) {
-	       count--;
-	       next--;
-	       runcnt[next] = runcnt[next+1]-1;
-	    }
-	    outrow[start++] = count;
-	    if (count >= 0) {
-	       while (count-- >= 0)
-		  outrow[start++] = inrow[from++];
-	    } else
-	       outrow[start++] = inrow[from];
-	 }
-	 if (start < num) {
-	    num = start;
-	    if (!pack) {
-	       printf("2m");
-	       pack = 1;
-	    }
-	 } else {
-	    if (pack) {
-	       printf("0m");
-	       pack = 0;
-	    }
-	 }
+     int start = 0;
+     int next;
+     runcnt[start] = 0;
+     for (i = 1; i < num; i++) {
+        if (inrow[i] == inrow[i-1]) {
+           if (runcnt[start] <= 0 && runcnt[start] > -127)
+          runcnt[start]--;
+           else
+          runcnt[start = i] = 0;
+        } else {
+           if (runcnt[start] >= 0 && runcnt[start] < 127)
+          runcnt[start]++;
+           else
+          runcnt[start = i] = 0;
+        }
+     }
+     start = 0;
+     for (i = 0; i < num; i = next) {
+        int count = runcnt[i];
+        int from = i;
+        if (count >= 0) { /* merge two-byte runs */
+           for (;;) {
+          next = i+1+runcnt[i];
+          if(next >= num || runcnt[next] < 0 ||
+             count+runcnt[next]+1 > 127)
+             break;
+          count += runcnt[next]+1;
+          i = next;
+           }
+        }
+        next =  i + 1 + ((runcnt[i] < 0) ? -runcnt[i] : runcnt[i]);
+        if (next < num && count > 0 &&
+        runcnt[next] < 0 && runcnt[next] > -127) {
+           count--;
+           next--;
+           runcnt[next] = runcnt[next+1]-1;
+        }
+        outrow[start++] = count;
+        if (count >= 0) {
+           while (count-- >= 0)
+          outrow[start++] = inrow[from++];
+        } else
+           outrow[start++] = inrow[from];
+     }
+     if (start < num) {
+        num = start;
+        if (!pack) {
+           printf("2m");
+           pack = 1;
+        }
+     } else {
+        if (pack) {
+           printf("0m");
+           pack = 0;
+        }
+     }
       }
       printf("%dW", num);
       for (i = 0; i < num; i++)
-	 putchar(pack ? outrow[i] : inrow[i]);
+     putchar(pack ? outrow[i] : inrow[i]);
       num = 0; /* new row */
    }
 }
 
+
+
 int
-main(argc, argv)
-     int argc;
-     char *argv[];
-{
-   FILE *ifd;
-   register pixel **pixels, *pixrow;
-   register int  row, col, bpp, i;
-   int rows, cols;
-   pixval maxval;
-   int bpr, bpg, bpb;
-   int render;
-   int colors, pclindex;
-   colorhist_vector chv;
-   colorhash_table cht;
+main(int argc, const char * argv[]) {
+
+    FILE * ifP;
+    pixel ** pixels;
+    unsigned int row;
+    unsigned int bpp;
+    int rows, cols;
+    pixval maxval;
+    int bpr, bpg, bpb;
+    int render;
+    int colors, pclindex;
+    colorhist_vector chv;
+    colorhash_table cht;
    
-   ppm_init( &argc, argv );
-
-   while (argc > 1 && argv[1][0] == '-') {
-      char *c;
-      for (i = 0; i < sizeof(options)/sizeof(struct options); i++) {
-	 if (pm_keymatch(argv[1], options[i].name,
-			 MIN(strlen(argv[1]), strlen(options[i].name)))) {
-	    switch (options[i].type) {
-	    case DIM:
-	       if (++argv, --argc == 1)
-		  pm_usage(usage);
-	       for (c = argv[1]; ISDIGIT(*c); c++);
-	       if (c[0] == 'p' && c[1] == 't') /* points */
-		  *(int *)(options[i].value) = atoi(argv[1])*10;
-	       else if (c[0] == 'd' && c[1] == 'p') /* decipoints */
-		  *(int *)(options[i].value) = atoi(argv[1]);
-	       else if (c[0] == 'i' && c[1] == 'n') /* inches */
-		  *(int *)(options[i].value) = atoi(argv[1])*720;
-	       else if (c[0] == 'c' && c[1] == 'm') /* centimetres */
-		  *(int *)(options[i].value) = atoi(argv[1])*283.46457;
-	       else if (!c[0]) /* dots */
-		  *(int *)(options[i].value) = atoi(argv[1])*4;
-	       else
-		  pm_error("illegal unit of measure %s", c);
-	       break;
-	    case REAL:
-	       if (++argv, --argc == 1)
-		  pm_usage(usage);
-	       *(double *)(options[i].value) = atof(argv[1]);
-	       break;
-	    case BOOL:
-	       *(int *)(options[i].value) = 1;
-	       break;
-	    }
-	    break;
-	 }
-      }
-      if (i >= sizeof(options)/sizeof(struct options))
-	 pm_usage(usage);
-      argv++; argc--;
-   }
-   if (argc > 2)
-      pm_usage(usage);
-   else if (argc == 2)
-      ifd = pm_openr(argv[1]);
-   else
-      ifd = stdin ;
-
-   /* validate arguments */
-   if (diffuse+cluster+dither > 1)
-      pm_error("only one of -diffuse, -dither and -cluster may be used");
-   render = diffuse ? 4 : dither ? 3 : cluster ? 7 : 0;
-
-   if (xsize != 0.0 && xscale != 0.0)
-      pm_error("only one of -xsize and -xscale may be used");
-
-   if (ysize != 0.0 && yscale != 0.0)
-      pm_error("only one of -ysize and -yscale may be used");
-
-   pixels = ppm_readppm( ifd, &cols, &rows, &maxval );
-   pm_close( ifd );
-
-   /* limit checks */
-   if (cols > PCL_MAXWIDTH || rows > PCL_MAXHEIGHT)
-      pm_error("image too large; reduce with ppmscale");
-   if (maxval > PCL_MAXVAL)
-      pm_error("color range too large; reduce with ppmcscale");
-
-   /* Figure out the colormap. */
-   fprintf( stderr, "(Computing colormap..." ); fflush( stderr );
-   chv = ppm_computecolorhist( pixels, cols, rows, MAXCOLORS, &colors );
-   if ( chv == (colorhist_vector) 0 )
-      pm_error("too many colors; reduce with pnmquant");
-   fprintf( stderr, "  Done.  %d colors found.)\n", colors );
-
-   /* And make a hash table for fast lookup. */
-   cht = ppm_colorhisttocolorhash( chv, colors );
-
-   /* work out color downloading mode */
-   pclindex = bitsperpixel(colors);
-   if (pclindex > 8) /* can't use indexed mode */
-      pclindex = 0;
-   else
-      switch (pclindex) { /* round up to 1,2,4,8 */
-      case 0: /* direct mode (no palette) */
-	 bpp = bitsperpixel(maxval); /* bits per pixel */
-	 bpg = bpp; bpb = bpp;
-	 bpp = (bpp*3+7)>>3;     /* bytes per pixel now */
-	 bpr = (bpp<<3)-bpg-bpb; 
-	 bpp *= cols;            /* bytes per row now */
-	 break;
-      case 5:         pclindex++;
-      case 6:         pclindex++;
-      case 3: case 7: pclindex++;
-      default:
-	 bpp = 8/pclindex;
-	 bpp = (cols+bpp-1)/bpp;      /* bytes per row */
-      }
+    pm_proginit(&argc, argv);
 
-   if ((inrow = (char *)malloc((unsigned)bpp)) == NULL ||
-       (outrow = (char *)malloc((unsigned)bpp*2)) == NULL ||
-       (runcnt = (signed char *)malloc((unsigned)bpp)) == NULL)
-      pm_error("can't allocate space for row");
-
-   /* set up image details */
-   if (xscale != 0.0)
-      xsize = cols * xscale * 4;
-   if (yscale != 0.0)
-      ysize = rows * yscale * 4;
-
-#ifdef DEBUG
-   fprintf(stderr, "dark    =%d\n", dark);
-   fprintf(stderr, "diffuse =%d\n", diffuse);
-   fprintf(stderr, "dither  =%d\n", dither);
-   fprintf(stderr, "cluster =%d\n", cluster);
-   fprintf(stderr, "quality =%d\n", quality);
-   fprintf(stderr, "xsize   =%d\n", xsize);
-   fprintf(stderr, "ysize   =%d\n", ysize);
-   fprintf(stderr, "xshift  =%d\n", xshift);
-   fprintf(stderr, "yshift  =%d\n", yshift);
-   fprintf(stderr, "xscale  =%lf\n", xscale);
-   fprintf(stderr, "yscale  =%lf\n", yscale);
-   fprintf(stderr, "gamma   =%lf\n", gamma_val);
-   fprintf(stderr, "pclindex   =%d\n", pclindex);
-   fprintf(stderr, "nopack  =%d\n", nopack);
-#endif
+    while (argc > 1 && argv[1][0] == '-') {
+        unsigned int i;
+        for (i = 0; i < sizeof(options)/sizeof(struct options); i++) {
+            if (pm_keymatch(argv[1], options[i].name,
+                            MIN(strlen(argv[1]), strlen(options[i].name)))) {
+                const char * c;
+                switch (options[i].type) {
+                case DIM:
+                    if (++argv, --argc == 1)
+                        pm_usage(usage);
+                    for (c = argv[1]; ISDIGIT(*c); c++);
+                    if (c[0] == 'p' && c[1] == 't') /* points */
+                        *(int *)(options[i].value) = atoi(argv[1])*10;
+                    else if (c[0] == 'd' && c[1] == 'p') /* decipoints */
+                        *(int *)(options[i].value) = atoi(argv[1]);
+                    else if (c[0] == 'i' && c[1] == 'n') /* inches */
+                        *(int *)(options[i].value) = atoi(argv[1])*720;
+                    else if (c[0] == 'c' && c[1] == 'm') /* centimetres */
+                        *(int *)(options[i].value) = atoi(argv[1])*283.46457;
+                    else if (!c[0]) /* dots */
+                        *(int *)(options[i].value) = atoi(argv[1])*4;
+                    else
+                        pm_error("illegal unit of measure %s", c);
+                    break;
+                case REAL:
+                    if (++argv, --argc == 1)
+                        pm_usage(usage);
+                    *(double *)(options[i].value) = atof(argv[1]);
+                    break;
+                case BOOL:
+                    *(int *)(options[i].value) = 1;
+                    break;
+                }
+                break;
+            }
+        }
+        if (i >= sizeof(options)/sizeof(struct options))
+            pm_usage(usage);
+        argv++; argc--;
+    }
+    if (argc > 2)
+        pm_usage(usage);
+    else if (argc == 2)
+        ifP = pm_openr(argv[1]);
+    else
+        ifP = stdin ;
+
+    /* validate arguments */
+    if (diffuse+cluster+dither > 1)
+        pm_error("only one of -diffuse, -dither and -cluster may be used");
+    render = diffuse ? 4 : dither ? 3 : cluster ? 7 : 0;
+
+    if (xsize != 0.0 && xscale != 0.0)
+        pm_error("only one of -xsize and -xscale may be used");
+
+    if (ysize != 0.0 && yscale != 0.0)
+        pm_error("only one of -ysize and -yscale may be used");
+
+    pixels = ppm_readppm(ifP, &cols, &rows, &maxval);
+    pm_close(ifP);
+
+    /* limit checks */
+    if (cols > PCL_MAXWIDTH || rows > PCL_MAXHEIGHT)
+        pm_error("image too large; reduce with ppmscale");
+    if (maxval > PCL_MAXVAL)
+        pm_error("color range too large; reduce with ppmcscale");
 
-   /* write PCL header */
+    /* Figure out the colormap. */
+    pm_message("Computing colormap...");
+    chv = ppm_computecolorhist(pixels, cols, rows, MAXCOLORS, &colors);
+    if (!chv)
+        pm_error("too many colors; reduce with pnmquant");
+    pm_message("... Done.  %u colors found.", colors);
+
+    /* And make a hash table for fast lookup. */
+    cht = ppm_colorhisttocolorhash(chv, colors);
+
+    /* work out color downloading mode */
+    pclindex = bitsperpixel(colors);
+    if (pclindex > 8) /* can't use indexed mode */
+        pclindex = 0;
+    else {
+        switch (pclindex) { /* round up to 1,2,4,8 */
+        case 0: /* direct mode (no palette) */
+            bpp = bitsperpixel(maxval); /* bits per pixel */
+            bpg = bpp; bpb = bpp;
+            bpp = (bpp*3+7)>>3;     /* bytes per pixel now */
+            bpr = (bpp<<3)-bpg-bpb; 
+            bpp *= cols;            /* bytes per row now */
+            break;
+        case 5:         pclindex++;
+        case 6:         pclindex++;
+        case 3: case 7: pclindex++;
+        default:
+            bpp = 8/pclindex;
+            bpp = (cols+bpp-1)/bpp;      /* bytes per row */
+        }
+    }
+    inrow = (char *)malloc((unsigned)bpp);
+    outrow = (char *)malloc((unsigned)bpp*2);
+    runcnt = (signed char *)malloc((unsigned)bpp);
+    if (inrow == NULL || outrow == NULL || runcnt == NULL)
+        pm_error("can't allocate space for row");
+
+    /* set up image details */
+    if (xscale != 0.0)
+        xsize = cols * xscale * 4;
+    if (yscale != 0.0)
+        ysize = rows * yscale * 4;
+
+    /* write PCL header */
 #if 0
-   printf("\033&l26A");                         /* paper size */
+    printf("\033&l26A");                         /* paper size */
 #endif
-   printf("\033*r%ds%dT", cols, rows);          /* source width, height */
-   if (xshift != 0 || yshift != 0)
-      printf("\033&a%+dh%+dV", xshift, yshift); /* xshift, yshift */
-   if (quality)
-      printf("\033*o%dQ", quality);             /* print quality */
-   printf("\033*t");
-   if (xsize == 0 && ysize == 0)
-      printf("180r");                   /* resolution */
-   else {                               /* destination width, height */
-      if (xsize != 0)
-	 printf("%dh", xsize);
-      if (ysize != 0)
-	 printf("%dv", ysize);
-   }
-   if (gamma_val != 0)
-      printf("%.3fi", gamma_val);                    /* gamma correction */
-   if (dark)
-      printf("%dk", dark);              /* scaling algorithms */
-   printf("%dJ", render);               /* rendering algorithm */
-   printf("\033*v18W");                           /* configure image data */
-      putchar(0); /* relative colors */
-      putchar(pclindex ? 1 : 3); /* index/direct pixel mode */
-      putchar(pclindex); /* ignored in direct pixel mode */
-      if (pclindex) {
-	 putchar(0);
-	 putchar(0);
-	 putchar(0);
-      } else {
-	 putchar(bpr); /* bits per red */
-	 putchar(bpg); /* bits per green */
-	 putchar(bpb); /* bits per blue */
-      }
-      putword(maxval); /* max red reference */
-      putword(maxval); /* max green reference */
-      putword(maxval); /* max blue reference */
-      putword(0); /* min red reference */
-      putword(0); /* min green reference */
-      putword(0); /* min blue reference */
-   if (pclindex) {                        /* set palette */
-      for (i = 0; i < colors; i++) {
-	 int r, g, b;
-	 r = PPM_GETR( chv[i].color );
-	 g = PPM_GETG( chv[i].color );
-	 b = PPM_GETB( chv[i].color );
-	 if (i == 0)
-	    printf("\033*v");
-	 if (r)
-	    printf("%da", r);
-	 if (g)
-	    printf("%db", g);
-	 if (b)
-	    printf("%dc", b);
-	 if (i == colors-1)
-	    printf("%dI", i);    /* assign color index */
-	 else
-	    printf("%di", i);    /* assign color index */
-      }
-   }
-   ppm_freecolorhist( chv );
-
-   /* start raster graphics at CAP */
-   printf("\033*r%dA", (xsize != 0 || ysize != 0) ? 3 : 1);
-
-   for (row = 0; row < rows; row++) {
-      if (pclindex) { /* indexed color mode */
-	 int out, cnt;
-	 out = cnt = 0;
-	 for (col = 0, pixrow=pixels[row]; col < cols; col++, pixrow++) {
-	    putbits(ppm_lookupcolor( cht, pixrow ), pclindex);
-	 }
-	 putbits(0, 0); /* flush row */
-      } else { /* direct color mode */
-	 for (col = 0, pixrow=pixels[row]; col < cols; col++, pixrow++) {
-	    putbits(PPM_GETR( *pixrow ), bpr);
-	    putbits(PPM_GETG( *pixrow ), bpg);
-	    putbits(PPM_GETB( *pixrow ), bpb); /* don't need to flush */
-	 }
-	 putbits(0, 0); /* flush row */
-      }
-   }
-   printf("\033*rC"); /* end raster graphics */
-   exit(0);
+    printf("\033*r%ds%dT", cols, rows);          /* source width, height */
+    if (xshift != 0 || yshift != 0)
+        printf("\033&a%+dh%+dV", xshift, yshift); /* xshift, yshift */
+    if (quality)
+        printf("\033*o%dQ", quality);             /* print quality */
+    printf("\033*t");
+    if (xsize == 0 && ysize == 0)
+        printf("180r");                   /* resolution */
+    else {                               /* destination width, height */
+        if (xsize != 0)
+            printf("%dh", xsize);
+        if (ysize != 0)
+            printf("%dv", ysize);
+    }
+    if (gamma_val != 0)
+        printf("%.3fi", gamma_val);                    /* gamma correction */
+    if (dark)
+        printf("%dk", dark);              /* scaling algorithms */
+    printf("%dJ", render);               /* rendering algorithm */
+    printf("\033*v18W");                           /* configure image data */
+    putchar(0); /* relative colors */
+    putchar(pclindex ? 1 : 3); /* index/direct pixel mode */
+    putchar(pclindex); /* ignored in direct pixel mode */
+    if (pclindex) {
+        putchar(0);
+        putchar(0);
+        putchar(0);
+    } else {
+        putchar(bpr); /* bits per red */
+        putchar(bpg); /* bits per green */
+        putchar(bpb); /* bits per blue */
+    }
+    putword(maxval); /* max red reference */
+    putword(maxval); /* max green reference */
+    putword(maxval); /* max blue reference */
+    putword(0); /* min red reference */
+    putword(0); /* min green reference */
+    putword(0); /* min blue reference */
+    if (pclindex) {                        /* set palette */
+        unsigned int i;
+        for (i = 0; i < colors; ++i) {
+            int const r = PPM_GETR( chv[i].color);
+            int const g = PPM_GETG( chv[i].color);
+            int const b = PPM_GETB( chv[i].color);
+            if (i == 0)
+                printf("\033*v");
+            if (r)
+                printf("%da", r);
+            if (g)
+                printf("%db", g);
+            if (b)
+                printf("%dc", b);
+            if (i == colors-1)
+                printf("%dI", i);    /* assign color index */
+            else
+                printf("%di", i);    /* assign color index */
+        }
+    }
+    ppm_freecolorhist(chv);
+
+    /* start raster graphics at CAP */
+    printf("\033*r%dA", (xsize != 0 || ysize != 0) ? 3 : 1);
+
+    for (row = 0; row < rows; row++) {
+        pixel * const pixrow = pixels[row];
+        if (pclindex) { /* indexed color mode */
+            unsigned int col;
+            for (col = 0; col < cols; ++col)
+                putbits(ppm_lookupcolor(cht, &pixrow[col]), pclindex);
+            putbits(0, 0); /* flush row */
+        } else { /* direct color mode */
+            unsigned int col;
+            for (col = 0; col < cols; ++col) {
+                putbits(PPM_GETR(pixrow[col]), bpr);
+                putbits(PPM_GETG(pixrow[col]), bpg);
+                putbits(PPM_GETB(pixrow[col]), bpb);
+                /* don't need to flush */
+            }
+            putbits(0, 0); /* flush row */
+        }
+    }
+    printf("\033*rC"); /* end raster graphics */
+
+    return 0;
 }
diff --git a/converter/ppm/ppmtoterm.c b/converter/ppm/ppmtoterm.c
index 72105705..81df614e 100644
--- a/converter/ppm/ppmtoterm.c
+++ b/converter/ppm/ppmtoterm.c
@@ -21,6 +21,7 @@
 
 #include <string.h>
 
+#include "pm_c_util.h"
 #include "ppm.h"
 #include "shhopt.h"
 
diff --git a/converter/ppm/ppmtowinicon.c b/converter/ppm/ppmtowinicon.c
index d7f12dd0..a96840a1 100644
--- a/converter/ppm/ppmtowinicon.c
+++ b/converter/ppm/ppmtowinicon.c
@@ -13,6 +13,7 @@
 #include <math.h>
 #include <string.h>
 
+#include "pm_c_util.h"
 #include "winico.h"
 #include "ppm.h"
 #include "mallocvar.h"
@@ -203,8 +204,6 @@ createAndBitmap (gray ** const ba, int const cols, int const rows,
     * How wide should the u1 string for each row be?
     * each byte is 8 pixels, but must be a multiple of 4 bytes.
     */
-
-#define ROUNDUP(X,M) (((X)+(M)-1)/(M)*(M))
    unsigned int const xBytes = ROUNDUP(cols, 32)/8;
    ICON_bmp icBitmap;
    int y,x;
diff --git a/converter/ppm/ppmtoxpm.c b/converter/ppm/ppmtoxpm.c
index 630653df..fc8ba9d7 100644
--- a/converter/ppm/ppmtoxpm.c
+++ b/converter/ppm/ppmtoxpm.c
@@ -39,6 +39,8 @@
 #include <stdio.h>
 #include <ctype.h>
 #include <string.h>
+
+#include "pm_c_util.h"
 #include "ppm.h"
 #include "shhopt.h"
 #include "nstring.h"
@@ -138,7 +140,7 @@ parseCommandLine(int argc, char ** argv,
     /* If output filename not specified, use input filename as default. */
     if (nameSpec)
         cmdlineP->name = nameOpt;
-    else if (STREQ(cmdlineP->inputFilename, "-"))
+    else if (streq(cmdlineP->inputFilename, "-"))
         cmdlineP->name = "noname";
     else {
         static char name[80+1];
diff --git a/converter/ppm/ppmtoyuvsplit.c b/converter/ppm/ppmtoyuvsplit.c
index 133161c1..b5809d0b 100644
--- a/converter/ppm/ppmtoyuvsplit.c
+++ b/converter/ppm/ppmtoyuvsplit.c
@@ -4,7 +4,7 @@
 ** - basename.V : The Chrominance chunk V at 1/4
 ** The subsampled U and V values are made by arithmetic mean.
 **
-** If CCIR601 is defined, the produced YUV triples are scaled again
+** The produced YUV triples are scaled again
 ** to fit into the smaller range of values for this standard.
 **
 ** by A.Beck
@@ -20,12 +20,6 @@
 ** implied warranty.
 */
 
-/* Wether to create YUV in JFIF(JPEG) or CCIR.601(MPEG) scale */
-#define CCIR601
-
-/* Wether to use pm_close() or fake it -- don't ask me why */
-/* #define ORIGINAL */
-
 /* ALPHA Kludge by Franky */
 
 #ifdef __alpha
@@ -70,156 +64,148 @@ termFileNameSet(struct FileNameSet const fname) {
 
 
 int
-main(argc, argv)
-char **argv;
-{
-        FILE *ifp,*vf,*uf,*yf;
-        pixel          *pixelrow1,*pixelrow2;
-        register pixel *pP1,*pP2;
-        int             rows, cols, format, row;
-        register int    col;
-        pixval          maxval;
-        myLONG u,v,y0,y1,y2,y3,u0,u1,u2,u3,v0,v1,v2,v3;
-        unsigned char  *y1buf,*y2buf,*ubuf,*vbuf;
-        struct FileNameSet fname;
-            /* Output file names - .U, .V, .Y */
-
-        ppm_init(&argc, argv);
-
-        if ((argc>3)||(argc<2)) pm_usage("basename [ppmfile]");
-
-        if (argc == 3) ifp = pm_openr(argv[2]);
-        else ifp = stdin;
-
-        makeOutputFileName(argv[1], &fname);
-
-        uf = pm_openw(fname.u);
-        vf = pm_openw(fname.v);
-        yf = pm_openw(fname.y);
-
-        termFileNameSet(fname);
-
-        if(!(uf && vf && yf)) {
-         perror("error opening output files");
-         exit(0);
-        }
-        ppm_readppminit(ifp, &cols, &rows, &maxval, &format);
-
-        if(cols & 1) fprintf(stderr,
-                             "%s: Warning: odd columns count, exceed ignored\n",
-                             argv[0]);
-        if(rows & 1) fprintf(stderr,
-                             "%s: Warning: odd rows count, exceed ignored\n",
-                             argv[0]);
-
-        pixelrow1 = ((pixel*) pm_allocrow( cols, sizeof(pixel) ));
-        pixelrow2 = ((pixel*) pm_allocrow( cols, sizeof(pixel) ));
-
-        y1buf = (unsigned char *) pm_allocrow( cols, 1 );
-        y2buf = (unsigned char *) pm_allocrow( cols, 1 );
-        ubuf = (unsigned char *) pm_allocrow( cols, 1 );
-        vbuf = (unsigned char *) pm_allocrow( cols, 1 );
-
-        for (row = 0; row < (rows & ~1); row += 2) {
-                unsigned char *y1ptr,*y2ptr,*uptr,*vptr;
-
-                ppm_readppmrow(ifp, pixelrow1, cols, maxval, format);
-                ppm_readppmrow(ifp, pixelrow2, cols, maxval, format);
-
-                pP1 = pixelrow1; pP2 = pixelrow2;
-                y1ptr = y1buf; y2ptr = y2buf; vptr = vbuf; uptr = ubuf;
-
-                for (col = 0 ; col < (cols & ~1); col += 2) {
-                        pixval r0,g0,b0,r1,g1,b1,r2,g2,b2,r3,g3,b3;
-
-                        /* first pixel */
-                        r0 = PPM_GETR(*pP1);
-                        g0 = PPM_GETG(*pP1);
-                        b0 = PPM_GETB(*pP1);
-                        pP1++;
-                        /* 2nd pixel */
-                        r1 = PPM_GETR(*pP1);
-                        g1 = PPM_GETG(*pP1);
-                        b1 = PPM_GETB(*pP1);
-                        pP1++;
-                        /* 3rd pixel */
-                        r2 = PPM_GETR(*pP2);
-                        g2 = PPM_GETG(*pP2);
-                        b2 = PPM_GETB(*pP2);
-                        pP2++;
-                        /* 4th pixel */
-                        r3 = PPM_GETR(*pP2);
-                        g3 = PPM_GETG(*pP2);
-                        b3 = PPM_GETB(*pP2);
-                        pP2++;
-
-
-/* The JFIF RGB to YUV Matrix for $00010000 = 1.0
-
-[Y]   [19595   38469    7471][R]
-[U] = [-11056  -21712  32768][G]
-[V]   [32768   -27440  -5328][B]
+main(int argc, const char ** argv) {
+
+    FILE * ifP;
+    FILE *vf, *uf, *yf;
+    pixel *pixelrow1, *pixelrow2;
+    int rows, cols;
+    int format;
+    unsigned int row;
+    pixval maxval;
+    unsigned char *y1buf, *y2buf, *ubuf, *vbuf;
+    struct FileNameSet fname;
+        /* Output file names - .U, .V, .Y */
+
+    pm_proginit(&argc, argv);
 
-*/
+    if ((argc-1 > 2) || (argc-1 < 1))
+        pm_error("Wrong number of arguments: %u.  "
+                 "Arguments are basename for output files "
+                 "and optional input file name", argc-1);
+
+    if (argc-1 == 2)
+        ifP = pm_openr(argv[2]);
+    else
+        ifP = stdin;
+
+    makeOutputFileName(argv[1], &fname);
+
+    uf = pm_openw(fname.u);
+    vf = pm_openw(fname.v);
+    yf = pm_openw(fname.y);
 
-                        y0 =  19595 * r0 + 38469 * g0 +  7471 * b0;
-                        u0 = -11056 * r0 - 21712 * g0 + 32768 * b0;
-                        v0 =  32768 * r0 - 27440 * g0 -  5328 * b0;
+    termFileNameSet(fname);
 
-                        y1 =  19595 * r1 + 38469 * g1 +  7471 * b1;
-                        u1 = -11056 * r1 - 21712 * g1 + 32768 * b1;
-                        v1 =  32768 * r1 - 27440 * g1 -  5328 * b1;
+    ppm_readppminit(ifP, &cols, &rows, &maxval, &format);
 
-                        y2 =  19595 * r2 + 38469 * g2 +  7471 * b2;
-                        u2 = -11056 * r2 - 21712 * g2 + 32768 * b2;
-                        v2 =  32768 * r2 - 27440 * g2 -  5328 * b2;
+    if (cols % 2 == 1)
+        pm_message("Warning: odd columns count %u, excess ignored", cols);
 
-                        y3 =  19595 * r3 + 38469 * g3 +  7471 * b3;
-                        u3 = -11056 * r3 - 21712 * g3 + 32768 * b3;
-                        v3 =  32768 * r3 - 27440 * g3 -  5328 * b3;
+    if (rows % 2 == 1)
+        pm_message("Warning: odd rows count %u, excess ignored", rows);
 
-                        /* mean the chroma for subsampling */
+    pixelrow1 = ((pixel*) pm_allocrow(cols, sizeof(pixel)));
+    pixelrow2 = ((pixel*) pm_allocrow(cols, sizeof(pixel)));
 
-                        u  = (u0+u1+u2+u3)>>2;
-                        v  = (v0+v1+v2+v3)>>2;
+    y1buf = (unsigned char *) pm_allocrow(cols, 1);
+    y2buf = (unsigned char *) pm_allocrow(cols, 1);
+    ubuf = (unsigned char *) pm_allocrow(cols, 1);
+    vbuf = (unsigned char *) pm_allocrow(cols, 1);
 
-#ifdef CCIR601
+    for (row = 0; row < (rows & ~1); row += 2) {
+        unsigned char *y1ptr, *y2ptr, *uptr, *vptr;
+        pixel *pP1, *pP2;
+        unsigned int col;
 
-                        y0 = (y0 * 219)/255 + 1048576;
-                        y1 = (y1 * 219)/255 + 1048576;
-                        y2 = (y2 * 219)/255 + 1048576;
-                        y3 = (y3 * 219)/255 + 1048576;
+        ppm_readppmrow(ifP, pixelrow1, cols, maxval, format);
+        ppm_readppmrow(ifP, pixelrow2, cols, maxval, format);
 
-                        u  = (u * 224)/255 ;
-                        v  = (v * 224)/255 ;
-#endif
+        pP1 = &pixelrow1[0]; pP2 = &pixelrow2[0];
+        y1ptr = y1buf; y2ptr = y2buf; vptr = vbuf; uptr = ubuf;
 
+        for (col = 0 ; col < (cols & ~1); col += 2) {
+            pixval r0,g0,b0,r1,g1,b1,r2,g2,b2,r3,g3,b3;
+            myLONG u, v, y0, y1, y2, y3, u0, u1, u2, u3, v0, v1, v2, v3;
 
-                        *y1ptr++  = (y0 >> 16) ;
-                        *y1ptr++  = (y1 >> 16) ;
-                        *y2ptr++  = (y2 >> 16) ;
-                        *y2ptr++  = (y3 >> 16) ;
+            /* first pixel */
+            r0 = PPM_GETR(*pP1);
+            g0 = PPM_GETG(*pP1);
+            b0 = PPM_GETB(*pP1);
+            pP1++;
+            /* 2nd pixel */
+            r1 = PPM_GETR(*pP1);
+            g1 = PPM_GETG(*pP1);
+            b1 = PPM_GETB(*pP1);
+            pP1++;
+            /* 3rd pixel */
+            r2 = PPM_GETR(*pP2);
+            g2 = PPM_GETG(*pP2);
+            b2 = PPM_GETB(*pP2);
+            pP2++;
+            /* 4th pixel */
+            r3 = PPM_GETR(*pP2);
+            g3 = PPM_GETG(*pP2);
+            b3 = PPM_GETB(*pP2);
+            pP2++;
 
 
-                        *uptr++   = (u >> 16)+128 ;
-                        *vptr++   = (v >> 16)+128 ;
+            /* The JFIF RGB to YUV Matrix for $00010000 = 1.0
 
-                }
-                fwrite(y1buf, (cols & ~1), 1, yf);
-                fwrite(y2buf, (cols & ~1), 1, yf);
-                fwrite(ubuf, cols/2, 1, uf);
-                fwrite(vbuf, cols/2, 1, vf);
-        }
+               [Y]   [19595   38469    7471][R]
+               [U] = [-11056  -21712  32768][G]
+               [V]   [32768   -27440  -5328][B]
 
-/* I dunno why pm_close sees an error... get rid of it */
+            */
 
-#ifdef ORIGINAL
-        pm_close(ifp);
-#else
-        if(ifp != stdin) fclose(ifp);
-#endif
-        fclose(yf);
-        fclose(uf);
-        fclose(vf);
-        exit(0);
+            y0 =  19595 * r0 + 38469 * g0 +  7471 * b0;
+            u0 = -11056 * r0 - 21712 * g0 + 32768 * b0;
+            v0 =  32768 * r0 - 27440 * g0 -  5328 * b0;
+
+            y1 =  19595 * r1 + 38469 * g1 +  7471 * b1;
+            u1 = -11056 * r1 - 21712 * g1 + 32768 * b1;
+            v1 =  32768 * r1 - 27440 * g1 -  5328 * b1;
+
+            y2 =  19595 * r2 + 38469 * g2 +  7471 * b2;
+            u2 = -11056 * r2 - 21712 * g2 + 32768 * b2;
+            v2 =  32768 * r2 - 27440 * g2 -  5328 * b2;
+
+            y3 =  19595 * r3 + 38469 * g3 +  7471 * b3;
+            u3 = -11056 * r3 - 21712 * g3 + 32768 * b3;
+            v3 =  32768 * r3 - 27440 * g3 -  5328 * b3;
+
+            /* mean the chroma for subsampling */
+
+            u  = (u0+u1+u2+u3)>>2;
+            v  = (v0+v1+v2+v3)>>2;
+
+            y0 = (y0 * 219)/255 + 1048576;
+            y1 = (y1 * 219)/255 + 1048576;
+            y2 = (y2 * 219)/255 + 1048576;
+            y3 = (y3 * 219)/255 + 1048576;
+
+            u  = (u * 224)/255 ;
+            v  = (v * 224)/255 ;
+
+            *y1ptr++  = (y0 >> 16) ;
+            *y1ptr++  = (y1 >> 16) ;
+            *y2ptr++  = (y2 >> 16) ;
+            *y2ptr++  = (y3 >> 16) ;
+
+
+            *uptr++   = (u >> 16)+128 ;
+            *vptr++   = (v >> 16)+128 ;
+
+        }
+        fwrite(y1buf, (cols & ~1), 1, yf);
+        fwrite(y2buf, (cols & ~1), 1, yf);
+        fwrite(ubuf, cols/2, 1, uf);
+        fwrite(vbuf, cols/2, 1, vf);
+    }
+
+    pm_close(ifP);
+    fclose(yf);
+    fclose(uf);
+    fclose(vf);
+    return 0;
 }
diff --git a/converter/ppm/rawtoppm.c b/converter/ppm/rawtoppm.c
index 8d6c3b2c..44e856da 100644
--- a/converter/ppm/rawtoppm.c
+++ b/converter/ppm/rawtoppm.c
@@ -13,39 +13,148 @@
 #include <math.h>
 #include "ppm.h"
 
-static void dorowskip ARGS(( FILE* ifp, int rowskip ));
+enum order { ORD_RGB, ORD_RBG, ORD_GRB, ORD_GBR, ORD_BRG, ORD_BGR };
+
+enum interleave { INT_PIX, INT_ROW };
+
+static void
+dorowskip(FILE * const ifP,
+          int    const rowskip) {
+
+    unsigned int i;
+
+    for (i = 0; i < rowskip; ++i) {
+        int const val = getc(ifP);
+        if (val == EOF)
+            pm_error("EOF / read error");
+    }
+}
+
+
+
+static void
+doRowPixInterleave(pixel *      const pixrow,
+                   unsigned int const cols,
+                   FILE *       const ifP,
+                   enum order   const order,
+                   int          const rowskip) {
+
+    unsigned int col;
+
+    for (col = 0; col < cols; ++col) {
+        int const val1 = getc(ifP);
+        int const val2 = getc(ifP);
+        int const val3 = getc(ifP);
+
+        if (val1 == EOF)
+            pm_error("EOF / read error");
+        if (val2 == EOF)
+            pm_error("EOF / read error");
+        if (val3 == EOF)
+            pm_error("EOF / read error");
+
+        switch (order) {
+        case ORD_RGB:
+            PPM_ASSIGN(pixrow[col], val1, val2, val3);
+            break;
+        case ORD_RBG:
+            PPM_ASSIGN(pixrow[col], val1, val3, val2);
+            break;
+        case ORD_GRB:
+            PPM_ASSIGN(pixrow[col], val2, val1, val3);
+            break;
+        case ORD_GBR:
+            PPM_ASSIGN(pixrow[col], val3, val1, val2);
+            break;
+        case ORD_BRG:
+            PPM_ASSIGN(pixrow[col], val2, val3, val1);
+            break;
+        case ORD_BGR:
+            PPM_ASSIGN(pixrow[col], val3, val2, val1);
+            break;
+        }
+    }
+    dorowskip(ifP, rowskip);
+}
+
+
+
+static void
+doRowRowInterleave(pixel *      const pixrow,
+                   unsigned int const cols,
+                   FILE *       const ifP,
+                   enum order   const order,
+                   int          const rowskip,
+                   pixval *     const grow1,
+                   pixval *     const grow2,
+                   pixval *     const grow3) {
+
+    unsigned int col;
+
+    for (col = 0; col < cols; ++col) {
+        int const val1 = getc(ifP);
+        if (val1 == EOF)
+            pm_error("EOF / read error");
+        grow1[col] = val1;
+    }
+    dorowskip(ifP, rowskip);
+    for (col = 0; col < cols; ++col) {
+        int const val2 = getc(ifP);
+        if (val2 == EOF)
+            pm_error( "EOF / read error" );
+        grow2[col] = val2;
+    }
+    dorowskip(ifP, rowskip);
+    for (col = 0; col < cols; ++col) {
+        int const val3 = getc(ifP);
+        if (val3 == EOF)
+            pm_error( "EOF / read error" );
+        grow3[col] = val3;
+    }
+    dorowskip(ifP, rowskip);
+
+    for (col = 0; col < cols; ++col) {
+        switch (order) {
+        case ORD_RGB:
+            PPM_ASSIGN(pixrow[col], grow1[col], grow2[col], grow3[col]);
+            break;
+        case ORD_RBG:
+            PPM_ASSIGN(pixrow[col], grow1[col], grow3[col], grow2[col]);
+            break;
+        case ORD_GRB:
+            PPM_ASSIGN(pixrow[col], grow2[col], grow1[col], grow3[col]);
+            break;
+        case ORD_GBR:
+            PPM_ASSIGN(pixrow[col], grow3[col], grow1[col], grow2[col]);
+            break;
+        case ORD_BRG:
+            PPM_ASSIGN(pixrow[col], grow2[col], grow3[col], grow1[col]);
+            break;
+        case ORD_BGR:
+            PPM_ASSIGN(pixrow[col], grow3[col], grow2[col], grow1[col]);
+            break;
+        }
+    }
+}
+
+
 
 int
-main( argc, argv )
-    int argc;
-    char* argv[];
-    {
-    FILE* ifp;
-    pixel* pixrow;
-    register pixel* pP;
+main(int argc, const char * argv[]) {
+
+    pixval const maxval = 255;
+
+    FILE * ifP;
+    pixel * pixrow;
     int argn, headerskip, rowskip, rows, cols, row, i;
-    register int col;
-    int order;
-#define ORD_RGB 1
-#define ORD_RBG 2
-#define ORD_GRB 3
-#define ORD_GBR 4
-#define ORD_BRG 5
-#define ORD_BGR 6
-int interleave;
-#define INT_PIX 1
-#define INT_ROW 2
-    int val1, val2, val3;
-    gray* grow1;
-    gray* grow2;
-    gray* grow3;
-    register gray* g1P;
-    register gray* g2P;
-    register gray* g3P;
+    enum order order;
+    enum interleave interleave;
+    gray * grow1;
+    gray * grow2;
+    gray * grow3;
     const char* const usage = "[-headerskip N] [-rowskip N] [-rgb|-rbg|-grb|-gbr|-brg|-bgr] [-interpixel|-interrow] <width> <height> [rawfile]";
 
-
-    ppm_init( &argc, argv );
+    pm_proginit(&argc, argv);
 
     argn = 1;
     headerskip = 0;
@@ -54,191 +163,90 @@ int interleave;
     interleave = INT_PIX;
 
     while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
-	{
-	if ( pm_keymatch( argv[argn], "-headerskip", 2 ) )
-	    {
-	    ++argn;
-	    if ( argn >= argc )
-		pm_usage( usage );
-	    headerskip = atoi( argv[argn] );
-	    }
-	else if ( pm_keymatch( argv[argn], "-rowskip", 3 ) )
-	    {
-	    ++argn;
-	    if ( argn >= argc )
-		pm_usage( usage );
-	    rowskip = atoi( argv[argn] );
-	    }
-	else if ( pm_keymatch( argv[argn], "-rgb", 3 ) )
-	    order = ORD_RGB;
-	else if ( pm_keymatch( argv[argn], "-rbg", 3 ) )
-	    order = ORD_RBG;
-	else if ( pm_keymatch( argv[argn], "-grb", 3 ) )
-	    order = ORD_GRB;
-	else if ( pm_keymatch( argv[argn], "-gbr", 3 ) )
-	    order = ORD_GBR;
-	else if ( pm_keymatch( argv[argn], "-brg", 3 ) )
-	    order = ORD_BRG;
-	else if ( pm_keymatch( argv[argn], "-bgr", 3 ) )
-	    order = ORD_BGR;
-	else if ( pm_keymatch( argv[argn], "-interpixel", 7 ) )
-	    interleave = INT_PIX;
-	else if ( pm_keymatch( argv[argn], "-interrow", 7 ) )
-	    interleave = INT_ROW;
-	else
-	    pm_usage( usage );
-	++argn;
-	}
+        {
+        if ( pm_keymatch( argv[argn], "-headerskip", 2 ) )
+            {
+            ++argn;
+            if ( argn >= argc )
+                pm_usage( usage );
+            headerskip = atoi( argv[argn] );
+            }
+        else if ( pm_keymatch( argv[argn], "-rowskip", 3 ) )
+            {
+            ++argn;
+            if ( argn >= argc )
+                pm_usage( usage );
+            rowskip = atoi( argv[argn] );
+            }
+        else if ( pm_keymatch( argv[argn], "-rgb", 3 ) )
+            order = ORD_RGB;
+        else if ( pm_keymatch( argv[argn], "-rbg", 3 ) )
+            order = ORD_RBG;
+        else if ( pm_keymatch( argv[argn], "-grb", 3 ) )
+            order = ORD_GRB;
+        else if ( pm_keymatch( argv[argn], "-gbr", 3 ) )
+            order = ORD_GBR;
+        else if ( pm_keymatch( argv[argn], "-brg", 3 ) )
+            order = ORD_BRG;
+        else if ( pm_keymatch( argv[argn], "-bgr", 3 ) )
+            order = ORD_BGR;
+        else if ( pm_keymatch( argv[argn], "-interpixel", 7 ) )
+            interleave = INT_PIX;
+        else if ( pm_keymatch( argv[argn], "-interrow", 7 ) )
+            interleave = INT_ROW;
+        else
+            pm_usage( usage );
+        ++argn;
+        }
 
     if ( argn + 2 > argc )
-	pm_usage( usage );
-
-    cols = atoi( argv[argn++] );
-    rows = atoi( argv[argn++] );
-    if ( cols <= 0 || rows <= 0 )
-	pm_usage( usage );
+        pm_usage( usage );
+    
+    cols = pm_parse_width(argv[argn++]);
+    rows = pm_parse_height(argv[argn++]);
 
     if ( argn < argc )
-	{
-	ifp = pm_openr( argv[argn] );
-	++argn;
-	}
+        {
+        ifP = pm_openr( argv[argn] );
+        ++argn;
+        }
     else
-	ifp = stdin;
+        ifP = stdin;
 
     if ( argn != argc )
-	pm_usage( usage );
-
-    ppm_writeppminit( stdout, cols, rows, (pixval) 255, 0 );
-    pixrow = ppm_allocrow( cols );
-
-    if ( interleave == INT_ROW )
-	{
-	grow1 = pgm_allocrow( cols );
-	grow2 = pgm_allocrow( cols );
-	grow3 = pgm_allocrow( cols );
-	}
-
-    for ( i = 0; i < headerskip; ++i )
-	{
-	val1 = getc( ifp );
-	if ( val1 == EOF )
-	    pm_error( "EOF / read error" );
-	}
-
-    for ( row = 0; row < rows; ++row)
-	{
-	switch ( interleave )
-	    {
-	    case INT_PIX:
-	    for ( col = 0, pP = pixrow; col < cols; ++col, ++pP )
-		{
-		val1 = getc( ifp );
-		if ( val1 == EOF )
-		    pm_error( "EOF / read error" );
-		val2 = getc( ifp );
-		if ( val2 == EOF )
-		    pm_error( "EOF / read error" );
-		val3 = getc( ifp );
-		if ( val3 == EOF )
-		    pm_error( "EOF / read error" );
-		switch ( order )
-		    {
-		    case ORD_RGB:
-		    PPM_ASSIGN( *pP, val1, val2, val3 );
-		    break;
-		    case ORD_RBG:
-		    PPM_ASSIGN( *pP, val1, val3, val2 );
-		    break;
-		    case ORD_GRB:
-		    PPM_ASSIGN( *pP, val2, val1, val3 );
-		    break;
-		    case ORD_GBR:
-		    PPM_ASSIGN( *pP, val3, val1, val2 );
-		    break;
-		    case ORD_BRG:
-		    PPM_ASSIGN( *pP, val2, val3, val1 );
-		    break;
-		    case ORD_BGR:
-		    PPM_ASSIGN( *pP, val3, val2, val1 );
-		    break;
-		    }
-		}
-	    dorowskip( ifp, rowskip );
-	    break;
-
-	    case INT_ROW:
-	    for ( col = 0, g1P = grow1; col < cols; ++col, ++g1P )
-		{
-		val1 = getc( ifp );
-		if ( val1 == EOF )
-		    pm_error( "EOF / read error" );
-		*g1P = val1;
-		}
-	    dorowskip( ifp, rowskip );
-	    for ( col = 0, g2P = grow2; col < cols; ++col, ++g2P )
-		{
-		val2 = getc( ifp );
-		if ( val2 == EOF )
-		    pm_error( "EOF / read error" );
-		*g2P = val2;
-		}
-	    dorowskip( ifp, rowskip );
-	    for ( col = 0, g3P = grow3; col < cols; ++col, ++g3P )
-		{
-		val3 = getc( ifp );
-		if ( val3 == EOF )
-		    pm_error( "EOF / read error" );
-		*g3P = val3;
-		}
-	    dorowskip( ifp, rowskip );
-	    for ( col = 0, pP = pixrow, g1P = grow1, g2P = grow2, g3P = grow3;
-		  col < cols; ++col, ++pP, ++g1P, ++g2P, ++g3P )
-		{
-		switch ( order )
-		    {
-		    case ORD_RGB:
-		    PPM_ASSIGN( *pP, *g1P, *g2P, *g3P );
-		    break;
-		    case ORD_RBG:
-		    PPM_ASSIGN( *pP, *g1P, *g3P, *g2P );
-		    break;
-		    case ORD_GRB:
-		    PPM_ASSIGN( *pP, *g2P, *g1P, *g3P );
-		    break;
-		    case ORD_GBR:
-		    PPM_ASSIGN( *pP, *g3P, *g1P, *g2P );
-		    break;
-		    case ORD_BRG:
-		    PPM_ASSIGN( *pP, *g2P, *g3P, *g1P );
-		    break;
-		    case ORD_BGR:
-		    PPM_ASSIGN( *pP, *g3P, *g2P, *g1P );
-		    break;
-		    }
-		}
-	    break;
-	    }
-	ppm_writeppmrow( stdout, pixrow, cols, (pixval) 255, 0 );
-	}
-
-    pm_close( ifp );
-    pm_close( stdout );
+        pm_usage( usage );
 
-    exit( 0 );
+    ppm_writeppminit(stdout, cols, rows, (pixval) 255, 0);
+    pixrow = ppm_allocrow(cols);
+
+    if (interleave == INT_ROW) {
+        grow1 = pgm_allocrow(cols);
+        grow2 = pgm_allocrow(cols);
+        grow3 = pgm_allocrow(cols);
     }
 
-static void
-dorowskip( ifp, rowskip )
-    FILE* ifp;
-    int rowskip;
-    {
-    int i, val;
-
-    for ( i = 0; i < rowskip; ++i )
-	{
-	val = getc( ifp );
-	if ( val == EOF )
-	    pm_error( "EOF / read error" );
-	}
+    for (i = 0; i < headerskip; ++i) {
+        int const val = getc(ifP);
+        if (val == EOF)
+            pm_error("EOF / read error");
+    }
+
+    for (row = 0; row < rows; ++row) {
+        switch (interleave) {
+        case INT_PIX:
+            doRowPixInterleave(pixrow, cols, ifP, order, rowskip);
+            break;
+
+        case INT_ROW:
+            doRowRowInterleave(pixrow, cols, ifP, order, rowskip,
+                               grow1, grow2, grow3);
+            break;
+        }
+        ppm_writeppmrow(stdout, pixrow, cols, maxval, 0);
+    }
+
+    pm_close( ifP );
+    pm_close( stdout );
+
+    exit( 0 );
     }
diff --git a/converter/ppm/sldtoppm.c b/converter/ppm/sldtoppm.c
index 6b51f291..ad16a649 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/converter/ppm/tgatoppm.c b/converter/ppm/tgatoppm.c
index 8a559848..f8538214 100644
--- a/converter/ppm/tgatoppm.c
+++ b/converter/ppm/tgatoppm.c
@@ -16,6 +16,8 @@
 #define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
 
 #include <string.h>
+
+#include "pm_c_util.h"
 #include "ppm.h"
 #include "tga.h"
 #include "shhopt.h"
@@ -81,7 +83,7 @@ parseCommandLine(int argc, char ** argv,
                  "is the input file specification");
 
     if (alpha_spec &&
-        STREQ(cmdlineP->alpha_filename, "-"))
+        streq(cmdlineP->alpha_filename, "-"))
         cmdlineP->alpha_stdout = 1;
     else 
         cmdlineP->alpha_stdout = 0;
diff --git a/converter/ppm/winicontoppm.c b/converter/ppm/winicontoppm.c
index 2d9de567..ad859c94 100644
--- a/converter/ppm/winicontoppm.c
+++ b/converter/ppm/winicontoppm.c
@@ -21,6 +21,7 @@
 #include <string.h>
 #include <assert.h>
 
+#include "pm_c_util.h"
 #include "ppm.h"
 #include "shhopt.h"
 #include "nstring.h"
@@ -572,7 +573,7 @@ trimOutputName(const char inputName[])
      * oh, for =~ ... :)
      */
     char * outFile = strdup(inputName);
-    if (STREQ(outFile + (strlen (outFile) - 4), ".ppm")) {
+    if (streq(outFile + (strlen (outFile) - 4), ".ppm")) {
         *(outFile + (strlen (outFile) - 4)) = 0;
     }
     return outFile;
@@ -828,7 +829,7 @@ main(int argc, char *argv[]) {
         pm_message("-bestqual doesn't make sense with -allicons.  "
                    "Ignoring -bestqual.");
    
-    if (STREQ(cmdline.outputFilespec, "-"))
+    if (streq(cmdline.outputFilespec, "-"))
         outputFileBase = NULL;
     else
         outputFileBase = trimOutputName(cmdline.outputFilespec);
diff --git a/converter/ppm/ximtoppm.c b/converter/ppm/ximtoppm.c
index 28c9b674..15589c16 100644
--- a/converter/ppm/ximtoppm.c
+++ b/converter/ppm/ximtoppm.c
@@ -14,6 +14,8 @@
 #define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
 
 #include <string.h>
+
+#include "pm_c_util.h"
 #include "ppm.h"
 #include "xim.h"
 #include "shhopt.h"
@@ -69,7 +71,7 @@ parseCommandLine(int argc, char ** argv,
                  "is the input file specification");
 
     if (cmdlineP->alpha_filename && 
-        STREQ(cmdlineP->alpha_filename, "-"))
+        streq(cmdlineP->alpha_filename, "-"))
         cmdlineP->alpha_stdout = TRUE;
     else 
         cmdlineP->alpha_stdout = FALSE;
diff --git a/converter/ppm/xpmtoppm.c b/converter/ppm/xpmtoppm.c
index bb6a7a0d..235c3867 100644
--- a/converter/ppm/xpmtoppm.c
+++ b/converter/ppm/xpmtoppm.c
@@ -33,6 +33,7 @@
 
 #include <string.h>
 
+#include "pm_c_util.h"
 #include "ppm.h"
 #include "shhopt.h"
 #include "nstring.h"
@@ -104,7 +105,7 @@ parse_command_line(int argc, char ** argv,
                  "is the input file specification");
 
     if (cmdline_p->alpha_filename && 
-        STREQ(cmdline_p->alpha_filename, "-"))
+        streq(cmdline_p->alpha_filename, "-"))
         cmdline_p->alpha_stdout = TRUE;
     else 
         cmdline_p->alpha_stdout = FALSE;
@@ -293,7 +294,7 @@ interpretXpm3ColorTableLine(char line[], int const seqNum,
                number if so)
             */
             for (key = 1; 
-                 key <= NKEYS && !STREQ(xpmColorKeys[key - 1], str2); 
+                 key <= NKEYS && !streq(xpmColorKeys[key - 1], str2); 
                  key++);
             isKey = (key <= NKEYS);
 
@@ -484,15 +485,15 @@ readXpm1Header(FILE * const stream, int * const widthP, int * const heightP,
                 t1 = str1;
             else
                 ++t1;
-            if (STREQ(t1, "format"))
+            if (streq(t1, "format"))
                 format = v;
-            else if (STREQ(t1, "width"))
+            else if (streq(t1, "width"))
                 *widthP = v;
-            else if (STREQ(t1, "height"))
+            else if (streq(t1, "height"))
                 *heightP = v;
-            else if (STREQ(t1, "ncolors"))
+            else if (streq(t1, "ncolors"))
                 *ncolorsP = v;
-            else if (STREQ(t1, "pixel"))
+            else if (streq(t1, "pixel"))
                 *chars_per_pixelP = v;
         } else if (!strncmp(line, "static char", 11)) {
             if ((t1 = strrchr(line, '_')) == NULL)
diff --git a/converter/ppm/xvminitoppm.c b/converter/ppm/xvminitoppm.c
index 935ab177..d76bea87 100644
--- a/converter/ppm/xvminitoppm.c
+++ b/converter/ppm/xvminitoppm.c
@@ -12,6 +12,7 @@
 
 #include <assert.h>
 #include <string.h>
+#include <errno.h>
 
 #include "pm_c_util.h"
 #include "nstring.h"
@@ -61,7 +62,8 @@ getLine(FILE * const ifP,
     rc = fgets(buf, size, ifP);
     if (rc == NULL) {
         if (ferror(ifP))
-            pm_perror("read error");
+            pm_error("read error.  fgets() failed, errno=%d (%s)",
+                     errno, strerror(errno));
         else
             pm_error("unexpected EOF");
     }
@@ -107,16 +109,16 @@ readXvHeader(FILE *         const ifP,
     
     getLine(ifP, buf, sizeof(buf));
 
-    if (!STRNEQ(buf, "P7 332", 6))
+    if (!strneq(buf, "P7 332", 6))
         pm_error("Input is not a XV thumbnail picture.  It does not "
                  "begin with the characters 'P7 332'.");
 
     endOfComments = FALSE;
     while (!endOfComments) {
         getLine(ifP, buf, sizeof(buf));
-        if (STRNEQ(buf, "#END_OF_COMMENTS", 16))
+        if (strneq(buf, "#END_OF_COMMENTS", 16))
             endOfComments = TRUE;
-        else if (STRNEQ(buf, "#BUILTIN", 8))
+        else if (strneq(buf, "#BUILTIN", 8))
             pm_error("This program does not know how to "
                      "convert builtin XV thumbnail pictures");
     }
diff --git a/converter/ppm/yuvsplittoppm.c b/converter/ppm/yuvsplittoppm.c
index 0f5e19a3..b3088812 100644
--- a/converter/ppm/yuvsplittoppm.c
+++ b/converter/ppm/yuvsplittoppm.c
@@ -20,6 +20,8 @@
 */
 
 #include <string.h>
+
+#include "pm_c_util.h"
 #include "ppm.h"
 #include "nstring.h"
 #include "shhopt.h"