about summary refs log tree commit diff
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2023-06-28 17:29:32 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2023-06-28 17:29:32 +0000
commit23ce26f64c34e30951ad9ade2151552ed77e7357 (patch)
treed73b31a0c2f7c7be4a69f8a8e84e00dd39c432b5
parent1b6e51a266008348ad93ed8b6ac9ec91b5024fea (diff)
downloadnetpbm-mirror-23ce26f64c34e30951ad9ade2151552ed77e7357.tar.gz
netpbm-mirror-23ce26f64c34e30951ad9ade2151552ed77e7357.tar.xz
netpbm-mirror-23ce26f64c34e30951ad9ade2151552ed77e7357.zip
promote Advanced to Stable
git-svn-id: http://svn.code.sf.net/p/netpbm/code/stable@4558 9d0c8265-081b-0410-96cb-a4ca84ce46f8
-rw-r--r--GNUmakefile41
-rw-r--r--analyzer/pamfind.c93
-rw-r--r--analyzer/pamgetcolor.c6
-rw-r--r--analyzer/pamsumm.c4
-rw-r--r--analyzer/pamtable.c85
-rw-r--r--analyzer/pamtilt.c13
-rw-r--r--analyzer/pgmtexture.c101
-rw-r--r--analyzer/pnmpsnr.c2
-rw-r--r--analyzer/ppmhist.c44
-rw-r--r--buildtools/README.pkg2
-rwxr-xr-xbuildtools/configure.pl277
-rw-r--r--buildtools/debian/README34
-rwxr-xr-xbuildtools/debian/mkdeb42
-rwxr-xr-xbuildtools/installnetpbm.pl2
-rwxr-xr-xbuildtools/makeman58
-rw-r--r--common.mk6
-rw-r--r--config.mk.in12
-rw-r--r--converter/other/Makefile34
-rw-r--r--converter/other/cameratopam/Makefile2
-rw-r--r--converter/other/cameratopam/camera.c245
-rw-r--r--converter/other/cameratopam/cameratopam.c2
-rw-r--r--converter/other/cameratopam/canon.c24
-rw-r--r--converter/other/cameratopam/foveon.c102
-rw-r--r--converter/other/cameratopam/identify.c49
-rw-r--r--converter/other/cameratopam/ljpeg.c16
-rw-r--r--converter/other/cameratopam/stdio_nofail.c120
-rw-r--r--converter/other/cameratopam/stdio_nofail.h29
-rw-r--r--converter/other/cameratopam/util.c34
-rw-r--r--converter/other/fiasco/codec/coder.c142
-rw-r--r--converter/other/fiasco/codec/cwfa.h2
-rw-r--r--converter/other/fiasco/codec/dfiasco.c40
-rw-r--r--converter/other/fiasco/codec/ip.c76
-rw-r--r--converter/other/fiasco/codec/prediction.c114
-rw-r--r--converter/other/fiasco/codec/subdivide.c124
-rw-r--r--converter/other/fiasco/codec/wfa.h8
-rw-r--r--converter/other/fiasco/doc/fiasco_c_options_new.35
-rw-r--r--converter/other/fiasco/doc/fiasco_coder.32
-rw-r--r--converter/other/fiasco/doc/fiasco_d_options_new.34
-rw-r--r--converter/other/fiasco/doc/fiasco_decoder_new.316
-rw-r--r--converter/other/fiasco/doc/fiasco_get_error_message.36
-rw-r--r--converter/other/fiasco/doc/fiasco_image_new.36
-rw-r--r--converter/other/fiasco/doc/fiasco_options_new.34
-rw-r--r--converter/other/fiasco/doc/fiasco_renderer_new.32
-rw-r--r--converter/other/fiasco/input/basis.c33
-rw-r--r--converter/other/fiasco/input/matrices.c80
-rw-r--r--converter/other/fiasco/input/mc.c61
-rw-r--r--converter/other/fiasco/input/nd.c31
-rw-r--r--converter/other/fiasco/input/read.c91
-rw-r--r--converter/other/fiasco/input/tree.c46
-rw-r--r--converter/other/fiasco/lib/arith.c130
-rw-r--r--converter/other/fiasco/lib/bit-io.c56
-rw-r--r--converter/other/fiasco/lib/image.c58
-rw-r--r--converter/other/fiasco/lib/image.h2
-rw-r--r--converter/other/fiasco/lib/macros.h2
-rw-r--r--converter/other/fiasco/output/mc.c40
-rw-r--r--converter/other/fiasco/output/nd.c38
-rw-r--r--converter/other/fiasco/output/tree.c18
-rw-r--r--converter/other/fiasco/params.c94
-rw-r--r--converter/other/fiasco/pnmtofiasco.c77
-rw-r--r--converter/other/fitstopnm.c210
-rw-r--r--converter/other/gemtopnm.c2
-rw-r--r--converter/other/giftopnm.c4
-rw-r--r--converter/other/infotopam.c33
-rw-r--r--converter/other/ipdb.c222
-rw-r--r--converter/other/ipdb.h23
-rw-r--r--converter/other/jbig/libjbig/include/jbig_ar.h4
-rw-r--r--converter/other/jbig/libjbig/jbig.c10
-rw-r--r--converter/other/jpeg2000/Makefile6
-rw-r--r--converter/other/jpeg2000/jpeg2ktopam.c34
-rw-r--r--converter/other/jpeg2000/libjasper/base/jas_image.c74
-rw-r--r--converter/other/jpeg2000/libjasper/base/jas_stream.c31
-rw-r--r--converter/other/jpeg2000/libjasper/include/jasper/jas_image.h27
-rw-r--r--converter/other/jpeg2000/libjasper/jp2/jp2_dec.c93
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_dec.c1085
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_dec.h2
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_enc.c1377
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_enc.h2
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_math.c2
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.c31
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.c1566
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.h14
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_t1enc.c163
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_util.c71
-rw-r--r--converter/other/jpeg2000/libjasper_compat.c26
-rw-r--r--converter/other/jpeg2000/libjasper_compat.h35
-rw-r--r--converter/other/jpeg2000/pamtojpeg2k.c29
-rw-r--r--converter/other/jpegtopnm.c604
-rw-r--r--converter/other/pamtofits.c19
-rw-r--r--converter/other/pamtogif.c55
-rw-r--r--converter/other/pamtopdbimg.c93
-rw-r--r--converter/other/pamtopng.c8
-rw-r--r--converter/other/pamtoqoi.c439
-rw-r--r--converter/other/pamtosvg/fit.c148
-rw-r--r--converter/other/pamtotiff.c2
-rw-r--r--converter/other/pamtowinicon.c50
-rw-r--r--converter/other/pamtoxvmini.c77
-rw-r--r--converter/other/pbmtopgm.c37
-rw-r--r--converter/other/pdbimgtopam.c127
-rw-r--r--converter/other/pgmtopbm.c122
-rw-r--r--converter/other/pgmtoppm.c156
-rw-r--r--converter/other/pngtopam.c26
-rw-r--r--converter/other/pngx.c22
-rw-r--r--converter/other/pnmtoddif.c4
-rw-r--r--converter/other/pnmtojpeg.c163
-rw-r--r--converter/other/pnmtopalm/README2
-rw-r--r--converter/other/pnmtopalm/palmtopnm.c28
-rw-r--r--converter/other/pnmtopalm/pnmtopalm.c281
-rw-r--r--converter/other/pnmtopng.c94
-rw-r--r--converter/other/pnmtops.c198
-rw-r--r--converter/other/pnmtorle.c290
-rw-r--r--converter/other/pnmtosir.c35
-rw-r--r--converter/other/pstopnm.c55
-rwxr-xr-xconverter/other/pstopnm.csh2
-rw-r--r--converter/other/qoi.h101
-rw-r--r--converter/other/qoitopam.c323
-rw-r--r--converter/other/rlatopam.c23
-rw-r--r--converter/other/rletopnm.c78
-rw-r--r--converter/other/sunicontopnm.c12
-rw-r--r--converter/other/tifftopnm.c235
-rw-r--r--converter/other/winicon.h3
-rw-r--r--converter/other/winicontopam.c149
-rw-r--r--converter/other/xwdtopnm.c217
-rw-r--r--converter/other/yuy2topam.c8
-rw-r--r--converter/pbm/atktopbm.c34
-rw-r--r--converter/pbm/escp2topbm.c18
-rw-r--r--converter/pbm/g3topbm.c11
-rw-r--r--converter/pbm/mdatopbm.c2
-rw-r--r--converter/pbm/mgrtopbm.c30
-rw-r--r--converter/pbm/pbmtoatk.c31
-rw-r--r--converter/pbm/pbmtoescp2.c23
-rw-r--r--converter/pbm/pbmtogem.c2
-rw-r--r--converter/pbm/pbmtogo.c72
-rw-r--r--converter/pbm/pbmtoibm23xx.c6
-rw-r--r--converter/pbm/pbmtolps.c378
-rw-r--r--converter/pbm/pbmtomacp.c2
-rw-r--r--converter/pbm/pbmtomgr.c14
-rw-r--r--converter/pbm/pbmtonokia.c87
-rw-r--r--converter/pbm/pbmtopk.c120
-rw-r--r--converter/pbm/pbmtoppa/README.REDHAT2
-rw-r--r--converter/pbm/pbmtoppa/ppa.c10
-rw-r--r--converter/pbm/pbmtoptx.c11
-rw-r--r--converter/pbm/pbmtox10bm15
-rw-r--r--converter/pbm/xbmtopbm.c36
-rw-r--r--converter/pbm/ybmtopbm.c6
-rw-r--r--converter/pgm/rawtopgm.c174
-rw-r--r--converter/pgm/st4topgm.c8
-rw-r--r--converter/ppm/hpcdtoppm/Makefile22
-rw-r--r--converter/ppm/hpcdtoppm/README37
-rwxr-xr-xconverter/ppm/hpcdtoppm/hpcdtoppm18
-rwxr-xr-xconverter/ppm/hpcdtoppm/pcdovtoppm172
-rw-r--r--converter/ppm/ilbm.h92
-rw-r--r--converter/ppm/ilbmtoppm.c4
-rw-r--r--converter/ppm/picttoppm.c2265
-rw-r--r--converter/ppm/pjtoppm.c2
-rw-r--r--converter/ppm/ppmtoapplevol.c2
-rw-r--r--converter/ppm/ppmtoarbtxt.c2
-rw-r--r--converter/ppm/ppmtobmp.c2
-rw-r--r--converter/ppm/ppmtoilbm.c210
-rw-r--r--converter/ppm/ppmtomitsu.c2
-rw-r--r--converter/ppm/ppmtompeg/LOGIC2
-rw-r--r--converter/ppm/ppmtompeg/Makefile2
-rw-r--r--converter/ppm/ppmtompeg/bsearch.c58
-rw-r--r--converter/ppm/ppmtompeg/docs/template.param2
-rw-r--r--converter/ppm/ppmtompeg/examples/payam.param2
-rw-r--r--converter/ppm/ppmtompeg/examples/payam18.param2
-rw-r--r--converter/ppm/ppmtompeg/examples/template.param2
-rw-r--r--converter/ppm/ppmtompeg/frame.c68
-rw-r--r--converter/ppm/ppmtompeg/frametype.c39
-rw-r--r--converter/ppm/ppmtompeg/jpeg.c230
-rw-r--r--converter/ppm/ppmtompeg/mheaders.c4
-rw-r--r--converter/ppm/ppmtompeg/mpeg.c241
-rw-r--r--converter/ppm/ppmtompeg/opts.c110
-rw-r--r--converter/ppm/ppmtompeg/parallel.c379
-rw-r--r--converter/ppm/ppmtompeg/param.c83
-rw-r--r--converter/ppm/ppmtompeg/parse_huff.pl2
-rw-r--r--converter/ppm/ppmtompeg/psearch.c2
-rw-r--r--converter/ppm/ppmtompeg/psocket.c63
-rw-r--r--converter/ppm/ppmtompeg/rate.c192
-rw-r--r--converter/ppm/ppmtompeg/readframe.c103
-rw-r--r--converter/ppm/ppmtompeg/specifics.c74
-rw-r--r--converter/ppm/ppmtopcx.c584
-rw-r--r--converter/ppm/ppmtospu.c2
-rw-r--r--converter/ppm/sldtoppm.c2
-rw-r--r--converter/ppm/xim.h14
-rw-r--r--converter/ppm/ximtoppm.c93
-rw-r--r--converter/ppm/xpmtoppm.README2
-rw-r--r--converter/ppm/xpmtoppm.c8
-rw-r--r--doc/COPYRIGHT.PATENT9
-rw-r--r--doc/HISTORY490
-rw-r--r--doc/INSTALL33
-rw-r--r--doc/TESTS35
-rw-r--r--doc/copyright_summary2
-rw-r--r--doc/patent_summary9
-rw-r--r--editor/Makefile33
-rw-r--r--editor/pamaddnoise.c644
-rw-r--r--editor/pamaltsat.c10
-rw-r--r--editor/pambackground.c52
-rw-r--r--editor/pamcat.c1461
-rw-r--r--editor/pamcomp.c436
-rw-r--r--editor/pamcut.c120
-rw-r--r--editor/pamdice.c158
-rw-r--r--editor/pamditherbw.c429
-rw-r--r--editor/pamenlarge.c1
-rw-r--r--editor/pamflip/pamflip.c2
-rw-r--r--editor/pamfunc.c28
-rw-r--r--editor/pamhomography.c799
-rw-r--r--editor/pamlevels.c3
-rw-r--r--editor/pammixmulti.c88
-rw-r--r--editor/pamperspective.c2
-rw-r--r--editor/pamrecolor.c50
-rw-r--r--editor/pamrestack.c472
-rw-r--r--editor/pamrubber.c638
-rw-r--r--editor/pamshuffle.c155
-rw-r--r--editor/pamsistoaglyph.c3
-rwxr-xr-xeditor/pamstretch-gen6
-rw-r--r--editor/pamthreshold.c31
-rw-r--r--editor/pamundice.c459
-rw-r--r--editor/pbmclean.c8
-rw-r--r--editor/pbmpscale.c30
-rw-r--r--editor/pbmreduce.c49
-rw-r--r--editor/pgmmedian.c311
-rw-r--r--editor/pnmcat.c872
-rw-r--r--editor/pnmconvol.c6
-rw-r--r--editor/pnmcrop.c174
-rwxr-xr-xeditor/pnmflip10
-rw-r--r--editor/pnmgamma.c2
-rwxr-xr-xeditor/pnmindex.csh189
-rwxr-xr-xeditor/pnmindex.sh214
-rwxr-xr-xeditor/pnmmargin6
-rw-r--r--editor/pnmnlfilt.c113
-rw-r--r--editor/pnmnorm.c158
-rw-r--r--editor/pnmpad.c60
-rwxr-xr-xeditor/pnmquant77
-rwxr-xr-xeditor/pnmquantall24
-rw-r--r--editor/pnmremap.c26
-rw-r--r--editor/pnmshear.c74
-rw-r--r--editor/pnmstitch.c12
-rwxr-xr-xeditor/ppmbrighten60
-rw-r--r--editor/ppmbrighten.c218
-rwxr-xr-xeditor/ppmfade146
-rwxr-xr-xeditor/ppmshadow4
-rw-r--r--editor/specialty/pampaintspill.c172
-rw-r--r--editor/specialty/pampop9.c3
-rw-r--r--editor/specialty/pgmabel.c18
-rw-r--r--editor/specialty/pnmindex.c106
-rw-r--r--editor/specialty/ppmshift.c235
-rw-r--r--editor/specialty/ppmspread.c206
-rw-r--r--generator/Makefile2
-rw-r--r--generator/pamcrater.c60
-rw-r--r--generator/pamseq.c319
-rw-r--r--generator/pamstereogram.c398
-rw-r--r--generator/pamtris/boundaries.c2
-rw-r--r--generator/pamtris/framebuffer.c4
-rw-r--r--generator/pbmnoise.c485
-rw-r--r--generator/pbmpage.c392
-rw-r--r--generator/pbmtext.c436
-rw-r--r--generator/pbmtextps.c450
-rwxr-xr-xgenerator/pgmcrater12
-rw-r--r--generator/pgmnoise.c145
-rw-r--r--generator/ppmforge.c422
-rw-r--r--generator/ppmmake.c6
-rw-r--r--generator/ppmpat.c648
-rwxr-xr-xgenerator/ppmrainbow37
-rw-r--r--generator/ppmrough.c510
-rw-r--r--lib/Makefile33
-rw-r--r--lib/fileio.h6
-rw-r--r--lib/libpam.c172
-rw-r--r--lib/libpamcolor.c6
-rw-r--r--lib/libpamd.c210
-rw-r--r--lib/libpammap.c116
-rw-r--r--lib/libpamwrite.c273
-rw-r--r--lib/libpbm2.c4
-rw-r--r--lib/libpbm3.c2
-rw-r--r--lib/libpbmfont0.c87
-rw-r--r--lib/libpbmfont1.c71
-rw-r--r--lib/libpbmfont2.c538
-rw-r--r--lib/libpm.c9
-rw-r--r--lib/libpnm2.c61
-rw-r--r--lib/libpnm3.c6
-rw-r--r--lib/libppmcmap.c113
-rw-r--r--lib/libppmd.c309
-rw-r--r--lib/libppmfloyd.c271
-rw-r--r--lib/libsystem.c38
-rw-r--r--lib/pam.h75
-rw-r--r--lib/pammap.h20
-rw-r--r--lib/pbm.h45
-rw-r--r--lib/pbmfont.h93
-rw-r--r--lib/pbmfontdata2.c2
-rw-r--r--lib/pm.h13
-rw-r--r--lib/pm_system.h7
-rw-r--r--lib/pmfileio.c229
-rw-r--r--lib/pnm.h11
-rw-r--r--lib/ppmcmap.h70
-rw-r--r--lib/ppmfloyd.h69
-rw-r--r--lib/util/LICENSE.txt2
-rw-r--r--lib/util/Makefile4
-rw-r--r--lib/util/mallocvar.h60
-rw-r--r--lib/util/nstring.c818
-rw-r--r--lib/util/nstring.h29
-rw-r--r--lib/util/rand.c294
-rw-r--r--lib/util/rand.h112
-rw-r--r--lib/util/randmersenne.c192
-rw-r--r--lib/util/randsysrand.c39
-rw-r--r--lib/util/randsysrandom.c45
-rw-r--r--lib/util/runlength.c18
-rw-r--r--lib/util/shhopt.README18
-rw-r--r--lib/util/shhopt.c115
-rw-r--r--lib/util/shhopt.h62
-rw-r--r--other/Makefile6
-rw-r--r--other/pamarith.c493
-rw-r--r--other/pambayer.c229
-rw-r--r--other/pamdepth.c23
-rw-r--r--other/pamendian.c51
-rw-r--r--other/pamexec.c77
-rw-r--r--other/pamfix.c2
-rw-r--r--other/pamunlookup.c27
-rw-r--r--other/pamx/Makefile8
-rw-r--r--other/pamx/window.c85
-rw-r--r--other/pnmcolormap.c699
-rw-r--r--pm_config.in.h10
-rwxr-xr-xtest/411toppm.test2
-rwxr-xr-xtest/Available-Testprog8
-rwxr-xr-xtest/Execute-Tests25
-rw-r--r--test/Makefile21
-rw-r--r--test/Test-Order80
-rw-r--r--test/all-in-place.ok12
-rwxr-xr-xtest/all-in-place.test14
-rwxr-xr-xtest/atari-roundtrip.test2
-rw-r--r--test/atk-roundtrip.ok8
-rwxr-xr-xtest/atk-roundtrip.test24
-rwxr-xr-xtest/avs-roundtrip.test2
-rwxr-xr-xtest/bmp-quant-roundtrip.test2
-rw-r--r--test/bmp-roundtrip.ok14
-rwxr-xr-xtest/bmp-roundtrip.test16
-rw-r--r--test/channel-stack-roundtrip.ok11
-rwxr-xr-xtest/channel-stack-roundtrip.test34
-rw-r--r--test/cis-roundtrip.ok5
-rwxr-xr-xtest/cis-roundtrip.test18
-rw-r--r--test/cmuw-roundtrip.ok3
-rwxr-xr-xtest/cmuw-roundtrip.test7
-rw-r--r--test/cut-cat-roundtrip.ok146
-rwxr-xr-xtest/cut-cat-roundtrip.test181
-rwxr-xr-xtest/cut-paste-roundtrip.test3
-rwxr-xr-xtest/enlarge-reduce-roundtrip.test2
-rwxr-xr-xtest/eyuvtoppm.test2
-rwxr-xr-xtest/facesaver-roundtrip.test2
-rwxr-xr-xtest/fiasco-roundtrip.test2
-rwxr-xr-xtest/fits-roundtrip.test2
-rw-r--r--test/g3-roundtrip.ok9
-rwxr-xr-xtest/g3-roundtrip.test43
-rw-r--r--test/gem-roundtrip.ok2
-rwxr-xr-xtest/gem-roundtrip.test6
-rw-r--r--test/gif-roundtrip.ok24
-rwxr-xr-xtest/gif-roundtrip.test90
-rw-r--r--test/gif-transparent1.ok99
-rwxr-xr-xtest/gif-transparent1.test224
-rwxr-xr-xtest/hdiff-roundtrip.test2
-rw-r--r--test/ilbm-roundtrip.ok16
-rwxr-xr-xtest/ilbm-roundtrip.test62
-rw-r--r--test/jbig-roundtrip.ok2
-rwxr-xr-xtest/jbig-roundtrip.test6
-rwxr-xr-xtest/jpeg-roundtrip.test2
-rwxr-xr-xtest/jpeg2k-roundtrip.test2
-rwxr-xr-xtest/leaf-roundtrip.test2
-rw-r--r--test/legacy-names.ok5
-rwxr-xr-xtest/legacy-names.test9
-rwxr-xr-xtest/lookup-roundtrip.test4
-rw-r--r--test/lps-roundtrip.ok4
-rwxr-xr-xtest/lps-roundtrip.test33
-rw-r--r--test/macp-roundtrip.ok13
-rwxr-xr-xtest/macp-roundtrip.test46
-rw-r--r--test/maze.pbmbin0 -> 481 bytes
-rw-r--r--test/mda-roundtrip.ok5
-rwxr-xr-xtest/mda-roundtrip.test14
-rw-r--r--test/mgr-roundtrip.ok8
-rwxr-xr-xtest/mgr-roundtrip.test16
-rw-r--r--test/mrf-roundtrip.ok2
-rwxr-xr-xtest/mrf-roundtrip.test6
-rw-r--r--test/pad-crop-roundtrip.ok4
-rwxr-xr-xtest/pad-crop-roundtrip.test25
-rw-r--r--test/palm-roundtrip.ok14
-rwxr-xr-xtest/palm-roundtrip.test10
-rwxr-xr-xtest/palm-roundtrip2.test2
-rw-r--r--test/pamarith-compare-equal.ok74
-rwxr-xr-xtest/pamarith-compare-equal.test92
-rw-r--r--test/pamarith-multiple-input.ok66
-rwxr-xr-xtest/pamarith-multiple-input.test61
-rw-r--r--test/pamarith.ok277
-rwxr-xr-xtest/pamarith.test378
-rwxr-xr-xtest/pambackground.test2
-rw-r--r--test/pambrighten.ok96
-rwxr-xr-xtest/pambrighten.test99
-rw-r--r--test/pamcat1.ok150
-rwxr-xr-xtest/pamcat1.test271
-rw-r--r--test/pamcat2.ok93
-rwxr-xr-xtest/pamcat2.test64
-rw-r--r--test/pamcat3.ok19
-rwxr-xr-xtest/pamcat3.test97
-rw-r--r--test/pamchannel.ok9
-rwxr-xr-xtest/pamchannel.test48
-rw-r--r--test/pamcrater.ok7
-rwxr-xr-xtest/pamcrater.test47
-rw-r--r--test/pamcut.ok37
-rwxr-xr-xtest/pamcut.test129
-rw-r--r--test/pamdepth-roundtrip.ok2
-rwxr-xr-xtest/pamdepth-roundtrip.test4
-rw-r--r--test/pamdepth.ok14
-rwxr-xr-xtest/pamdepth.test40
-rw-r--r--test/pamdice-roundtrip.ok15
-rwxr-xr-xtest/pamdice-roundtrip.test62
-rw-r--r--test/pamdice.ok26
-rwxr-xr-xtest/pamdice.test79
-rwxr-xr-xtest/pamditherbw-random.ok6
-rwxr-xr-xtest/pamditherbw-random.test23
-rw-r--r--test/pamditherbw.ok24
-rwxr-xr-xtest/pamditherbw.test101
-rwxr-xr-xtest/pamedge.test2
-rw-r--r--test/pamendian-roundtrip.ok5
-rwxr-xr-xtest/pamendian-roundtrip.test26
-rwxr-xr-xtest/pamenlarge-pamscale-point.test4
-rwxr-xr-xtest/pamenlarge-pbm.test32
-rw-r--r--test/pamenlarge.ok8
-rwxr-xr-xtest/pamenlarge.test15
-rw-r--r--test/pamexec-roundtrip.ok10
-rwxr-xr-xtest/pamexec-roundtrip.test25
-rw-r--r--test/pamexec.ok10
-rwxr-xr-xtest/pamexec.test42
-rw-r--r--test/pamfile.ok7
-rwxr-xr-xtest/pamfile.test32
-rw-r--r--test/pamfind.ok181
-rwxr-xr-xtest/pamfind.test44
-rw-r--r--test/pamfix.ok68
-rwxr-xr-xtest/pamfix.test69
-rw-r--r--test/pamflip-pbm-roundtrip.ok122
-rwxr-xr-xtest/pamflip-pbm-roundtrip.test74
-rw-r--r--test/pamflip-roundtrip.ok77
-rwxr-xr-xtest/pamflip-roundtrip.test142
-rw-r--r--test/pamflip1.ok13
-rwxr-xr-xtest/pamflip1.test26
-rw-r--r--test/pamflip2.ok9
-rwxr-xr-xtest/pamflip2.test16
-rw-r--r--test/pamfunc.ok70
-rwxr-xr-xtest/pamfunc.test213
-rw-r--r--test/pamgauss.ok10
-rwxr-xr-xtest/pamgauss.test59
-rw-r--r--test/pamhue-roundtrip.ok10
-rwxr-xr-xtest/pamhue-roundtrip.test19
-rw-r--r--test/pamhue.ok36
-rwxr-xr-xtest/pamhue.test48
-rwxr-xr-xtest/pammixmulti-identity.test2
-rwxr-xr-xtest/pamrecolor.ok11
-rwxr-xr-xtest/pamrecolor.test62
-rw-r--r--test/pamrestack.ok68
-rwxr-xr-xtest/pamrestack.test91
-rwxr-xr-xtest/pamscale-filters1.test6
-rwxr-xr-xtest/pamscale-filters2.test6
-rw-r--r--test/pamscale-filters3.ok1
-rwxr-xr-xtest/pamscale-filters3.test7
-rw-r--r--test/pamscale-reportonly.ok14
-rwxr-xr-xtest/pamscale-reportonly.test59
-rw-r--r--test/pamseq.ok6
-rwxr-xr-xtest/pamseq.test38
-rwxr-xr-xtest/pamshuffle.ok19
-rwxr-xr-xtest/pamshuffle.test67
-rw-r--r--test/pamslice-roundtrip.ok13
-rwxr-xr-xtest/pamslice-roundtrip.test80
-rwxr-xr-xtest/pamstretch.test9
-rw-r--r--test/pamsumm.ok12
-rwxr-xr-xtest/pamsumm.test43
-rw-r--r--test/pamtable.ok60
-rwxr-xr-xtest/pamtable.test62
-rw-r--r--test/pamtopam.ok40
-rwxr-xr-xtest/pamtopam.test23
-rwxr-xr-xtest/pamtopdbimg.test8
-rw-r--r--test/pamundice.ok27
-rwxr-xr-xtest/pamundice.test202
-rw-r--r--test/pamvalidate.ok13
-rwxr-xr-xtest/pamvalidate.test20
-rw-r--r--test/pbm-misc-converters.ok83
-rwxr-xr-xtest/pbm-misc-converters.test118
-rw-r--r--test/pbm-ppm-roundtrip.ok39
-rwxr-xr-xtest/pbm-ppm-roundtrip.test34
-rw-r--r--test/pbmclean.ok15
-rwxr-xr-xtest/pbmclean.test44
-rwxr-xr-xtest/pbmlife.ok63
-rwxr-xr-xtest/pbmlife.test13
-rw-r--r--test/pbmmake.ok11
-rwxr-xr-xtest/pbmmake.test83
-rw-r--r--test/pbmminkowski.ok8
-rwxr-xr-xtest/pbmminkowski.test9
-rw-r--r--test/pbmnoise-parameters.ok26
-rwxr-xr-xtest/pbmnoise-parameters.test143
-rw-r--r--test/pbmnoise1.ok50
-rwxr-xr-xtest/pbmnoise1.test38
-rw-r--r--test/pbmnoise2.ok19
-rwxr-xr-xtest/pbmnoise2.test85
-rw-r--r--test/pbmpage.ok6
-rwxr-xr-xtest/pbmpage.test35
-rw-r--r--test/pbmpscale.ok226
-rwxr-xr-xtest/pbmpscale.test55
-rw-r--r--test/pbmtext-bdf.ok3
-rwxr-xr-xtest/pbmtext-bdf.test14
-rw-r--r--test/pbmtext-iso88591.ok6
-rwxr-xr-xtest/pbmtext-iso88591.test71
-rw-r--r--test/pbmtext-utf8.ok20
-rwxr-xr-xtest/pbmtext-utf8.test194
-rw-r--r--test/pbmtext.ok23
-rwxr-xr-xtest/pbmtext.test113
-rw-r--r--test/pbmtextps-dump.ok88
-rwxr-xr-xtest/pbmtextps-dump.test136
-rw-r--r--test/pbmtextps.ok18
-rwxr-xr-xtest/pbmtextps.test55
-rw-r--r--test/pbmtog3.ok18
-rwxr-xr-xtest/pbmtog3.test39
-rw-r--r--test/pbmtopgm.ok25
-rwxr-xr-xtest/pbmtopgm.test38
-rw-r--r--test/pbmupc.ok11
-rwxr-xr-xtest/pbmupc.test58
-rw-r--r--test/pcx-roundtrip.ok6
-rwxr-xr-xtest/pcx-roundtrip.test16
-rw-r--r--test/pdb-roundtrip.ok8
-rwxr-xr-xtest/pdb-roundtrip.test30
-rwxr-xr-xtest/pfm-roundtrip.test2
-rwxr-xr-xtest/pgmbentley.test2
-rw-r--r--test/pgmhist.ok22
-rwxr-xr-xtest/pgmhist.test45
-rw-r--r--test/pgmmake.ok10
-rwxr-xr-xtest/pgmmake.test54
-rw-r--r--test/pgmminkowski.ok17
-rwxr-xr-xtest/pgmminkowski.test10
-rw-r--r--test/pgmnoise-parameters.ok5
-rwxr-xr-xtest/pgmnoise-parameters.test36
-rw-r--r--test/pgmnoise.ok102
-rw-r--r--test/pgmnoise.rand-ok3
-rwxr-xr-xtest/pgmnoise.test129
-rw-r--r--test/pgmramp.ok9
-rwxr-xr-xtest/pgmramp.test34
-rw-r--r--test/pgmtopgm.ok12
-rwxr-xr-xtest/pgmtopgm.test12
-rw-r--r--test/pgmtoppm.ok36
-rwxr-xr-xtest/pgmtoppm.test139
-rw-r--r--test/pi3-roundtrip.ok5
-rwxr-xr-xtest/pi3-roundtrip.test17
-rwxr-xr-xtest/pict-roundtrip.test2
-rw-r--r--test/pj-roundtrip.ok4
-rwxr-xr-xtest/pj-roundtrip.test26
-rw-r--r--test/png-roundtrip.ok36
-rwxr-xr-xtest/png-roundtrip.test6
-rw-r--r--test/png-roundtrip2.ok4
-rwxr-xr-xtest/png-roundtrip2.test6
-rw-r--r--test/pnm-pam-roundtrip.ok2
-rwxr-xr-xtest/pnm-pam-roundtrip.test4
-rw-r--r--test/pnm-plain-roundtrip.ok2
-rwxr-xr-xtest/pnm-plain-roundtrip.test4
-rw-r--r--test/pnmcat.ok102
-rwxr-xr-xtest/pnmcat.test186
-rw-r--r--test/pnmcolormap.ok40
-rwxr-xr-xtest/pnmcolormap.test80
-rw-r--r--test/pnmcolormap2.ok9
-rwxr-xr-xtest/pnmcolormap2.test55
-rw-r--r--test/pnmcrop-blank.ok130
-rwxr-xr-xtest/pnmcrop-blank.test55
-rw-r--r--test/pnmcrop1.ok82
-rwxr-xr-xtest/pnmcrop1.test84
-rw-r--r--test/pnmcrop2.ok29
-rwxr-xr-xtest/pnmcrop2.test55
-rw-r--r--test/pnmcrop3.ok90
-rwxr-xr-xtest/pnmcrop3.test80
-rw-r--r--test/pnminvert-roundtrip.ok2
-rwxr-xr-xtest/pnminvert-roundtrip.test4
-rw-r--r--test/pnminvert.ok7
-rwxr-xr-xtest/pnminvert.test19
-rw-r--r--test/pnmpad-reportonly.ok67
-rwxr-xr-xtest/pnmpad-reportonly.test129
-rwxr-xr-xtest/pnmpaste-pbm.test2
-rw-r--r--test/pnmpsnr.ok7
-rwxr-xr-xtest/pnmpsnr.test39
-rw-r--r--test/pnmquant.ok18
-rwxr-xr-xtest/pnmquant.test82
-rw-r--r--test/pnmquantall.ok6
-rwxr-xr-xtest/pnmquantall.test44
-rw-r--r--test/pnmremap1.ok6
-rwxr-xr-xtest/pnmremap1.test42
-rwxr-xr-xtest/pnmremap2.test2
-rwxr-xr-xtest/pnmshear.test2
-rw-r--r--test/pnmtile.ok6
-rwxr-xr-xtest/pnmtile.test35
-rw-r--r--test/pnmtopnm-plain.ok89
-rwxr-xr-xtest/pnmtopnm-plain.test16
-rw-r--r--test/ppmbrighten.ok10
-rwxr-xr-xtest/ppmbrighten.test35
-rw-r--r--test/ppmchange-roundtrip.ok4
-rwxr-xr-xtest/ppmchange-roundtrip.test6
-rwxr-xr-xtest/ppmchange.test2
-rwxr-xr-xtest/ppmcie.test2
-rwxr-xr-xtest/ppmdfont.test2
-rwxr-xr-xtest/ppmdim.test2
-rwxr-xr-xtest/ppmdither.test2
-rw-r--r--test/ppmforge-parameters.ok14
-rwxr-xr-xtest/ppmforge-parameters.test65
-rw-r--r--test/ppmforge.ok10
-rw-r--r--test/ppmforge.rand-ok3
-rwxr-xr-xtest/ppmforge.test55
-rw-r--r--test/ppmhist.ok6
-rwxr-xr-xtest/ppmhist.test33
-rw-r--r--test/ppmmake.ok13
-rwxr-xr-xtest/ppmmake.test64
-rwxr-xr-xtest/ppmmix.test2
-rwxr-xr-xtest/ppmpat-random.ok6
-rw-r--r--test/ppmpat-random.rand-ok7
-rwxr-xr-xtest/ppmpat-random.test20
-rw-r--r--test/ppmpat.ok41
-rwxr-xr-xtest/ppmpat.test188
-rwxr-xr-xtest/ppmrelief.test2
-rwxr-xr-xtest/ppmrough.ok1
-rw-r--r--test/ppmrough.rand-ok3
-rwxr-xr-xtest/ppmrough.test2
-rwxr-xr-xtest/ppmshift.ok23
-rwxr-xr-xtest/ppmshift.test42
-rwxr-xr-xtest/ppmspread.ok12
-rwxr-xr-xtest/ppmspread.test28
-rw-r--r--test/ppmtoapplevol.ok6
-rwxr-xr-xtest/ppmtoapplevol.test30
-rwxr-xr-xtest/ppmtoarbtxt-roundtrip.test5
-rwxr-xr-xtest/ppmtopgm.test2
-rw-r--r--test/ppmtoppm.ok24
-rwxr-xr-xtest/ppmtoppm.test15
-rw-r--r--test/ppmwheel.ok7
-rwxr-xr-xtest/ppmwheel.test39
-rw-r--r--test/ps-alt-roundtrip.ok5
-rwxr-xr-xtest/ps-alt-roundtrip.test34
-rw-r--r--test/ps-flate-roundtrip.ok4
-rwxr-xr-xtest/ps-flate-roundtrip.test17
-rw-r--r--test/ps-roundtrip.ok9
-rwxr-xr-xtest/ps-roundtrip.test24
-rw-r--r--test/qoi-roundtrip.ok34
-rwxr-xr-xtest/qoi-roundtrip.test254
-rw-r--r--test/random-generator.ok219
-rwxr-xr-xtest/random-generator.test86
-rw-r--r--test/rawtoppm.ok23
-rwxr-xr-xtest/rawtoppm.test72
-rw-r--r--test/rgb3-roundtrip.ok8
-rwxr-xr-xtest/rgb3-roundtrip.test62
-rwxr-xr-xtest/sbig-roundtrip.test2
-rw-r--r--test/sgi-roundtrip.ok13
-rwxr-xr-xtest/sgi-roundtrip.test31
-rwxr-xr-xtest/st4-roundtrip.test2
-rw-r--r--test/stdin-pam1.ok44
-rwxr-xr-xtest/stdin-pam1.test75
-rw-r--r--test/stdin-pam2.ok5
-rwxr-xr-xtest/stdin-pam2.test70
-rw-r--r--test/stdin-pam3.ok34
-rwxr-xr-xtest/stdin-pam3.test75
-rw-r--r--test/stdin-pbm1.ok9
-rwxr-xr-xtest/stdin-pbm1.test45
-rw-r--r--test/stdin-pbm2.ok28
-rwxr-xr-xtest/stdin-pbm2.test78
-rw-r--r--test/stdin-pgm1.ok11
-rwxr-xr-xtest/stdin-pgm1.test47
-rw-r--r--test/stdin-pgm2.ok6
-rwxr-xr-xtest/stdin-pgm2.test49
-rw-r--r--test/stdin-pnm1.ok22
-rwxr-xr-xtest/stdin-pnm1.test59
-rw-r--r--test/stdin-pnm2.ok28
-rwxr-xr-xtest/stdin-pnm2.test91
-rw-r--r--test/stdin-ppm1.ok15
-rwxr-xr-xtest/stdin-ppm1.test58
-rw-r--r--test/stdin-ppm2.ok11
-rwxr-xr-xtest/stdin-ppm2.test58
-rw-r--r--test/stdin-ppm3.ok20
-rwxr-xr-xtest/stdin-ppm3.test75
-rw-r--r--test/sunicon-roundtrip.ok5
-rwxr-xr-xtest/sunicon-roundtrip.test28
-rwxr-xr-xtest/sunrast-roundtrip.test2
-rw-r--r--test/symmetry.ok6
-rwxr-xr-xtest/symmetry.test25
-rw-r--r--test/targa-roundtrip.ok30
-rwxr-xr-xtest/targa-roundtrip.test26
-rw-r--r--test/tiff-flate-lzw-roundtrip.ok4
-rwxr-xr-xtest/tiff-flate-lzw-roundtrip.test14
-rw-r--r--test/tiff-roundtrip.ok20
-rwxr-xr-xtest/tiff-roundtrip.test32
-rwxr-xr-xtest/tiffcmyk-roundtrip.test2
-rwxr-xr-xtest/utahrle-roundtrip.test2
-rw-r--r--test/wbmp-roundtrip.ok2
-rwxr-xr-xtest/wbmp-roundtrip.test6
-rw-r--r--test/winicon-roundtrip.ok14
-rwxr-xr-xtest/winicon-roundtrip.test46
-rw-r--r--test/winicon-roundtrip2.ok82
-rwxr-xr-xtest/winicon-roundtrip2.test154
-rw-r--r--test/xbm-roundtrip.ok5
-rwxr-xr-xtest/xbm-roundtrip.test7
-rw-r--r--test/xpm-roundtrip.ok2
-rwxr-xr-xtest/xpm-roundtrip.test4
-rwxr-xr-xtest/xv-roundtrip.test2
-rw-r--r--test/xwd-roundtrip.ok5
-rwxr-xr-xtest/xwd-roundtrip.test13
-rwxr-xr-xtest/yuv-roundtrip.test2
-rw-r--r--urt/Makefile6
-rw-r--r--urt/README5
-rw-r--r--urt/Runput.c300
-rw-r--r--urt/Runput.h2
-rw-r--r--urt/cmd_name.c30
-rw-r--r--urt/rle.h202
-rw-r--r--urt/rle_addhist.c20
-rw-r--r--urt/rle_code.h57
-rw-r--r--urt/rle_config.h10
-rw-r--r--urt/rle_error.c119
-rw-r--r--urt/rle_getcom.c44
-rw-r--r--urt/rle_getrow.c97
-rw-r--r--urt/rle_getskip.c198
-rw-r--r--urt/rle_global.c78
-rw-r--r--urt/rle_hdr.c394
-rw-r--r--urt/rle_open_f.c63
-rw-r--r--urt/rle_put.h64
-rw-r--r--urt/rle_putcom.c57
-rw-r--r--urt/rle_putrow.c753
-rw-r--r--urt/rle_row_alc.c100
-rw-r--r--urt/scanargs.c918
-rw-r--r--urt/vaxshort.c39
-rw-r--r--version.mk6
721 files changed, 38185 insertions, 19599 deletions
diff --git a/GNUmakefile b/GNUmakefile
index e5b0265a..2c172da6 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -24,6 +24,18 @@
 #   The default target is either "merge" or "nonmerge", as determined by
 #   the DEFAULT_TARGET variable set by config.mk.
 
+# Debugging techniques:
+#
+#   To build so you can easily debug with a debugger such as Gdb:
+#
+#     make CFLAGS="-g -O0"
+#
+#   To debug libnetpbm, link it statically into the using program:
+#
+#     make NETPBMLIBTYPE=unixstatic pamcut
+#
+#     (Then 'ldd ./pamcut' to make sure it worked)
+#
 # About the "merge" target: Normally the Makefiles build separate
 # executables for each program.  However, on some systems (especially
 # those without shared libraries) this can mean a lot of space.  In
@@ -52,6 +64,11 @@
 # running in.  The -f option is necessary in order to have separate
 # source and object directories.
 
+# For the check targets, results go in a results directory, which you'll need
+# if a test fails to find out how it failed.  The default is
+# RESULTDIR_DEFAULT in config.mk.  Override it with
+# 'make resultdir=/tmp/myresultdir .
+
 ifeq ($(CURDIR)x,x)
 all package install:
 	@echo "YOU NEED AT LEAST VERSION 3.77 OF GNU MAKE TO BUILD NETPBM."
@@ -266,7 +283,14 @@ init_package:
 	echo "Netpbm install package made by 'make package'" \
 	    >$(PKGDIR)/pkginfo
 	date >>$(PKGDIR)/pkginfo
-	echo Netpbm $(MAJOR).$(MINOR).$(POINT) >$(PKGDIR)/VERSION
+# For many years, the version string was "Netpbm x.y.z" instead of just
+# "x.y.z".  This was probably related to the fact that when you ask a Netpbm
+# program its version, it says "Netpbm x.y.z" to let you know it's the version
+# of the whole package, not just that program.  And also to distinguish from
+# the Pbmplus version of the program.  But this is highly unconventional in
+# pkg-config or config files, so we removed the "Netpbm" in Netpbm 10.90
+# (March 2020).
+	echo $(MAJOR).$(MINOR).$(POINT) >$(PKGDIR)/VERSION
 	$(INSTALL) -c -m 664 $(SRCDIR)/buildtools/README.pkg $(PKGDIR)/README
 	$(INSTALL) -c -m 664 $(SRCDIR)/buildtools/config_template \
 	  $(PKGDIR)/config_template
@@ -310,8 +334,8 @@ ifneq ($(LINUXSVGALIB),NONE)
   MERGELIBS += $(LINUXSVGALIB)
 endif
 
-ifneq ($(shell pkg-config --modversion libpng$(PNGVER)),)
-  PNGLD = $(shell pkg-config --libs libpng$(PNGVER))
+ifneq ($(shell $(PKG_CONFIG) --modversion libpng$(PNGVER)),)
+  PNGLD = $(shell $(PKG_CONFIG) --libs libpng$(PNGVER))
 else
   ifneq ($(shell libpng$(PNGVER)-config --version),)
     PNGLD = $(shell libpng$(PNGVER)-config --ldflags)
@@ -320,8 +344,8 @@ else
   endif
 endif
 
-ifneq ($(shell pkg-config --modversion libxml-2.0),)
-  XML2LD=$(shell pkg-config --libs libxml-2.0)
+ifneq ($(shell $(PKG_CONFIG) --modversion libxml-2.0),)
+  XML2LD=$(shell $(PKG_CONFIG) --libs libxml-2.0)
 else
   ifneq ($(shell xml2-config --version),)
     XML2LD=$(shell xml2-config --libs)
@@ -330,8 +354,8 @@ else
   endif
 endif
 
-ifneq ($(shell pkg-config x11 --libs),)
-  X11LD = $(shell pkg-config x11 --libs)
+ifneq ($(shell $(PKG_CONFIG) x11 --libs),)
+  X11LD = $(shell $(PKG_CONFIG) x11 --libs)
 else
   X11LD = $(shell $(LIBOPT) $(LIBOPTR) $(X11LIB))
 endif
@@ -349,7 +373,7 @@ endif
 #   1) Each directory produces an object file merge.o containing all the code
 #      in that directory and its descendants that needs to go into the 'netpbm'
 #      program.  The make files do this recursively, via a link command that
-#      combines multiple relocateable object files into one.  All we do here
+#      combines multiple relocatable object files into one.  All we do here
 #      at the top level is make merge.o and link it with netpbm.o and the
 #      libraries.
 #
@@ -449,6 +473,7 @@ CHECK_VARS = \
 	JASPERLIB="$(JASPERLIB)" \
 	JBIGLIB="$(JBIGLIB)" \
 	JPEGLIB="$(JPEGLIB)" \
+	LINUXSVGALIB="$(LINUXSVGALIB)" \
 	PNGLIB="$(PNGLIB)" \
 	TIFFLIB="$(TIFFLIB)" \
 	URTLIB="$(URTLIB)" \
diff --git a/analyzer/pamfind.c b/analyzer/pamfind.c
index 860c01ff..15ca9e85 100644
--- a/analyzer/pamfind.c
+++ b/analyzer/pamfind.c
@@ -1,4 +1,6 @@
+#include <assert.h>
 #include <nstring.h>
+
 #include <pam.h>
 
 #include "pm_c_util.h"
@@ -9,11 +11,13 @@
 typedef struct {
     unsigned int * target;
     unsigned int   targetDepth;
+    unsigned int   machine;
     const char *   color;  /* NULL means not specified */
     const char *   inputFileName;
 } CmdLineInfo;
 
 
+
 static CmdLineInfo
 parsedCommandLine(int                 argc,
                   const char ** const argv) {
@@ -33,9 +37,10 @@ parsedCommandLine(int                 argc,
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENT3 */
-    OPTENT3(0,   "target",  OPT_STRINGLIST, &target,         &targetSpec, 0);
-    OPTENT3(0,   "color",   OPT_STRING,     &cmdLine.color,  &colorSpec,  0);
-    OPTENT3(0,  0,          OPT_END,        NULL,            NULL,        0);
+    OPTENT3(0,   "target",  OPT_STRINGLIST, &target,          &targetSpec, 0);
+    OPTENT3(0,   "color",   OPT_STRING,     &cmdLine.color,   &colorSpec,  0);
+    OPTENT3(0,   "machine", OPT_FLAG,       NULL,       &cmdLine.machine,  0);
+    OPTENT3(0,  0,          OPT_END,        NULL,             NULL,        0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
@@ -43,35 +48,37 @@ parsedCommandLine(int                 argc,
 
     pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
 
-    if (targetSpec) {
-        if (colorSpec)
-            pm_error("You cannot specify both -target and -color");
-        else {
-            unsigned int i;
+    if (targetSpec + colorSpec > 1)
+        pm_error("You cannot specify both -target and -color");
 
-            cmdLine.color = NULL;
+    else if (targetSpec + colorSpec == 0)
+        pm_error("You must specify either -target or -color");
 
-            cmdLine.target = NULL;  /* initial value */
+    else if (targetSpec) {
+        unsigned int i;
 
-            for (i = 0, cmdLine.targetDepth = 0; target[i]; ++i) {
-                unsigned int sampleVal;
-                const char * error;
+        cmdLine.color = NULL;
 
-                pm_string_to_uint(target[i], &sampleVal, &error);
-                if (error) {
-                    pm_error("Invalid sample value in -target option: '%s'.  "
-                             "%s", target[i], error);
-                }
+        cmdLine.target = NULL;  /* initial value */
 
-                REALLOCARRAY(cmdLine.target, i+1);
+        for (i = 0, cmdLine.targetDepth = 0; target[i]; ++i) {
+            unsigned int sampleVal;
+            const char * error;
 
-                cmdLine.target[cmdLine.targetDepth++] = sampleVal;
+            pm_string_to_uint(target[i], &sampleVal, &error);
+            if (error) {
+                pm_error("Invalid sample value in -target option: '%s'.  "
+                         "%s", target[i], error);
             }
 
-            free(target);
+            REALLOCARRAY(cmdLine.target, i+1);
+
+            cmdLine.target[cmdLine.targetDepth++] = sampleVal;
         }
-    } else if (!colorSpec)
-        pm_error("You must specify either -target or -color");
+
+        free(target);
+    } else
+        assert (colorSpec == 1);
 
     if (argc-1 < 1)
         cmdLine.inputFileName = "-";
@@ -118,7 +125,7 @@ targetValue(CmdLineInfo  const cmdLine,
     } else {
         if (cmdLine.targetDepth != inpamP->depth)
             pm_error("You specified a %u-tuple for -target, "
-                     "but the input image of of depth %u",
+                     "but the input image is of depth %u",
                      cmdLine.targetDepth, inpamP->depth);
         else {
             unsigned int i;
@@ -161,6 +168,29 @@ printHeader(FILE *       const ofP,
 
 
 
+static unsigned int
+decimalDigitCt(unsigned int const n) {
+/*----------------------------------------------------------------------------
+   Minimum number of digits needed to display 'n' in decimal.
+-----------------------------------------------------------------------------*/
+    unsigned int digitCt;
+
+    if (n == 0)
+        digitCt = 1;
+    else {
+        unsigned int x;
+
+        for (digitCt = 0, x = n; x > 0;) {
+            ++digitCt;
+            x /= 10;
+        }
+        assert(digitCt > 0);
+    }
+    return digitCt;
+}
+
+
+
 static void
 pamfind(FILE *       const ifP,
         struct pam * const inpamP,
@@ -174,8 +204,16 @@ pamfind(FILE *       const ifP,
         tuple   const target   = targetValue(cmdLine, inpamP);
 
         unsigned int row;
-
-        printHeader(ofP, inpamP, target);
+        const char * fmt;
+
+        if (cmdLine.machine) {
+            pm_asprintf(&fmt, "%%0%uu %%0%uu\n",
+                        decimalDigitCt(inpamP->height-1),
+                        decimalDigitCt(inpamP->width-1));
+        } else {
+            printHeader(ofP, inpamP, target);
+            fmt = pm_strdup("(%u, %u)\n");
+        }
 
         for (row = 0; row < inpamP->height; ++row) {
             unsigned int col;
@@ -185,10 +223,11 @@ pamfind(FILE *       const ifP,
             for (col = 0; col < inpamP->width; ++col) {
 
                 if (pnm_tupleequal(inpamP, target, inputRow[col])) {
-                    fprintf(ofP, "(%u, %u)\n", row, col);
+                    fprintf(ofP, fmt, row, col);
                 }
             }
         }
+        pm_strfree(fmt);
         pnm_freepamtuple(target);
         pnm_freepamrow(inputRow);
     }
diff --git a/analyzer/pamgetcolor.c b/analyzer/pamgetcolor.c
index 430f3b07..d1ea3799 100644
--- a/analyzer/pamgetcolor.c
+++ b/analyzer/pamgetcolor.c
@@ -37,7 +37,7 @@ typedef struct {
     uint         regN;      /* number of regions                             */
     uint         maxLbLen;  /* maximum label length                          */
     RegSpec *    regSpecs;
-        /* list of points to sample, dymamically allocated*/
+        /* list of points to sample, dynamically allocated*/
     const char * formatStr; /* output color format as string                 */
     uint         formatId;  /* the Id of the selected color format           */
     uint         formatArg; /* the argument to the color formatting function */
@@ -45,9 +45,9 @@ typedef struct {
 } CmdLineInfo;
 
 /* Generic pointer to a color-formatting function. Returns the textual
-   representation of the color <tuple> in terms of the image pointed-to
+   representation of the color <tuple> in terms of the image pointed to
    by <pamP>. <param> is a generic integer parameter that depends on the
-   specific funcion and may denote precison or maxval.
+   specific function and may denote precision or maxval.
 */
 typedef const char *
 (*FormatColor)(struct pam * const pamP,
diff --git a/analyzer/pamsumm.c b/analyzer/pamsumm.c
index 9b74e789..03ff6749 100644
--- a/analyzer/pamsumm.c
+++ b/analyzer/pamsumm.c
@@ -58,8 +58,8 @@ parseCommandLine(int argc, const char ** const argv,
     pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
-    if (sumSpec + minSpec + maxSpec > 1)
-        pm_error("You may specify at most one of -sum, -min, and -max");
+    if (sumSpec + minSpec + maxSpec + meanSpec > 1)
+        pm_error("You may specify at most one of -sum, -min, -max, and -mean");
 
     if (sumSpec) {
         cmdlineP->function = FN_ADD;
diff --git a/analyzer/pamtable.c b/analyzer/pamtable.c
index 2835469a..acd027a6 100644
--- a/analyzer/pamtable.c
+++ b/analyzer/pamtable.c
@@ -15,12 +15,16 @@
 #include "mallocvar.h"
 #include "nstring.h"
 
+enum Style {STYLE_BASIC, STYLE_TUPLE};
+
 struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
     const char * inputFileName;  /* Name of input file */
-    unsigned int  verbose;
+    enum Style   outputStyle;
+    unsigned int hex;
+    unsigned int verbose;
 };
 
 
@@ -34,11 +38,14 @@ parseCommandLine(int argc, const char ** const argv,
     optStruct3 opt;
 
     unsigned int option_def_index;
+    unsigned int tuple;
 
     MALLOCARRAY(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENT3 */
 
+    OPTENT3(0,   "tuple",     OPT_FLAG,  NULL, &tuple,               0);
+    OPTENT3(0,   "hex",       OPT_FLAG,  NULL, &cmdlineP->hex,       0);
     OPTENT3(0,   "verbose",   OPT_FLAG,  NULL, &cmdlineP->verbose,   0);
         /* For future expansion */
 
@@ -49,6 +56,14 @@ parseCommandLine(int argc, const char ** const argv,
     pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
+    if (tuple && cmdlineP->hex)
+        pm_error("-hex is invalid with -tuple");
+
+    if (tuple)
+        cmdlineP->outputStyle = STYLE_TUPLE;
+    else
+        cmdlineP->outputStyle = STYLE_BASIC;
+
     if (argc-1 > 1)
         pm_error("Too many arguments (%d).  File name is the only argument.",
                  argc-1);
@@ -74,12 +89,27 @@ typedef struct {
     const char * interTupleGutter;
        /* What we print between tuples within a row */
 
+    const char * rowStartString;
+       /* What we print at the beginning of each row */
+
+    const char * rowEndString;
+       /* What we print at the end of each row */
+
 } Format;
 
 
 
+static double const
+log16(double const arg) {
+
+    return log(arg)/log(16);
+}
+
+
+
 static const char *
-sampleFormat(const struct pam * const pamP) {
+basicSampleFormat(const struct pam * const pamP,
+                  bool               const wantHex) {
 /*----------------------------------------------------------------------------
    The printf format string for a single sample in the output table.
 
@@ -87,11 +117,21 @@ sampleFormat(const struct pam * const pamP) {
 
    This format does not include any spacing between samples.
 -----------------------------------------------------------------------------*/
-    unsigned int const decimalWidth = ROUNDU(ceil(log10(pamP->maxval + 1)));
-
+    unsigned int cipherWidth;
+    char         formatSpecifier;
+    const char * flag;
     const char * retval;
 
-    pm_asprintf(&retval, "%%%uu", decimalWidth);
+    if (wantHex) {
+        formatSpecifier = 'x';
+        cipherWidth     = ROUNDU(ceil(log16(pamP->maxval + 1)));
+        flag            = "0";
+    } else {
+        formatSpecifier = 'u';
+        cipherWidth     = ROUNDU(ceil(log10(pamP->maxval + 1)));
+        flag            = "";
+    }
+    pm_asprintf(&retval, "%%%s%u%c", flag, cipherWidth, formatSpecifier);
 
     return retval;
 }
@@ -100,13 +140,26 @@ sampleFormat(const struct pam * const pamP) {
 
 static void
 makeFormat(const struct pam * const pamP,
+           enum Style         const outputStyle,
+           bool               const wantHex,
            Format *           const formatP) {
 
-    formatP->sampleFmt = sampleFormat(pamP);
-
-    formatP->interSampleGutter = " ";
-
-    formatP->interTupleGutter = pamP->depth > 1 ? "|" : " ";
+    switch (outputStyle) {
+      case STYLE_BASIC:
+          formatP->sampleFmt         = basicSampleFormat(pamP, wantHex);
+          formatP->interSampleGutter = " ";
+          formatP->interTupleGutter  = pamP->depth > 1 ? "|" : " ";
+          formatP->rowStartString    = "";
+          formatP->rowEndString      = "\n";
+          break;
+      case STYLE_TUPLE:
+          formatP->sampleFmt         = pm_strdup("%u");
+          formatP->interSampleGutter = ",";
+          formatP->interTupleGutter  = ") (";
+          formatP->rowStartString    = "(";
+          formatP->rowEndString      = ")\n";
+          break;
+    }
 }
 
 
@@ -127,6 +180,8 @@ printRow(const struct pam * const pamP,
 
     unsigned int col;
 
+    fputs (format.rowStartString, ofP);
+
     for (col = 0; col < pamP->width; ++col) {
         unsigned int plane;
 
@@ -142,7 +197,7 @@ printRow(const struct pam * const pamP,
         }
     }
 
-    fputs("\n", ofP);
+    fputs (format.rowEndString, ofP);
 }
 
 
@@ -150,14 +205,16 @@ printRow(const struct pam * const pamP,
 static void
 printRaster(FILE *             const ifP,
             const struct pam * const pamP,
-            FILE *             const ofP) {
+            FILE *             const ofP,
+            enum Style         const outputStyle,
+            bool               const wantHex) {
 
     Format format;
 
     tuple * inputRow;   /* Row from input image */
     unsigned int row;
 
-    makeFormat(pamP, &format);
+    makeFormat(pamP, outputStyle, wantHex, &format);
 
     inputRow = pnm_allocpamrow(pamP);
 
@@ -189,7 +246,7 @@ main(int argc, const char *argv[]) {
 
     pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
 
-    printRaster(ifP, &inpam, stdout);
+    printRaster(ifP, &inpam, stdout, cmdline.outputStyle, cmdline.hex);
 
     pm_close(inpam.file);
 
diff --git a/analyzer/pamtilt.c b/analyzer/pamtilt.c
index 70338545..2898d30f 100644
--- a/analyzer/pamtilt.c
+++ b/analyzer/pamtilt.c
@@ -143,7 +143,7 @@ load(const struct pam * const pamP,
     sample ** pixels;
 
     tuplerow = pnm_allocpamrow(pamP);
-    
+
     MALLOCARRAY(pixels, pamP->height);
 
     if (pixels == NULL)
@@ -221,7 +221,7 @@ totalBrightness(sample **    const pixels,
 /*----------------------------------------------------------------------------
    Total brightness of samples in the line that goes from the left edge
    of Row 'startRow' of 'pixels' down to the right at 'dy' rows per column.
-   
+
    Note that 'dy' can be negative.
 
    Assume that whatever 'dy' is, the sloping line thus described remains
@@ -319,7 +319,7 @@ scoreAngle(const struct pam * const pamP,
   If 'angle' is so great that not a single line goes all the way across the
   page without running off the top or bottom, we call the score -1.  In
   every other case, it is nonnegative.
-  
+
   'pixels' is NOT all the pixels in the image; it is just a sampling.
   In each row, it contains only 'hsampleCt' pixels, sampled from the
   image at intervals of 'hstep' pixels.  E.g if the image is 1000
@@ -468,7 +468,7 @@ readSampledPixels(const char *   const inputFilename,
 
     *hstepP = hstep;
     *vstepP = vstep;
-    
+
     pm_close(ifP);
 }
 
@@ -490,7 +490,7 @@ getAngle(const struct pam * const pamP,
     float a;
     float da;
     float lastq;        /* quality (s/n ratio) of last measurement */
-    
+
     getBestAngleLocal(pamP, pixels, hstep, vstep, hsampleCt,
                       -maxangle, maxangle, astep, verbose,
                       &a, &lastq);
@@ -551,3 +551,6 @@ main(int argc, const char ** argv) {
 
     return 0;
 }
+
+
+
diff --git a/analyzer/pgmtexture.c b/analyzer/pgmtexture.c
index 4e0dd4d5..5af51bf5 100644
--- a/analyzer/pgmtexture.c
+++ b/analyzer/pgmtexture.c
@@ -1,49 +1,5 @@
 /* pgmtexture.c - calculate textural features of a PGM image
 **
-** Author: James Darrell McCauley
-**         Texas Agricultural Experiment Station
-**         Department of Agricultural Engineering
-**         Texas A&M University
-**         College Station, Texas 77843-2117 USA
-**
-** Code written partially taken from pgmtofs.c in the PBMPLUS package
-** by Jef Poskanzer.
-**
-** Algorithms for calculating features (and some explanatory comments) are
-** taken from:
-**
-**   Haralick, R.M., K. Shanmugam, and I. Dinstein. 1973. Textural features
-**   for image classification.  IEEE Transactions on Systems, Man, and
-**   Cybertinetics, SMC-3(6):610-621.
-**
-** Copyright (C) 1991 Texas Agricultural Experiment Station, employer for
-** hire of James Darrell McCauley
-**
-** 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 TEXAS AGRICULTURAL EXPERIMENT STATION (TAES) AND THE TEXAS A&M
-** UNIVERSITY SYSTEM (TAMUS) MAKE NO EXPRESS OR IMPLIED WARRANTIES
-** (INCLUDING BY WAY OF EXAMPLE, MERCHANTABILITY) WITH RESPECT TO ANY
-** ITEM, AND SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL
-** OR CONSEQUENTAL DAMAGES ARISING OUT OF THE POSESSION OR USE OF
-** ANY SUCH ITEM. LICENSEE AND/OR USER AGREES TO INDEMNIFY AND HOLD
-** TAES AND TAMUS HARMLESS FROM ANY CLAIMS ARISING OUT OF THE USE OR
-** POSSESSION OF SUCH ITEMS.
-**
-** Modification History:
-** 24 Jun 91 - J. Michael Carstensen <jmc@imsor.dth.dk> supplied fix for
-**             correlation function.
-**
-** 05 Oct 05 - Marc Breithecker <Marc.Breithecker@informatik.uni-erlangen.de>
-**             Fix calculation or normalizing constants for d > 1.
-** 9 Jul 11  - Francois P. S. Luus <fpsluus@gmail.com> supplied fix for sum
-**             variance calculation (use F6:savg instead of F8:sentropy in
-**             F7:svar equation).
 
 
 */
@@ -93,7 +49,16 @@ static bool const sortit = FALSE;
 static float *
 vector(unsigned int const nl,
        unsigned int const nh) {
+/*----------------------------------------------------------------------------
+  Allocate a float vector with range [nl..nh]
+
+  We do some seedy C here, subtracting an arbitrary integer from a pointer and
+  calling the result a pointer.  It normally works because the only way we'll
+  use that pointer is by adding that same integer or something greater to it.
 
+  The point of this is not to allocate memory for vector elements that will
+  never be referenced (component < nl).
+-----------------------------------------------------------------------------*/
     float * v;
     unsigned int i;
 
@@ -1175,3 +1140,51 @@ main (int argc, const char ** argv) {
 
     return 0;
 }
+
+
+/*
+** Author: James Darrell McCauley
+**         Texas Agricultural Experiment Station
+**         Department of Agricultural Engineering
+**         Texas A&M University
+**         College Station, Texas 77843-2117 USA
+**
+** Code written partially taken from pgmtofs.c in the PBMPLUS package
+** by Jef Poskanzer.
+**
+** Algorithms for calculating features (and some explanatory comments) are
+** taken from:
+**
+**   Haralick, R.M., K. Shanmugam, and I. Dinstein. 1973. Textural features
+**   for image classification.  IEEE Transactions on Systems, Man, and
+**   Cybertinetics, SMC-3(6):610-621.
+**
+** Copyright (C) 1991 Texas Agricultural Experiment Station, employer for
+** hire of James Darrell McCauley
+**
+** 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 TEXAS AGRICULTURAL EXPERIMENT STATION (TAES) AND THE TEXAS A&M
+** UNIVERSITY SYSTEM (TAMUS) MAKE NO EXPRESS OR IMPLIED WARRANTIES
+** (INCLUDING BY WAY OF EXAMPLE, MERCHANTABILITY) WITH RESPECT TO ANY
+** ITEM, AND SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL
+** OR CONSEQUENTAL DAMAGES ARISING OUT OF THE POSSESSION OR USE OF
+** ANY SUCH ITEM. LICENSEE AND/OR USER AGREES TO INDEMNIFY AND HOLD
+** TAES AND TAMUS HARMLESS FROM ANY CLAIMS ARISING OUT OF THE USE OR
+** POSSESSION OF SUCH ITEMS.
+**
+** Modification History:
+** 24 Jun 91 - J. Michael Carstensen <jmc@imsor.dth.dk> supplied fix for
+**             correlation function.
+**
+** 05 Oct 05 - Marc Breithecker <Marc.Breithecker@informatik.uni-erlangen.de>
+**             Fix calculation or normalizing constants for d > 1.
+** 9 Jul 11  - Francois P. S. Luus <fpsluus@gmail.com> supplied fix for sum
+**             variance calculation (use F6:savg instead of F8:sentropy in
+**             F7:svar equation).
+*/
diff --git a/analyzer/pnmpsnr.c b/analyzer/pnmpsnr.c
index 2363e8c3..6543c542 100644
--- a/analyzer/pnmpsnr.c
+++ b/analyzer/pnmpsnr.c
@@ -179,7 +179,7 @@ validateInput(struct pam const pam1,
                  pam1.height, pam2.height);
 
     if (pam1.maxval != pam2.maxval)
-        pm_error("images do not have the same maxval.  This programs works "
+        pm_error("images do not have the same maxval.  This program works "
                  "only on like maxvals.  "
                  "The first image has maxval %u, "
                  "while the second has %u.  Use Pamdepth to change the "
diff --git a/analyzer/ppmhist.c b/analyzer/ppmhist.c
index c4ab3581..62345fa1 100644
--- a/analyzer/ppmhist.c
+++ b/analyzer/ppmhist.c
@@ -120,25 +120,6 @@ cmpUint(unsigned int const a,
 
 
 #ifndef LITERAL_FN_DEF_MATCH
-static qsort_comparison_fn countcompare;
-#endif
-
-
-static int
-countcompare(const void * const a,
-             const void * const b) {
-/*----------------------------------------------------------------------------
-   This is a 'qsort' collation function.
------------------------------------------------------------------------------*/
-    const struct colorhist_item * const histItem1P = a;
-    const struct colorhist_item * const histItem2P = b;
-
-    return cmpUint(histItem2P->value, histItem1P->value);
-}
-
-
-
-#ifndef LITERAL_FN_DEF_MATCH
 static qsort_comparison_fn rgbcompare;
 #endif
 
@@ -167,6 +148,31 @@ rgbcompare(const void * const a,
 
 
 
+#ifndef LITERAL_FN_DEF_MATCH
+static qsort_comparison_fn countcompare;
+#endif
+
+
+static int
+countcompare(const void * const a,
+             const void * const b) {
+/*----------------------------------------------------------------------------
+   This is a 'qsort' collation function.
+-----------------------------------------------------------------------------*/
+    const struct colorhist_item * const histItem1P = a;
+    const struct colorhist_item * const histItem2P = b;
+
+    int const countComparison = cmpUint(histItem2P->value, histItem1P->value);
+
+    if (countComparison == 0) {
+        /* Counts are the same; use RGB secondary sort */
+        return rgbcompare(a, b);
+    } else
+        return countComparison;
+}
+
+
+
 static pixval
 universalMaxval(pixval const maxval,
                 int    const format) {
diff --git a/buildtools/README.pkg b/buildtools/README.pkg
index d642dee8..71afc000 100644
--- a/buildtools/README.pkg
+++ b/buildtools/README.pkg
@@ -114,7 +114,7 @@ The parts to be installed are:
     replacement for the classic Man program that can access both traditional
     man pages and worldwide web documentation in the Netpbm style with the
     familiar 'man jpegtopnm' kind of command.  The package contains the files
-    necessary to use Manweb to access Netpbm documention on the web (on
+    necessary to use Manweb to access Netpbm documentation on the web (on
     netpbm.sourceforge.net).  These files are the contents of the man/web
     directory and the file 'bin/doc.url'.  You should install the
     'bin/doc.url' file if you are installing the Netpbm executables in a
diff --git a/buildtools/configure.pl b/buildtools/configure.pl
index 4e6ff21a..aa94a6bb 100755
--- a/buildtools/configure.pl
+++ b/buildtools/configure.pl
@@ -9,15 +9,15 @@ use Cwd 'abs_path';
 use Fcntl;
 use Config;
 #use File::Temp "tempfile";   Not available before Perl 5.6.1
-    
+
 
 my ($TRUE, $FALSE) = (1,0);
 
 # This program generates config.mk, which is included by all of the
-# Netpbm makefiles.  You run this program as the first step in building 
+# Netpbm makefiles.  You run this program as the first step in building
 # Netpbm.  (The second step is 'make').
 
-# This program is only a convenience.  It is supported to create 
+# This program is only a convenience.  It is supported to create
 # config.mk any way you want.  In fact, an easy way is to copy
 # config.mk.in and follow the instructions in the comments therein
 # to uncomment certain lines and make other changes.
@@ -28,7 +28,7 @@ my ($TRUE, $FALSE) = (1,0);
 # user, but it isn't the normal build process.
 
 # The argument to this program is the filepath of the config.mk.in
-# file.  If unspecified, the default is 'config.mk.in' in the 
+# file.  If unspecified, the default is 'config.mk.in' in the
 # Netpbm source directory.
 
 # For explanations of the stuff we put in the make files, see the comments
@@ -105,7 +105,7 @@ sub promptYesNo($) {
 
     while (!defined($retval)) {
         my $response = prompt("(y)es or (n)o", $default);
-        
+
         if (uc($response) =~ m{ ^ (Y|YES) $ }x)  {
             $retval = $TRUE;
         } elsif (uc($response) =~ m{ ^ (N|NO) $ }x)  {
@@ -125,17 +125,17 @@ sub flow($) {
     my ($unflowed) = @_;
 #-----------------------------------------------------------------------------
 #  Return the text $unflowed, split with newlines into 72 character lines.
-#  We assum $unflowed is pure text, without any kind of formatting characters
+#  We assume $unflowed is pure text, without any kind of formatting characters
 #  such as newlines.
 #-----------------------------------------------------------------------------
     my $retval;
 
     my @words = split(m{\s+}, $unflowed);
-    
+
     my $currentLine;
-    
+
     $currentLine = "";
-    
+
     foreach my $word (@words) {
         my $mustSpill;
         if (length($currentLine) == 0) {
@@ -148,7 +148,7 @@ sub flow($) {
             } else {
                 $separator = " ";
             }
-                
+
             if (length($currentLine) + length($separator) + length($word)
                 <= 72) {
                 $currentLine .= $separator;
@@ -194,7 +194,7 @@ sub tmpdir() {
 # basic Perl some time after Perl 5.005_03.
 
     my $retval;
-    
+
     if ($ENV{'TMPDIR'}) {
         $retval = $ENV{'TMPDIR'};
     } elsif ($ENV{'TEMP'}) {
@@ -217,8 +217,8 @@ sub tempFile($) {
 
 # Here's what we'd do if we could expect Perl 5.6.1 or later, instead
 # of calling this subroutine:
-#    my ($cFile, $cFileName) = tempfile("netpbmXXXX", 
-#                                       SUFFIX=>".c", 
+#    my ($cFile, $cFileName) = tempfile("netpbmXXXX",
+#                                       SUFFIX=>".c",
 #                                       DIR=>File::Spec->tmpdir(),
 #                                       UNLINK=>0);
     my ($suffix) = @_;
@@ -275,7 +275,7 @@ sub commandExists($) {
 # from system() a lot different than if system() were to try to
 # execute the program directly.
 
-    return(system("$command 1</dev/null 1>/dev/null 2>/dev/null")/256 != 127); 
+    return(system("$command 1</dev/null 1>/dev/null 2>/dev/null")/256 != 127);
 }
 
 
@@ -304,20 +304,20 @@ sub testCflags() {
 
     my $cflags;
 
-    $cflags = "";  # initial value 
-    
+    $cflags = "";  # initial value
+
     if ($ENV{"CPPFLAGS"}) {
         $cflags = $ENV{"CPPFLAGS"};
     } else {
         $cflags = "";
     }
-    
+
     if ($ENV{"CFLAGS"}) {
         $cflags .= " " . $ENV{"CFLAGS"};
     }
-    
+
     return $cflags;
-}    
+}
 
 
 
@@ -325,21 +325,21 @@ sub testCompile($$$) {
     my ($cflags, $cSourceCodeR, $successR) = @_;
 #-----------------------------------------------------------------------------
 #  Do a test compile of the program in @{$cSourceCodeR}.
-#  
+#
 #  Return $$successR == $TRUE iff the compile succeeds (exit code 0).
 #-----------------------------------------------------------------------------
     my ($cFile, $cFileName) = tempFile(".c");
 
     print $cFile @{$cSourceCodeR};
-    
+
     my ($oFile, $oFileName) = tempFile(".o");
     # Note: we tried using /dev/null for the output file and got complaints
     # from the Sun compiler that it has the wrong suffix.  2002.08.09.
-    
+
     my $compileCommand = "$testCc -c -o $oFileName $cflags $cFileName";
     print ("Doing test compile: $compileCommand\n");
     my $rc = system($compileCommand);
-    
+
     unlink($oFileName);
     close($oFile);
     unlink($cFileName);
@@ -354,22 +354,22 @@ sub testCompileLink($$$) {
     my ($flags, $cSourceCodeR, $successR) = @_;
 #-----------------------------------------------------------------------------
 #  Do a test compile and link of the program in @{$cSourceCodeR}.
-#  
+#
 #  Return $$successR == $TRUE iff the compile succeeds (exit code 0).
 #-----------------------------------------------------------------------------
     my ($cFile, $cFileName) = tempFile('.c');
 
     print $cFile @{$cSourceCodeR};
-    
+
     my ($oFile, $oFileName) = tempFile('');
 
     # Note that $flags may contain -l options, which where static linking
     # is involved have to go _after_ the base object file ($oFileName).
-    
+
     my $compileCommand = "$testCc -o $oFileName $cFileName $flags";
     print ("Doing test compile/link: $compileCommand\n");
     my $rc = system($compileCommand);
-    
+
     unlink($oFileName);
     close($oFile);
     unlink($cFileName);
@@ -410,14 +410,14 @@ sub askAboutCygwin() {
 
     print("Are you building in/for the Cygwin environment?\n");
     print("\n");
-    
+
     my $default;
     if ($OSNAME eq "cygwin") {
         $default = "y";
     } else {
         $default = "n";
     }
-    
+
     my $retval = promptYesNo($default);
 
     return $retval;
@@ -429,14 +429,14 @@ sub askAboutDjgpp() {
 
     print("Are you building in/for the DJGPP environment?\n");
     print("\n");
-    
+
     my $default;
     if ($OSNAME eq "dos") {
         $default = "y";
     } else {
         $default = "n";
     }
-    
+
     my $retval = promptYesNo($default);
 }
 
@@ -446,7 +446,7 @@ sub askAboutMingw() {
 
     print("Are you building for the MinGW environment?\n");
     print("\n");
-    
+
     my $retval = promptYesNo("n");
 
     return $retval;
@@ -488,7 +488,7 @@ sub getPlatform() {
     computePlatformDefault(\$default);
 
     print("Which of the following best describes your platform?\n");
- 
+
     print("gnu      GNU/Linux\n");
     print("win      Windows/DOS (Cygwin, DJGPP, Mingw32)\n");
     print("sun      Solaris or SunOS\n");
@@ -658,7 +658,7 @@ sub getCompiler($$$) {
 #    make variable (e.g. make CC=gcc2).
 #
 #  - Configure needs to do test compiles.  The test is best if it uses
-#    the same compiler that the build eventually will use, but it's 
+#    the same compiler that the build eventually will use, but it's
 #    useful even if not.
 #
 # The value this subroutine returns is NOT the command name to invoke the
@@ -714,11 +714,11 @@ sub gccLinker() {
     # First, we assume that the compiler calls 'collect2' as the linker
     # front end.  The specs file might specify some other program, but
     # it usually says 'collect2'.
-    
+
     my $retval;
 
     my $collect2 = qx{gcc --print-prog-name=collect2};
-    
+
     if (defined($collect2)) {
         chomp($collect2);
         my $linker = qx{$collect2 -v 2>&1};
@@ -749,14 +749,14 @@ sub getLinker($$$$) {
             print("\n");
 
             my $default;
-            
+
             if ($compiler eq "gcc") {
                 $default = gccLinker();
             } else {
                 $default = "sun";
             }
             my $response = prompt("sun or gnu", $default);
-            
+
             if ($response eq "gnu") {
                 $$baseLinkerR = "GNU";
             } elsif ($response eq "sun") {
@@ -811,11 +811,11 @@ sub getLibTypes($$$$$$$$) {
 
     my $default = ($default_target eq "merge") ? "static" : "shared";
 
-    my ($netpbmlibtype, $netpbmlibsuffix, $shlibprefixlist, 
+    my ($netpbmlibtype, $netpbmlibsuffix, $shlibprefixlist,
         $willBuildShared, $staticlib_too);
-    
+
     my $response = prompt("static or shared", $default);
-    
+
     if ($response eq "shared") {
         $willBuildShared = $TRUE;
         if ($platform eq "WINDOWS") {
@@ -823,7 +823,7 @@ sub getLibTypes($$$$$$$$) {
             $netpbmlibsuffix = "dll";
             if ($subplatform eq "cygwin") {
                 $shlibprefixlist = "cyg lib";
-            } 
+            }
         } elsif ($platform eq "DARWIN") {
             $netpbmlibtype = "dylib";
             $netpbmlibsuffix = "dylib";
@@ -846,7 +846,7 @@ sub getLibTypes($$$$$$$$) {
         $netpbmlibtype = "unixstatic";
         $netpbmlibsuffix = "a";
         # targets, but needed for building
-        # libopt 
+        # libopt
     } else {
         print("'$response' isn't one of the choices.  \n" .
               "You must choose 'static' or 'shared'.\n");
@@ -857,18 +857,18 @@ sub getLibTypes($$$$$$$$) {
 
     # Note that we can't do both a static and shared library for AIX, because
     # they both have the same name: libnetpbm.a.
-    
-    if (($netpbmlibtype eq "unixshared" or 
-         $netpbmlibtype eq "irixshared" or 
+
+    if (($netpbmlibtype eq "unixshared" or
+         $netpbmlibtype eq "irixshared" or
          $netpbmlibtype eq "dll") and $netpbmlibsuffix ne "a") {
         print("Do you want to build static libraries too (for linking to \n");
         print("programs not in the Netpbm package?\n");
         print("\n");
-        
+
         my $default = "y";
-        
+
         my $response = prompt("(y)es or (n)o", $default);
-        
+
         if (uc($response) =~ /^(Y|YES)$/)  {
             $staticlib_too = "Y";
         } elsif (uc($response) =~ /^(N|NO)$/)  {
@@ -919,16 +919,16 @@ sub inttypesDefault() {
 
         my @candidateList = ("<inttypes.h>", "<sys/inttypes.h>",
                              "<types.h>", "<sys/types.h>");
-        
+
         for (my $i = 0; $i < @candidateList && !$works; ++$i) {
             my $candidate = $candidateList[$i];
             my @cSourceCode = (
                                "#include $candidate\n",
                                "int_fast32_t testvar;\n"
                                );
-            
+
             testCompile($cflags, \@cSourceCode, \my $success);
-            
+
             if ($success) {
                 $works = $candidate;
             }
@@ -961,7 +961,7 @@ sub getInttypes($) {
     print("\n");
 
     my $default = inttypesDefault();
-    
+
     while (!$gotit) {
         my $response = prompt("'#include' argument or NONE", $default);
 
@@ -1000,9 +1000,9 @@ sub getInt64($$) {
                            "#include $inttypes_h\n",
                            "int64_t testvar;\n"
                            );
-            
+
         testCompile($cflags, \@cSourceCode, \my $success);
-            
+
         if ($success) {
             print("You do.\n");
             $$haveInt64R = 'Y';
@@ -1034,9 +1034,9 @@ sub determineSseCapability($) {
         my @cSourceCode = (
                            "#include <emmintrin.h>\n",
                            );
-            
+
         testCompile($cflags, \@cSourceCode, \my $success);
-            
+
         if ($success) {
             print("It does.\n");
             $$haveEmmintrinR = $TRUE;
@@ -1115,9 +1115,9 @@ sub getTiffLibrary($@) {
         my $default = "libtiff" . libSuffix($platform);
 
         print("What is your TIFF (graphics format) library?\n");
-        
+
         my $response = prompt("library filename or 'none'", $default);
-        
+
         if ($response ne "none") {
             $tifflib = $response;
         }
@@ -1137,9 +1137,9 @@ sub getTiffLibrary($@) {
             $default = "default";
         }
         print("Where are the interface headers for it?\n");
-        
+
         my $response = prompt("TIFF header directory", $default);
-        
+
         if ($response ne "default") {
             $tiffhdr_dir = $response;
         }
@@ -1161,9 +1161,9 @@ sub getJpegLibrary($@) {
         my $default = "libjpeg" . libSuffix($platform);
 
         print("What is your JPEG (graphics format) library?\n");
-        
+
         my $response = prompt("library filename or 'none'", $default);
-        
+
         if ($response ne "none") {
             $jpeglib = $response;
         }
@@ -1178,9 +1178,9 @@ sub getJpegLibrary($@) {
             $default = "default";
         }
         print("Where are the interface headers for it?\n");
-        
+
         my $response = prompt("JPEG header directory", $default);
-        
+
         if ($response ne "default") {
             $jpeghdr_dir = $response;
         }
@@ -1218,9 +1218,9 @@ sub getPngLibrary($@) {
             my $default = "libpng" . libSuffix($platform);
 
             print("What is your PNG (graphics format) library?\n");
-            
+
             my $response = prompt("library filename or 'none'", $default);
-            
+
             if ($response ne "none") {
                 $pnglib = $response;
             }
@@ -1233,9 +1233,9 @@ sub getPngLibrary($@) {
             } else {
                 $default = "default";
             }
-            
+
             print("Where are the interface headers for it?\n");
-            
+
             my $response = prompt("PNG header directory", $default);
 
             if ($response ne "default") {
@@ -1258,9 +1258,9 @@ sub getZLibrary($@) {
         my $default = "libz" . libSuffix($platform);
 
         print("What is your Z (compression) library?\n");
-        
+
         my $response = prompt("library filename or 'none'", $default);
-        
+
         if ($response ne "none") {
             $zlib = $response;
         }
@@ -1273,11 +1273,11 @@ sub getZLibrary($@) {
         } else {
             $default = "default";
         }
-        
+
         print("Where are the interface headers for it?\n");
-        
+
         my $response = prompt("Z header directory", $default);
-        
+
         if ($response ne "default") {
             $zhdr_dir = $response;
         }
@@ -1315,9 +1315,9 @@ sub getX11Library($@) {
                 $default = "libX11" . libSuffix($platform);
             }
             print("What is your X11 (X client) library?\n");
-            
+
             my $response = prompt("library filename or 'none'", $default);
-            
+
             if ($response ne "none") {
                 $x11lib = $response;
             }
@@ -1328,9 +1328,9 @@ sub getX11Library($@) {
             $default = "default";
 
             print("Where are the interface headers for it?\n");
-            
+
             my $response = prompt("X11 header directory", $default);
-            
+
             if ($response ne "default") {
                 $x11hdr_dir = $response;
             }
@@ -1371,27 +1371,27 @@ sub getLinuxsvgaLibrary($@) {
         } else {
             $default = 'none';
         }
-            
+
         print("What is your Svgalib library?\n");
-        
+
         my $response = prompt("library filename or 'none'", $default);
-            
+
         if ($response ne 'none') {
             $svgalib = $response;
         }
     }
     if (defined($svgalib) && $svgalib ne 'none') {
         my $default;
-        
+
         if (-d('/usr/include/svgalib')) {
             $default = '/usr/include/svgalib';
         } else {
             $default = "default";
         }
         print("Where are the interface headers for it?\n");
-        
+
         my $response = prompt("Svgalib header directory", $default);
-        
+
         if ($response ne "default") {
             $svgalibhdr_dir = $response;
         }
@@ -1414,13 +1414,13 @@ sub symlink_command() {
     # simulation via a "ln" command, but have a "cp" command which works
     # in a pinch.  Some Windows environments have "ln", but it won't do
     # symbolic links.
-    
+
     if (commandExists("ln")) {
         # We assume if Perl can do symbolic links, so can Ln, and vice
         # versa.
 
         my $symlink_exists = eval { symlink("",""); 1 };
-        
+
         if ($symlink_exists) {
             $retval = "ln -s";
         } else {
@@ -1459,7 +1459,7 @@ sub gnuOptimizeOpt($) {
 #  that causes -O3 to generate incorrect code (symptom: pnmtojpeg --quality=95
 #  generates a syntax error message from shhopt).
 #-----------------------------------------------------------------------------
-# I don't know what are exactly the cases that Gcc is broken.  I know 
+# I don't know what are exactly the cases that Gcc is broken.  I know
 # Red Hat 7.1 and 7.2 and Mandrake 8.2, running gcc 2.96.1, commonly have
 # the problem.  But it may be limited to a certain subrelease level or
 # CPU type or other environment.  People who have reported the problem have
@@ -1472,7 +1472,7 @@ sub gnuOptimizeOpt($) {
     my @gccVerboseResp = `$gccCommandName --verbose 2>&1`;
 
     my $brokenCompiler;
-    
+
     if (@gccVerboseResp ==2) {
         if ($gccVerboseResp[1] =~ m{gcc version 2.96}) {
             $brokenCompiler = $TRUE;
@@ -1513,13 +1513,13 @@ sub wnostrictoverflowWorks($) {
     my ($cFile, $cFileName) = tempFile(".c");
 
     print $cFile "int x;";
-    
+
     my $compileCommand =
         "$gccCommandName -c -o /dev/null -Wno-strict-overflow $cFileName";
     print("Doing test compile to see if -Wno-strict-overflow works: "
           . "$compileCommand\n");
     my $rc = system($compileCommand);
-    
+
     unlink($cFileName);
     close($cFile);
 
@@ -1534,7 +1534,7 @@ sub gnuCflags($) {
     my $flags;
 
     $flags = gnuOptimizeOpt($gccCommandName) . " -ffast-math " .
-        " -pedantic -fno-common " . 
+        " -pedantic -fno-common " .
         "-Wall -Wno-uninitialized -Wmissing-declarations -Wimplicit " .
         "-Wwrite-strings -Wmissing-prototypes -Wundef " .
         "-Wno-unknown-pragmas ";
@@ -1577,7 +1577,7 @@ sub findProcessManagement($) {
     my @cSourceCode = (
                        "#include <sys/wait.h>\n",
                        );
-    
+
     testCompile($cflags, \@cSourceCode, \my $success);
 
     if (!$success) {
@@ -1637,7 +1637,7 @@ sub testCompileJpeglibH($$) {
                        "#include <stdio.h>\n",
                        "#include <jpeglib.h>\n",
                        );
-    
+
     testCompile($cflags, \@cSourceCode, $successR);
 }
 
@@ -1646,7 +1646,7 @@ sub testCompileJpeglibH($$) {
 sub testCompileJpegMarkerStruct($$) {
     my ($cflags, $successR) = @_;
 #-----------------------------------------------------------------------------
-#  Do a test compile to see if struct jpeg_marker_struct is defined in 
+#  Do a test compile to see if struct jpeg_marker_struct is defined in
 #  jpeglib.h.  Assume it is already established that the compiler works
 #  and can find jpeglib.h.
 #-----------------------------------------------------------------------------
@@ -1668,7 +1668,7 @@ sub printMissingHdrWarning($$) {
 
     warnUser("You said the compile-time part of the $name library " .
              "(the header files) is in " .
-             
+
              (defined($hdr_dir) ?
               "directory '$hdr_dir', " :
               "the compiler's default search path, ") .
@@ -1719,7 +1719,7 @@ sub testJpegHdr($) {
         } else {
             # We can get to something named jpeglib.h, but maybe it's an old
             # version we can't use.  Check it out.
-            testCompileJpegMarkerStruct("$generalCflags $jpegIOpt", 
+            testCompileJpegMarkerStruct("$generalCflags $jpegIOpt",
                                         \my $success);
             if (!$success) {
                 print("\n");
@@ -1789,7 +1789,7 @@ sub testCompileZlibH($$) {
     my @cSourceCode = (
                        "#include <zlib.h>\n",
                        );
-    
+
     testCompile($cflags, \@cSourceCode, $successR);
 }
 
@@ -1804,7 +1804,7 @@ sub testCompilePngH($$) {
     my @cSourceCode = (
                        "#include <png.h>\n",
                        );
-    
+
     testCompile($cflags, \@cSourceCode, $successR);
 }
 
@@ -1829,7 +1829,7 @@ sub testPngHdr($$) {
         } else {
             my $pngIOpt = $pnghdr_dir ? "-I$pnghdr_dir" : "";
 
-            testCompilePngH("$generalCflags $zlibIOpt $pngIOpt", 
+            testCompilePngH("$generalCflags $zlibIOpt $pngIOpt",
                             \my $success);
 
             if (!$success) {
@@ -1903,10 +1903,10 @@ sub testLinkPnglib($$) {
     } else {
         my $pngLdflags = qx{libpng-config --ldflags};
         chomp($pngLdflags);
-        
+
         testCompileLink("$generalCflags $pngCflags $pngLdflags",
                         \@cSourceCode, \my $success);
-        
+
         if (!$success) {
             testCompileLink("$generalCflags $pngCflags $pngLdflags -lz -lm",
                         \@cSourceCode, \my $lzLmSuccess);
@@ -1947,7 +1947,7 @@ sub testCompileXmlreaderH($$) {
     my @cSourceCode = (
                        "#include <libxml/xmlreader.h>\n",
                        );
-    
+
     testCompile($cflags, \@cSourceCode, $successR);
 }
 
@@ -1979,7 +1979,7 @@ sub testCompileXmlReaderTypes($$) {
                        "#include <libxml/xmlreader.h>\n",
                        "xmlReaderTypes dummy;\n",
                        );
-    
+
     testCompile($cflags, \@cSourceCode, $successR);
 }
 
@@ -2083,7 +2083,7 @@ if (@ARGV > 0) {
         } else {
             die("Unrecognized option: $ARGV[0]");
         }
-    } 
+    }
     $configInPathArg = $ARGV[0];
 }
 
@@ -2161,7 +2161,7 @@ print("\n");
 {
     my $default = "regular";
     my $response = prompt("regular or merge", $default);
-    
+
     if ($response eq "regular") {
         $default_target = "nonmerge";
     } elsif ($response eq "merge") {
@@ -2220,18 +2220,18 @@ my ($jpeglib, $jpeghdr_dir) = getJpegLibrary($platform);
 print("\n");
 my ($tifflib, $tiffhdr_dir) = getTiffLibrary($platform, $jpeghdr_dir);
 print("\n");
-my ($pnglib, $pnghdr_dir)   = getPngLibrary($platform, 
+my ($pnglib, $pnghdr_dir)   = getPngLibrary($platform,
                                             $tiffhdr_dir, $jpeghdr_dir);
 print("\n");
-my ($zlib, $zhdr_dir)       = getZLibrary($platform, 
+my ($zlib, $zhdr_dir)       = getZLibrary($platform,
                                           $pnghdr_dir,
                                           $tiffhdr_dir,
                                           $jpeghdr_dir);
 print("\n");
-my ($x11lib, $x11hdr_dir) = getX11Library($platform); 
+my ($x11lib, $x11hdr_dir) = getX11Library($platform);
 
 print("\n");
-my ($linuxsvgalib, $linuxsvgahdr_dir) = getLinuxsvgaLibrary($platform); 
+my ($linuxsvgalib, $linuxsvgahdr_dir) = getLinuxsvgaLibrary($platform);
 
 print("\n");
 
@@ -2241,27 +2241,6 @@ print("\n");
 
 #******************************************************************************
 #
-#  CONFIGURE DOCUMENTATION
-#
-#*****************************************************************************
-
-print("What URL will you use for the main Netpbm documentation page?\n");
-print("This information does not get built into any programs or libraries.\n");
-print("It does not make anything actually install that web page.\n");
-print("It is just for including in legacy man pages.\n");
-print("\n");
-
-my $default = "http://netpbm.sourceforge.net/doc/";
-
-my $netpbm_docurl = prompt("Documentation URL", $default);
-
-print("\n");
-
-
-
-
-#******************************************************************************
-#
 #  VALIDATE THE CONFIGURATION USER HAS SELECTED
 #
 #*****************************************************************************
@@ -2295,7 +2274,7 @@ if (-f("GNUmakefile")) {
     while (!$done) {
         print("Where is the Netpbm source code?\n");
 
-        $srcdir = prompt("Netpbm source directory", 
+        $srcdir = prompt("Netpbm source directory",
                          abs_path(dirname($0) . "/.."));
 
         if (-f("$srcdir/GNUmakefile")) {
@@ -2304,7 +2283,7 @@ if (-f("GNUmakefile")) {
             print("That doesn't appear to contain Netpbm source code.\n");
             print("There is no file named 'GNUmakefile' in it.\n");
             print("\n");
-        }    
+        }
     }
     unlink("GNUmakefile");
     symlink("$srcdir/GNUmakefile", "GNUmakefile");
@@ -2314,7 +2293,7 @@ if (-f("GNUmakefile")) {
     open(SRCDIR, ">srcdir.mk");
     print(SRCDIR "SRCDIR = $srcdir\n");
     close(SRCDIR);
-    
+
     $defaultConfigInPath = "$srcdir/config.mk.in";
 }
 
@@ -2341,7 +2320,7 @@ open (CONFIG_IN,"<$configInPath") or
 
 @config_mk = <CONFIG_IN>;
 
-unshift(@config_mk, 
+unshift(@config_mk,
         "####This file was automatically created by 'configure.'\n",
         "####Many variables are set twice -- a generic setting, then \n",
         "####a system-specific override at the bottom of the file.\n",
@@ -2381,7 +2360,7 @@ if ($platform eq "GNU") {
         push(@config_mk, gnuCflags('cc'));
     }
 # The merged programs have a main_XXX subroutine instead of main(),
-# which would cause a warning with -Wmissing-declarations or 
+# which would cause a warning with -Wmissing-declarations or
 # -Wmissing-prototypes.
     push(@config_mk, "CFLAGS_MERGE = " .
          "-Wno-missing-declarations -Wno-missing-prototypes\n");
@@ -2397,7 +2376,7 @@ if ($platform eq "GNU") {
     } else {
         makeCompilerGcc(\@config_mk);
     }
-    # Before Netpbm 10.20 (January 2004), we set this to -R for 
+    # Before Netpbm 10.20 (January 2004), we set this to -R for
     # $compiler == cc and -rpath otherwise.  But now we know that the GNU
     # compiler can also invoke a linker that needs -R, so we're more flexible.
     if ($baseLinker eq "GNU") {
@@ -2437,7 +2416,7 @@ if ($platform eq "GNU") {
              "-L/usr/local/lib\n");
         push(@config_mk, "LDSHLIB = -shared -expect_unresolved \"*\"\n");
     } else {
-        # We've never tested this.  This is just here to give a user a 
+        # We've never tested this.  This is just here to give a user a
         # headstart on submitting to us the necessary information.  2002.07.04.
         push(@config_mk, "CC = gcc\n");
         push(@config_mk, 'CFLAGS = -O3', "\n");
@@ -2473,7 +2452,7 @@ if ($platform eq "GNU") {
 #    }
     push(@config_mk, 'SYMLINK = ', symlink_command(), "\n");
     push(@config_mk, 'DLLVER=$(NETPBM_MAJOR_RELEASE)', "\n");
-    push(@config_mk, "LDSHLIB = " . 
+    push(@config_mk, "LDSHLIB = " .
          '-shared -Wl,--image-base=0x10000000 -Wl,--enable-auto-import', "\n");
     if ($subplatform ne "cygwin") {
         push(@config_mk, "MSVCRT = Y\n");
@@ -2484,7 +2463,7 @@ if ($platform eq "GNU") {
 } elsif ($platform eq "BEOS") {
     push(@config_mk, "LDSHLIB = -nostart\n");
 } elsif ($platform eq "OPENBSD") {
-    # vedge@vedge.com.ar says on 2001.04.29 that there are a ton of 
+    # vedge@vedge.com.ar says on 2001.04.29 that there are a ton of
     # undefined symbols in the Fiasco stuff on OpenBSD.  So we'll just
     # cut it out of the build until someone feels like fixing it.
     push(@config_mk, "BUILD_FIASCO = N\n");
@@ -2503,13 +2482,21 @@ if ($platform eq "GNU") {
         push(@config_mk, "SHLIB_CLIB =\n");
     } else {
         makeCompilerGcc(\@config_mk);
-        push(@config_mk, "LDSHLIB = -shared\n"); 
+        push(@config_mk, "LDSHLIB = -shared\n");
     }
     push(@config_mk, "NETWORKLD = -lsocket -lresolve\n");
 } elsif ($platform eq "DARWIN") {
     push(@config_mk, "CC = cc -no-cpp-precomp\n");
     push(@config_mk, gnuCflags('cc'));
     push(@config_mk, 'CFLAGS_SHLIB = -fno-common', "\n");
+    # -D_DARWIN_SOURCE is a hack.  We've seen build fail on MacOS because the
+    # C library erroneously neglects to include 'sprintf' and 'vasprintf' in
+    # <stdio.h> under the conditions under which Netpbm includes it.
+    # -D_DARWIN_SOURCE makes it include them.  *_SOURCE macros are supposed to
+    # be defined in the source code to which they apply, but since this is
+    # just a hack, we prefer to do it with a compiler option and leave the
+    # source code unsullied.
+    push(@config_mk, "CFLAGS += -D_DARWIN_SOURCE\n");
 
     my $installNameOpt;
     if ($netpbmlib_runtime_path eq '') {
@@ -2541,7 +2528,7 @@ if (!$flex_result) {
         print("You do not appear to have the 'flex' or 'lex' pattern \n");
         print("matcher generator on your system, so we will not build \n");
         print("programs that need it (Thinkjettopbm)\n");
-        
+
         print("\n");
         print("Press ENTER to continue.\n");
         my $key = <STDIN>;
@@ -2555,7 +2542,7 @@ if (!$flex_result) {
         print("find 'flex' on your system.\n");
         print("\n");
 
-        push(@config_mk, "LEX = lex\n"); 
+        push(@config_mk, "LEX = lex\n");
     }
 }
 
@@ -2605,10 +2592,6 @@ if (defined($linuxsvgalib)) {
     push(@config_mk, "LINUXSVGALIB = $linuxsvgalib\n");
 }
 
-if (defined($netpbm_docurl)) {
-    push(@config_mk, "NETPBM_DOCURL = $netpbm_docurl\n");
-}
-
 if ($inttypesHeaderFile ne '<inttypes.h>') {
     push(@config_mk, "INTTYPES_H = $inttypesHeaderFile\n");
 }
@@ -2653,4 +2636,4 @@ if ($warned) {
 print("\n");
 
 
-exit 0;          
+exit 0;
diff --git a/buildtools/debian/README b/buildtools/debian/README
index 7cefb249..3f74f494 100644
--- a/buildtools/debian/README
+++ b/buildtools/debian/README
@@ -37,17 +37,23 @@ To install Netpbm as a Debian package:
 PREREQUSISITES
 --------------
 
-The following information was taken from the Jessie version (Version 8) of
-Debian, in March 2017.
-
-You don't actually need the current version of any of these.  For example,
-while we list package libjpeg62-dev, the package libjpeg8-dev works fine.
+The following information was taken from the Stretch version (Version 9) of
+Debian, in June 2019.
 
 
 Building
 --------
 
-You need the following Debian packages to build all of Netpbm.
+You need the following Debian packages to build all of Netpbm.  These
+are in addition to what is in the base system.
+
+Build tools:
+
+  gcc
+  make
+  flex
+
+Libraries to link with Netpbm:
 
 You could omit some of these and, in the Netpbm build configuration dialog,
 indicate you don't have them, and the build will simply omit some parts.
@@ -56,20 +62,14 @@ will not build the 'pamx' program.
 
   libjpeg-dev
   libpng-dev
-  libtiff5-dev
+  libtiff-dev
   libx11-dev
   libxml2-dev
   zlib1g-dev
 
+Example:
 
-In addition, you need the following build tools:
-
-  make
-  gcc
-  flex
-  perl
-  pkg-config
-
+  $ apt-get install gcc
 
 
 Running
@@ -95,6 +95,10 @@ be pretty obvious what the problem is when you need the prerequisite package
 and don't have it, so if you don't want to install a prerequisite, it would
 probably be fine to force install Netpbm, ignoring the prerequisites.
 
+There is one part you cannot build with current Debian: 'ppmsvgalib'.  That is
+because Debian does not include the required libsvga library (the last version
+that did was 7).
+
 
 CONFLICTS WITH DEBIAN'S NETPBM
 ------------------------------
diff --git a/buildtools/debian/mkdeb b/buildtools/debian/mkdeb
index 51d77cdb..6c475530 100755
--- a/buildtools/debian/mkdeb
+++ b/buildtools/debian/mkdeb
@@ -3,7 +3,7 @@
 #                                mkdeb
 ###############################################################################
 #
-#  This generates a Debian packge file (.deb) to install Sourceforge
+#  This generates a Debian package file (.deb) to install Sourceforge
 #  Netpbm on a Debian system.
 #
 #  This is especially useful because Debian does not have a good Debian
@@ -89,13 +89,7 @@ sub netpbmVersion($) {
     } else {
         my $version = <VERSION>;
         chomp($version);
-
-        if ($version =~ m{^Netpbm (\S*)}) {
-            my ($versionNumber) = ($1);
-            $retval = $versionNumber;
-        } else {
-            die("Can't understand format of '$versionFileName': '$version'");
-        }
+        $retval = $version;
         close(VERSION);
     }
 
@@ -112,12 +106,30 @@ sub netpbmVersion($) {
 
 sub control($$) {
     my ($release, $architecture) = @_;
+#-----------------------------------------------------------------------------
+#  The contents for the package control file, as a hash reference.  In the
+#  referenced hash, there is one key for each line of the control file.  The
+#  key and value in the hash are the key and value for the line of the control
+#  file.
+#-----------------------------------------------------------------------------
 
-# The Debian packaging system doesn't provide a way to express Netpbm's actual
-# prerequisites.  For example, Netpbm needs Version 6.2 or better of Libjpeg,
-# but there is no way to state that here.  Instead, we state Libjpeg 6.2
-# exactly.  This makes the Netpbm package less useful.
-
+    # Because developers of some of the dependent libraries frequently switch
+    # to distributing versions not backward compatible with what they
+    # previously distributed, and Debian always packages the currently
+    # distributed version, it is virtually impossible to produce a Netpbm
+    # package that works in multiple Debian versions.  This program is coded
+    # to create a package that works on the Debian system the Netpbm
+    # maintainer currently uses to build the Debian packages he distributes.
+    # If you are building for any other version of Debian, you'll have to
+    # modify this code.
+
+    # Note that the backward incompatibility is usually only at a binary
+    # level, not source level.  And sometimes the only incompatibility for
+    # Netpbm purposes is that the soname has changed so that Linux will refuse
+    # to run a Netpbm program built for Debian N on Debian N-1.
+
+    # The following is for Debian 9.
+    
     my %control;
 
     my $debianNativeNetpbm = 
@@ -138,7 +150,7 @@ sub control($$) {
     $control{'Depends'} =
         'libc6, ' .
         'libjpeg62, ' .
-        'libpng12-0 | libpng16-16, ' .
+        'libpng16-16, ' .
         'libtiff5, ' .
         'libx11-6, ' .
         'libxml2, ' .
@@ -148,6 +160,8 @@ sub control($$) {
         'perl-base, ' .
         'bash'
         ;
+    # Note: Instead of libjpeg62, Debian 10 has libjpeg62-turbo and Ubuntu 18
+    # has libjpeg-turbo8.
     $control{'Conflicts'} = $debianNativeNetpbm;
     $control{'Replaces'} = $debianNativeNetpbm;
     $control{'Provides'} = 
diff --git a/buildtools/installnetpbm.pl b/buildtools/installnetpbm.pl
index d29fda1a..0c3679f8 100755
--- a/buildtools/installnetpbm.pl
+++ b/buildtools/installnetpbm.pl
@@ -990,7 +990,7 @@ sub installHeader($$$) {
         my $rc = system("cd $hdrDir; ln -s netpbm/* .");
 
         if ($rc != 0) {
-            print("Failed to create backward compatibilty symlinks from " .
+            print("Failed to create backward compatibility symlinks from " .
                   "$hdrDir into $hdrDir/netpbm\n");
             print("ln exit code is $rc\n");
         } else {
diff --git a/buildtools/makeman b/buildtools/makeman
index dc8e45ce..6ff40aca 100755
--- a/buildtools/makeman
+++ b/buildtools/makeman
@@ -2,17 +2,24 @@
 #
 # makeman -- compile netpbm's stereotyped HTML to troff markup
 #
-# This approach works because we control the entire document universe 
+# Example:
+#
+#    $ makeman pamcut.html pamcomp.html
+#
+#    $ makeman -v -d /tmp/inputdir pamcut.html
+#
+# The output troff file is in the same directory as the input HTML file, named
+# the same except with .1 extension.
+
+# This approach works because we control the entire document universe
 # this is going to convert and can reinforce useful stereotypes.
 #
 # The output of this tool uses cliches parseable by doclifter,
 # which should thus be able to recover all the semantic information
 # it looks like this thing is losing.
 #
-# Known bugs:
-#  * Ordered lists are smashed into unordered lists
-#
 # Limitations:
+#  * Ordered lists are smashed into unordered lists
 #  * IMG tags are issued as .IMG preceded by a bolded caption containing
 #    the alt content.  This will only work if the page is formatted with
 #    mwww macros.
@@ -29,7 +36,7 @@
 # Version 1.1, February 11 2016
 #
 #   Added ability to process &mdash; &minus;
-#   Added footer message to clarify original source. 
+#   Added footer message to clarify original source.
 #
 
 import os, sys, re
@@ -110,7 +117,7 @@ def makeman(name, file, indoc):
     indoc = ('.TH "%s" %d "%s" "%s"\n' % (title,section,date,source)) + indoc
     # Literal layout
     indoc = re.sub("(?i)\n *<PRE>", "\n.nf", indoc)
-    indoc = re.sub("(?i)\n *</PRE>", "\n.fi", indoc)
+    indoc = re.sub("(?i) *</PRE>\n", "\n.fi\n", indoc)
     indoc = re.sub("(?i)\n *<BLOCKQUOTE>", "\n.RS", indoc)
     indoc = re.sub("(?i)\n *</BLOCKQUOTE>", "\n.RE", indoc)
     # Highlight processing
@@ -151,8 +158,8 @@ def makeman(name, file, indoc):
     indoc = "\n".join(lines)
     indoc = re.sub(r"\s*\.sp", "\n.sp", indoc)
     # Format email addresses as italic
-    indoc = re.sub('(?i)<A[ \n]+HREF="mailto:[^>]+">([^<]+)</A>', r'\\fI\1\\fP', indoc)    
-    # Format manual crossreferences
+    indoc = re.sub('(?i)<A[ \n]+HREF="mailto:[^>]+">([^<]+)</A>', r'\\fI\1\\fP', indoc)
+    # Format manual cross-references
     def xrefmatch(match):
         xrefto = match.group(2)
         xrefurl = match.group(1)
@@ -200,7 +207,8 @@ def makeman(name, file, indoc):
     indoc = re.sub('(?i)<H2>([^><]*)</H2>', ".SH \\1", indoc)
     indoc = re.sub('(?i)<H3>([^><]*)</H3>', ".SS \\1", indoc)
     indoc = re.sub('(?i)<H4>([^><]*)</H4>', ".B \\1", indoc)
-    # 
+    indoc = re.sub('(?i)<H5>([^><]*)</H5>', ".B \\1", indoc)
+    #
     # Process definition lists -- just turn them into .TPs
     indoc = re.sub("(?i) *<DL *(COMPACT)?>", "", indoc)
     indoc = re.sub("(?i) *</DL>", "", indoc)
@@ -221,6 +229,15 @@ def makeman(name, file, indoc):
     # Acronyms
     indoc = re.sub('<acronym [a-zA-Z0-9:= \n"]*>', "", indoc)
     indoc = re.sub("</acronym>", "", indoc)
+    # Abbreviation - just erase tags
+    indoc = re.sub('<abbr [^>]+>', '', indoc)
+    indoc = re.sub('</abbr>', '', indoc)
+    # Subscript - just erase tags
+    indoc = re.sub('(?i)<sub [^>]+>', '', indoc)
+    indoc = re.sub('(?i)</sub>', '', indoc)
+    # Span - just erase tags
+    indoc = re.sub('(?i)<span [^>]+>', '', indoc)
+    indoc = re.sub('(?i)</span>', '', indoc)
     # Image tags
     indoc = re.sub(' *<img src="([^"]*)" alt="([^"]*)"( *[a-z]*="?[0-9]*"?)*>', ".B \\2\n.IMG -C \\1", indoc)
     # Special characters
@@ -236,7 +253,7 @@ def makeman(name, file, indoc):
     indoc = re.sub("(?i) *</table>.*", ".TE", indoc)
     # First the single-line case
     indoc = re.sub("(?i)</td> *<td>", "\t", indoc)
-    indoc = re.sub("(?i)<tr> *<td>", "", indoc)
+    indoc = re.sub("(?i)<tr> *<td( [^>]*)?>", "", indoc)
     indoc = re.sub("(?i)</td> *</tr>", "", indoc)
     # Then the multiline case
     indoc = re.sub(r'(?i)\s*<t[hd][^>]*>([^<\n]*)</t[dh]>\s*', '\t\\1', indoc)
@@ -248,6 +265,9 @@ def makeman(name, file, indoc):
     # Debugging
     #sys.stderr.write("Name: %s, Title: %s, Date: %s\n" % (name, title, date))
     # Time for error checking now
+    # We replaced every HTML tag we could above, so any remaining in
+    #   'indoc' represent material we don't know how to convert, which we call
+    #   bad lines.
     badlines = []
     for line in indoc.split("\n"):
         if "<" in line or ">" in line.replace(" >", "") or re.search(r'(?<!^\\)&.*;', line):
@@ -279,13 +299,15 @@ def main(args, mainout=sys.stdout, mainerr=sys.stderr):
         elif switch == '-v':	# Enable verbose error reporting
             verbosity += 1
     try:
-        # First pass: gather locations for crossreferences:
+        # First pass: gather locations for cross-references:
         sectmap = {}
         for file in arguments:
-            try: 
-                infp = open(os.path.join(dirprefix, file))
+            fullfilenm = os.path.join(dirprefix, file)
+            try:
+                infp = open(fullfilenm)
             except:
-                sys.stderr.write("makeman: can't open %s\n" % file)
+                sys.stderr.write(
+                    "makeman: can't open input file '%s'\n" % fullfilenm)
                 continue
             indoc = infp.read()
             infp.close()
@@ -313,10 +335,12 @@ def main(args, mainout=sys.stdout, mainerr=sys.stderr):
                 LiftException("%s has two <HR> tags!" % file)
         # Second pass: do formatting
         for file in arguments:
-            try: 
-                infp = open(os.path.join(dirprefix, file))
+            fullfilenm = os.path.join(dirprefix, file)
+            try:
+                infp = open(fullfilenm)
             except:
-                sys.stderr.write("makeman: can't open %s\n" % file)
+                sys.stderr.write(
+                    "makeman: can't open output file '%s'\n" % fullfilenm)
                 continue
             indoc = infp.read()
             infp.close()
diff --git a/common.mk b/common.mk
index 749488c2..c86ef910 100644
--- a/common.mk
+++ b/common.mk
@@ -144,13 +144,13 @@ IMPORTINC_ROOT_HEADERS := pm_config.h inttypes_netpbm.h version.h
 
 IMPORTINC_LIB_HEADERS := \
   pm.h pbm.h pgm.h ppm.h pnm.h pam.h pbmfont.h ppmcmap.h \
-  pammap.h colorname.h ppmfloyd.h ppmdraw.h pm_system.h ppmdfont.h \
+  pammap.h colorname.h ppmdraw.h pm_system.h ppmdfont.h \
   pm_gamma.h lum.h dithers.h pamdraw.h
 
 IMPORTINC_LIB_UTIL_HEADERS := \
   bitarith.h bitio.h bitreverse.h filename.h intcode.h floatcode.h io.h \
   matrix.h mallocvar.h \
-  nsleep.h nstring.h pm_c_util.h runlength.h shhopt.h token.h
+  nsleep.h nstring.h pm_c_util.h rand.h runlength.h shhopt.h token.h
 
 IMPORTINC_HEADERS := \
   $(IMPORTINC_ROOT_HEADERS) \
@@ -470,7 +470,7 @@ empty.c:
 # 2000.06.15
 
 # DJGPP can do SYMKINKs for programs but not for ordinary files, so
-# it define SYMLINKEXE, other system don't need it
+# it defines SYMLINKEXE, other system don't need it
 ifeq ($(SYMLINKEXE)x,x)
   SYMLINKEXE := $(SYMLINK)
 endif
diff --git a/config.mk.in b/config.mk.in
index ee692332..b79472b0 100644
--- a/config.mk.in
+++ b/config.mk.in
@@ -282,7 +282,7 @@ LDSHLIB = -shared -Wl,-soname,$(SONAME)
 #LDSHLIB=-dynamiclib
 #LDSHLIB=-dynamiclib -install_name $(NETPBMLIB_RUNTIME_PATH)/libnetpbm.$(MAJ).dylib
 
-# LDRELOC is the command to combine two .o files (relocateable object files)
+# LDRELOC is the command to combine two .o files (relocatable object files)
 # into a single .o file that can later be linked into something else.  NONE
 # means no such command is available.
 
@@ -657,16 +657,6 @@ DLLVER =
 #Cygwin
 #DLLVER = $(NETPBM_MAJOR_RELEASE)
 
-#NETPBM_DOCURL is the URL of the main documentation page for Netpbm.
-#This is a directory which contains a file for each Netpbm program,
-#library, and file type.  E.g. The documentation for jpegtopnm might be in
-#http://netpbm.sourceforge.net/doc/jpegtopnm.html .  This value gets
-#installed in the man pages (which say no more than to read the webpage)
-#and in the Manweb netpbm.url file.
-NETPBM_DOCURL = http://netpbm.sourceforge.net/doc/
-#For a system with no web access, but a local copy of the doc:
-#NETPBM_DOCURL = file:/usr/doc/netpbm/
-
 # RGB_DB_PATH is where Netpbm looks for the color database when the RGBDEF
 # environment variable is not set.  See pm_config.in.h for details.
 RGB_DB_PATH = /usr/local/netpbm/rgb.txt:/usr/share/netpbm/rgb.txt:/etc/X11/rgb.txt:/usr/lib/X11/rgb.txt:/usr/share/X11/rgb.txt:/usr/X11R6/lib/X11/rgb.txt
diff --git a/converter/other/Makefile b/converter/other/Makefile
index 2be88781..3b3b6aa0 100644
--- a/converter/other/Makefile
+++ b/converter/other/Makefile
@@ -7,10 +7,26 @@ VPATH=.:$(SRCDIR)/$(SUBDIR)
 
 include $(BUILDDIR)/config.mk
 
-TEST_PKGCONFIG_LIBXML2 = if $(PKG_CONFIG) libxml-2.0; then echo exists; fi
+# The pkg-config test used to be just 'pkg-config libxml-2.0', without the
+# --exists, and on at least one system, it does the same thing as --exists:
+# exit code 0 if the package exists; 1 if it does not, with no Standard
+# Output.  But we have evidence that on one system, it issues the whole
+# package not found try a different path, blah, blah, blah message that
+# looks like a failure in the build.  We're hoping --exists does not do that.
+# But maybe we didn't do --exists in the first place because it doesn't exist
+# on older pkg-config.  19.09.20.
+#
+# Note that --exists is better for another reason - it fails when the named
+# package exists, but it is unusable because its prerequisite packages don't.
+#
+# Also note that in both cases, the shell command fails if pkg-config
+# doesn't even exist.
+
+TEST_PKGCONFIG_LIBXML2 := \
+  if $(PKG_CONFIG) libxml-2.0 --exists; then echo exists; fi
 
 ifneq ($(shell $(TEST_PKGCONFIG_LIBXML2)),)
-  # pkg-config libxml2 works on this system
+  # pkg-config works and says libxml2 exists on this system
   XML2_LIBS = $(shell $(PKG_CONFIG) libxml-2.0 --libs)
   XML2_CFLAGS = $(shell $(PKG_CONFIG) libxml-2.0 --cflags)
 else
@@ -34,10 +50,11 @@ ifneq ($(TIFFLIB),NONE)
   endif
 endif
 
-TEST_PKGCONFIG_LIBPNG = if $(PKG_CONFIG) libpng$(PNGVER); then echo exists; fi
+TEST_PKGCONFIG_LIBPNG := \
+  if $(PKG_CONFIG) libpng$(PNGVER) --exists; then echo exists; fi
 
 ifneq ($(shell $(TEST_PKGCONFIG_LIBPNG)),)
-  # pkg-config libpng works on this system
+  # pkg-config works and says libpng exists on this system
   HAVE_PNGLIB = Y
   EXTERN_INCLUDES += $(shell $(PKG_CONFIG) libpng$(PNGVER) --cflags)
 else
@@ -117,14 +134,15 @@ PORTBINARIES =  avstopam bmptopnm fitstopnm \
 		gemtopnm giftopnm hdifftopam infotopam \
 		pamtoavs pamtodjvurle pamtofits pamtogif \
 		pamtohdiff pamtohtmltbl pamtompfont pamtooctaveimg \
-		pamtopam pamtopdbimg pamtopfm pamtopnm pamtosrf pamtouil \
+		pamtopam pamtopdbimg pamtopfm pamtopnm \
+                pamtoqoi pamtosrf pamtouil \
 		pamtowinicon pamtoxvmini \
 		pbmtopgm pdbimgtopam pfmtopam \
 	        pgmtopbm pgmtoppm ppmtopgm pnmtoddif \
 		pnmtopclxl pnmtorast \
-		pnmtosgi pnmtosir pamtotga pnmtoxwd \
+		pnmtosgi pnmtosir pamtotga pnmtoxwd qoitopam \
 		rasttopnm rlatopam sgitopnm sirtopnm srftopam sunicontopnm \
-		winicontopam xwdtopnm yuy2topam zeisstopnm
+		winicontopam xwdtopnm yuy2topam zeisstopnm \
 
 ifneq ($(DONT_HAVE_PROCESS_MGMT),Y)
   PORTBINARIES += pstopnm pnmtops
@@ -193,7 +211,7 @@ tifftopnm pamtotiff pnmtotiffcmyk: \
  $(shell $(LIBOPT)  $(LIBOPTR) $(TIFFLIB) $(TIFFLIB_EXTRALIBS))
 
 ifneq ($(shell $(TEST_PKGCONFIG_LIBPNG)),)
-  # pkg-config libpng works on this system
+  # pkg-config works and says libpng exists on this system
   PNGLIB_LIBOPTS = $(shell $(PKG_CONFIG) libpng$(PNGVER) --libs)
 else
   ifneq ($(shell libpng$(PNGVER)-config --version),)
diff --git a/converter/other/cameratopam/Makefile b/converter/other/cameratopam/Makefile
index d6207aea..bb4c4cde 100644
--- a/converter/other/cameratopam/Makefile
+++ b/converter/other/cameratopam/Makefile
@@ -20,7 +20,7 @@ include $(BUILDDIR)/config.mk
 all: cameratopam
 
 ADDL_OBJECTS = util.o identify.o camera.o foveon.o decode.o \
-	canon.o ljpeg.o dng.o
+	canon.o ljpeg.o dng.o stdio_nofail.o
 
 OBJECTS = cameratopam.o $(ADDL_OBJECTS)
 
diff --git a/converter/other/cameratopam/camera.c b/converter/other/cameratopam/camera.c
index 439c9413..4610462c 100644
--- a/converter/other/cameratopam/camera.c
+++ b/converter/other/cameratopam/camera.c
@@ -24,6 +24,7 @@
 #include "bayer.h"
 #include "ljpeg.h"
 #include "dng.h"
+#include "stdio_nofail.h"
 
 #include "camera.h"
 
@@ -94,8 +95,8 @@ adobe_dng_load_raw_lj(Image const image) {
     unsigned short *rp;
 
     while (1) {
-        save = ftell(ifp);
-        fseek (ifp, get4(ifp), SEEK_SET);
+        save = ftell_nofail(ifp);
+        fseek_nofail (ifp, get4(ifp), SEEK_SET);
         if (!ljpeg_start (ifp, &jh)) break;
         if (trow >= raw_height) break;
         if (jh.high > raw_height-trow)
@@ -113,7 +114,7 @@ adobe_dng_load_raw_lj(Image const image) {
                 adobeCopyPixel(image,
                                trow+jrow, tcol+jcol, &rp, use_secondary);
         }
-        fseek (ifp, save+4, SEEK_SET);
+        fseek_nofail (ifp, save+4, SEEK_SET);
         if ((tcol += twide) >= raw_width) {
             tcol = 0;
             trow += jh.high;
@@ -157,14 +158,14 @@ nikon_compressed_load_raw(Image const image) {
     init_decoder();
     make_decoder (nikon_tree, 0);
 
-    fseek (ifp, nikon_curve_offset, SEEK_SET);
+    fseek_nofail (ifp, nikon_curve_offset, SEEK_SET);
     read_shorts (ifp, vpred, 4);
     csize = get2(ifp);
     curve = calloc (csize, sizeof *curve);
     merror (curve, "nikon_compressed_load_raw()");
     read_shorts (ifp, curve, csize);
 
-    fseek (ifp, data_offset, SEEK_SET);
+    fseek_nofail (ifp, data_offset, SEEK_SET);
     getbits(ifp, -1);
 
     for (row=0; row < height; row++)
@@ -197,8 +198,8 @@ nikon_load_raw(Image const image) {
     if (model[0] == 'E') {
       row = irow * 2 % height + irow / (height/2);
       if (row == 1 && atoi(model+1) < 5000) {
-    fseek (ifp, 0, SEEK_END);
-    fseek (ifp, ftell(ifp)/2, SEEK_SET);
+    fseek_nofail (ifp, 0, SEEK_END);
+    fseek_nofail (ifp, ftell_nofail(ifp)/2, SEEK_SET);
     getbits(ifp, -1);
       }
     }
@@ -227,8 +228,8 @@ nikon_is_compressed()
     return 0;
   if (strcmp(model,"D100"))
     return 1;
-  fseek (ifp, data_offset, SEEK_SET);
-  fread (test, 1, 256, ifp);
+  fseek_nofail (ifp, data_offset, SEEK_SET);
+  fread_nofail (test, 1, 256, ifp);
   for (i=15; i < 256; i+=16)
     if (test[i]) return 1;
   return 0;
@@ -244,9 +245,9 @@ nikon_e990()
   const unsigned char often[] = { 0x00, 0x55, 0xaa, 0xff };
 
   memset (histo, 0, sizeof histo);
-  fseek (ifp, 2064*1540*3/4, SEEK_SET);
+  fseek_nofail (ifp, 2064*1540*3/4, SEEK_SET);
   for (i=0; i < 2000; i++)
-    histo[fgetc(ifp)]++;
+    histo[fgetc_nofail(ifp)]++;
   for (i=0; i < 4; i++)
     if (histo[often[i]] > 400)
       return 1;
@@ -262,9 +263,9 @@ nikon_e2100()
   unsigned char t[12];
   int i;
 
-  fseek (ifp, 0, SEEK_SET);
+  fseek_nofail (ifp, 0, SEEK_SET);
   for (i=0; i < 1024; i++) {
-    fread (t, 1, 12, ifp);
+    fread_nofail (t, 1, 12, ifp);
     if (((t[2] & t[4] & t[7] & t[9]) >> 4
     & t[1] & t[6] & t[8] & t[11] & 3) != 3)
       return 0;
@@ -281,8 +282,8 @@ pentax_optio33()
   int i, sum[] = { 0, 0 };
   unsigned char tail[952];
 
-  fseek (ifp, -sizeof tail, SEEK_END);
-  fread (tail, 1, sizeof tail, ifp);
+  fseek_nofail (ifp, -sizeof tail, SEEK_END);
+  fread_nofail (tail, 1, sizeof tail, ifp);
   for (i=0; i < sizeof tail; i++)
     sum[(i>>2) & 1] += tail[i];
   return sum[0] < sum[1]*4;
@@ -297,8 +298,8 @@ minolta_z2()
   int i;
   char tail[424];
 
-  fseek (ifp, -sizeof tail, SEEK_END);
-  fread (tail, 1, sizeof tail, ifp);
+  fseek_nofail (ifp, -sizeof tail, SEEK_END);
+  fread_nofail (tail, 1, sizeof tail, ifp);
   for (i=0; i < sizeof tail; i++)
     if (tail[i]) return 1;
   return 0;
@@ -313,10 +314,10 @@ nikon_e2100_load_raw(Image const image) {
 
   for (row=0; row <= height; row+=2) {
     if (row == height) {
-      fseek (ifp, ((width==1616) << 13) - (-ftell(ifp) & -2048), SEEK_SET);
+      fseek_nofail (ifp, ((width==1616) << 13) - (-ftell_nofail(ifp) & -2048), SEEK_SET);
       row = 1;
     }
-    fread (data, 1, width*3/2, ifp);
+    fread_nofail (data, 1, width*3/2, ifp);
     for (dp=data, pix=pixel; pix < pixel+width; dp+=12, pix+=8) {
       pix[0] = (dp[2] >> 4) + (dp[ 3] << 4);
       pix[1] = (dp[2] << 8) +  dp[ 1];
@@ -356,7 +357,7 @@ fuji_s2_load_raw(Image const image) {
   unsigned short pixel[2944];
   int row, col, r, c;
 
-  fseek (ifp, (2944*24+32)*2, SEEK_CUR);
+  fseek_nofail (ifp, (2944*24+32)*2, SEEK_CUR);
   for (row=0; row < 2144; row++) {
     read_shorts(ifp, pixel, 2944);
     for (col=0; col < 2880; col++) {
@@ -372,7 +373,7 @@ fuji_s3_load_raw(Image const image) {
   unsigned short pixel[4352];
   int row, col, r, c;
 
-  fseek (ifp, (4352*2+32)*2, SEEK_CUR);
+  fseek_nofail (ifp, (4352*2+32)*2, SEEK_CUR);
   for (row=0; row < 1440; row++) {
     read_shorts(ifp, pixel, 4352);
     for (col=0; col < 4288; col++) {
@@ -408,7 +409,7 @@ fuji_common_load_raw(Image        const image,
 void
 fuji_s5000_load_raw(Image const image) {
 
-  fseek (ifp, (1472*4+24)*2, SEEK_CUR);
+  fseek_nofail (ifp, (1472*4+24)*2, SEEK_CUR);
   fuji_common_load_raw(image, 1472, 1423, 2152);
 }
 
@@ -449,7 +450,7 @@ rollei_load_raw(Image const image) {
   unsigned iten=0, isix, i, buffer=0, row, col, todo[16];
 
   isix = raw_width * raw_height * 5 / 8;
-  while (fread (pixel, 1, 10, ifp) == 10) {
+  while (fread_or_eof_nofail (pixel, 1, 10, ifp) == 10) {
     for (i=0; i < 10; i+=2) {
       todo[i]   = iten++;
       todo[i+1] = pixel[i] << 8 | pixel[i+1];
@@ -474,11 +475,11 @@ phase_one_load_raw(Image const image) {
   int row, col, a, b;
   unsigned short *pixel, akey, bkey;
 
-  fseek (ifp, 8, SEEK_CUR);
-  fseek (ifp, get4(ifp) + 296, SEEK_CUR);
+  fseek_nofail (ifp, 8, SEEK_CUR);
+  fseek_nofail (ifp, get4(ifp) + 296, SEEK_CUR);
   akey = get2(ifp);
   bkey = get2(ifp);
-  fseek (ifp, data_offset + 12 + top_margin*raw_width*2, SEEK_SET);
+  fseek_nofail (ifp, data_offset + 12 + top_margin*raw_width*2, SEEK_SET);
   pixel = calloc (raw_width, sizeof *pixel);
   merror (pixel, "phase_one_load_raw()");
   for (row=0; row < height; row++) {
@@ -501,7 +502,7 @@ ixpress_load_raw(Image const image) {
   int row, col;
 
   order = 0x4949;
-  fseek (ifp, 304 + 6*2*4090, SEEK_SET);
+  fseek_nofail (ifp, 304 + 6*2*4090, SEEK_SET);
   for (row=height; --row >= 0; ) {
     read_shorts(ifp, pixel, 4090);
     for (col=0; col < width; col++)
@@ -567,7 +568,7 @@ olympus_e300_load_raw(Image const image) {
   merror (data, "olympus_e300_load_raw()");
   pixel = (unsigned short *) (data + dwide);
   for (row=0; row < height; row++) {
-    fread (data, 1, dwide, ifp);
+    fread_nofail (data, 1, dwide, ifp);
     for (dp=data, pix=pixel; pix < pixel+raw_width; dp+=3, pix+=2) {
       if (((dp-data) & 15) == 15) dp++;
       pix[0] = dp[1] << 8 | dp[0];
@@ -586,7 +587,7 @@ olympus_cseries_load_raw(Image const image) {
   for (irow=0; irow < height; irow++) {
     row = irow * 2 % height + irow / (height/2);
     if (row < 2) {
-      fseek (ifp, data_offset - row*(-width*height*3/4 & -2048), SEEK_SET);
+      fseek_nofail (ifp, data_offset - row*(-width*height*3/4 & -2048), SEEK_SET);
       getbits(ifp, -1);
     }
     for (col=0; col < width; col++)
@@ -602,7 +603,7 @@ eight_bit_load_raw(Image const image) {
   pixel = calloc (raw_width, sizeof *pixel);
   merror (pixel, "eight_bit_load_raw()");
   for (row=0; row < height; row++) {
-    fread (pixel, 1, raw_width, ifp);
+    fread_nofail (pixel, 1, raw_width, ifp);
     for (col=0; col < width; col++)
       BAYER(row,col) = pixel[col];
   }
@@ -617,7 +618,7 @@ casio_qv5700_load_raw(Image const image) {
   int row, col;
 
   for (row=0; row < height; row++) {
-    fread (data, 1, 3232, ifp);
+    fread_nofail (data, 1, 3232, ifp);
     for (dp=data, pix=pixel; dp < data+3220; dp+=5, pix+=4) {
       pix[0] = (dp[0] << 2) + (dp[1] >> 6);
       pix[1] = (dp[1] << 4) + (dp[2] >> 4);
@@ -783,7 +784,7 @@ fill_input_buffer (j_decompress_ptr cinfo)
   static char jpeg_buffer[4096];
   size_t nbytes;
 
-  nbytes = fread (jpeg_buffer, 1, 4096, ifp);
+  nbytes = fread_or_eof_nofail (jpeg_buffer, 1, 4096, ifp);
   swab (jpeg_buffer, jpeg_buffer, nbytes);
   cinfo->src->next_input_byte = jpeg_buffer;
   cinfo->src->bytes_in_buffer = nbytes;
@@ -840,7 +841,7 @@ kodak_dc120_load_raw(Image const image)
   int row, shift, col;
 
   for (row=0; row < height; row++) {
-    fread (pixel, 848, 1, ifp);
+    fread_nofail (pixel, 848, 1, ifp);
     shift = row * mul[row & 3] + add[row & 3];
     for (col=0; col < width; col++)
       BAYER(row,col) = (unsigned short) pixel[(col + shift) % 848];
@@ -878,7 +879,7 @@ kodak_easy_load_raw(Image const image)
   pixel = calloc (raw_width, sizeof *pixel);
   merror (pixel, "kodak_easy_load_raw()");
   for (row=0; row < height; row++) {
-    fread (pixel, 1, raw_width, ifp);
+    fread_nofail (pixel, 1, raw_width, ifp);
     for (col=0; col < raw_width; col++) {
       icol = col - left_margin;
       if (icol < width)
@@ -912,21 +913,21 @@ kodak_compressed_load_raw(Image const image)
       if ((col & 255) == 0) {       /* Get the bit-lengths of the */
     len = width - col;      /* next 256 pixel values      */
     if (len > 256) len = 256;
-    save = ftell(ifp);
+    save = ftell_nofail(ifp);
     for (israw=i=0; i < len; i+=2) {
-      c = fgetc(ifp);
+      c = fgetc_nofail(ifp);
       if ((blen[i+0] = c & 15) > 12 ||
           (blen[i+1] = c >> 4) > 12 )
         israw = 1;
     }
     bitbuf = bits = pred[0] = pred[1] = 0;
     if (len % 8 == 4) {
-      bitbuf  = fgetc(ifp) << 8;
-      bitbuf += fgetc(ifp);
+      bitbuf  = fgetc_nofail(ifp) << 8;
+      bitbuf += fgetc_nofail(ifp);
       bits = 16;
     }
     if (israw)
-      fseek (ifp, save, SEEK_SET);
+      fseek_nofail (ifp, save, SEEK_SET);
       }
       if (israw) {          /* If the data is not compressed */
     switch (col & 7) {
@@ -944,7 +945,7 @@ kodak_compressed_load_raw(Image const image)
     len = blen[col & 255];      /* Number of bits for this pixel */
     if (bits < len) {       /* Got enough bits in the buffer? */
       for (i=0; i < 32; i+=8)
-        bitbuf += (INT64) fgetc(ifp) << (bits+(i^8));
+        bitbuf += (INT64) fgetc_nofail(ifp) << (bits+(i^8));
       bits += 32;
     }
     diff = bitbuf & (0xffff >> (16-len));  /* Pull bits from buffer */
@@ -976,14 +977,14 @@ kodak_yuv_load_raw(Image const image)
     len = (width - col + 1) * 3 & -4;
     if (len > 384) len = 384;
     for (i=0; i < len; ) {
-      c = fgetc(ifp);
+      c = fgetc_nofail(ifp);
       blen[i++] = c & 15;
       blen[i++] = c >> 4;
     }
     li = bitbuf = bits = y[1] = y[3] = cb = cr = 0;
     if (len % 8 == 4) {
-      bitbuf  = fgetc(ifp) << 8;
-      bitbuf += fgetc(ifp);
+      bitbuf  = fgetc_nofail(ifp) << 8;
+      bitbuf += fgetc_nofail(ifp);
       bits = 16;
     }
       }
@@ -991,7 +992,7 @@ kodak_yuv_load_raw(Image const image)
     len = blen[li++];
     if (bits < len) {
       for (i=0; i < 32; i+=8)
-        bitbuf += (INT64) fgetc(ifp) << (bits+(i^8));
+        bitbuf += (INT64) fgetc_nofail(ifp) << (bits+(i^8));
       bits += 32;
     }
     diff = bitbuf & (0xffff >> (16-len));
@@ -1062,20 +1063,20 @@ sony_load_raw(Image const image)
   struct pixel * pixelrow;
   unsigned i, key, row, col;
 
-  fseek (ifp, 200896, SEEK_SET);
-  fseek (ifp, (unsigned) fgetc(ifp)*4 - 1, SEEK_CUR);
+  fseek_nofail (ifp, 200896, SEEK_SET);
+  fseek_nofail (ifp, (unsigned) fgetc_nofail(ifp)*4 - 1, SEEK_CUR);
   order = 0x4d4d;
   key = get4(ifp);
-  fseek (ifp, 164600, SEEK_SET);
-  fread (head, 1, 40, ifp);
+  fseek_nofail (ifp, 164600, SEEK_SET);
+  fread_nofail (head, 1, 40, ifp);
   sony_decrypt ((void *) head, 10, 1, key);
   for (i=26; i-- > 22; )
     key = key << 8 | head[i];
-  fseek (ifp, data_offset, SEEK_SET);
+  fseek_nofail (ifp, data_offset, SEEK_SET);
   MALLOCARRAY(pixelrow, raw_width);
   merror (pixelrow, "sony_load_raw()");
   for (row=0; row < height; row++) {
-    fread (pixelrow, 2, raw_width, ifp);
+    fread_nofail (pixelrow, 2, raw_width, ifp);
     sony_decrypt ((void *) pixelrow, raw_width/2, !row, key);
     for (col=9; col < left_margin; col++)
       black += pixelrow[col].bytes[0] * 256 + pixelrow[col].bytes[1];
@@ -1095,14 +1096,14 @@ parse_minolta(FILE * const ifp)
 {
   int save, tag, len, offset, high=0, wide=0;
 
-  fseek (ifp, 4, SEEK_SET);
+  fseek_nofail (ifp, 4, SEEK_SET);
   offset = get4(ifp) + 8;
-  while ((save=ftell(ifp)) < offset) {
+  while ((save=ftell_nofail(ifp)) < offset) {
     tag = get4(ifp);
     len = get4(ifp);
     switch (tag) {
       case 0x505244:                /* PRD */
-    fseek (ifp, 8, SEEK_CUR);
+    fseek_nofail (ifp, 8, SEEK_CUR);
     high = get2(ifp);
     wide = get2(ifp);
     break;
@@ -1114,9 +1115,9 @@ parse_minolta(FILE * const ifp)
     camera_blue = get2(ifp) / camera_blue;
     break;
       case 0x545457:                /* TTW */
-    parse_tiff(ifp, ftell(ifp));
+    parse_tiff(ifp, ftell_nofail(ifp));
     }
-    fseek (ifp, save+len+8, SEEK_SET);
+    fseek_nofail (ifp, save+len+8, SEEK_SET);
   }
   raw_height = high;
   raw_width  = wide;
@@ -1168,24 +1169,24 @@ parse_ciff(FILE * const ifp,
       strcmp(model,"Canon PowerShot S70") &&
       strcmp(model,"Canon PowerShot Pro1"))
     key[0] = key[1] = 0;
-  fseek (ifp, offset+length-4, SEEK_SET);
+  fseek_nofail (ifp, offset+length-4, SEEK_SET);
   tboff = get4(ifp) + offset;
-  fseek (ifp, tboff, SEEK_SET);
+  fseek_nofail (ifp, tboff, SEEK_SET);
   nrecs = get2(ifp);
   for (i = 0; i < nrecs; i++) {
     type = get2(ifp);
     len  = get4(ifp);
     roff = get4(ifp);
     aoff = offset + roff;
-    save = ftell(ifp);
+    save = ftell_nofail(ifp);
     if (type == 0x080a) {       /* Get the camera make and model */
-      fseek (ifp, aoff, SEEK_SET);
-      fread (make, 64, 1, ifp);
-      fseek (ifp, aoff+strlen(make)+1, SEEK_SET);
-      fread (model, 64, 1, ifp);
+      fseek_nofail (ifp, aoff, SEEK_SET);
+      fread_nofail (make, 64, 1, ifp);
+      fseek_nofail (ifp, aoff+strlen(make)+1, SEEK_SET);
+      fread_nofail (model, 64, 1, ifp);
     }
     if (type == 0x102a) {       /* Find the White Balance index */
-      fseek (ifp, aoff+14, SEEK_SET);   /* 0=auto, 1=daylight, 2=cloudy ... */
+      fseek_nofail (ifp, aoff+14, SEEK_SET);   /* 0=auto, 1=daylight, 2=cloudy ... */
       wbi = get2(ifp);
       if (((!strcmp(model,"Canon EOS DIGITAL REBEL") ||
         !strcmp(model,"Canon EOS 300D DIGITAL"))) && wbi == 6)
@@ -1194,19 +1195,19 @@ parse_ciff(FILE * const ifp,
     if (type == 0x102c) {       /* Get white balance (G2) */
       if (!strcmp(model,"Canon PowerShot G1") ||
       !strcmp(model,"Canon PowerShot Pro90 IS")) {
-    fseek (ifp, aoff+120, SEEK_SET);
+    fseek_nofail (ifp, aoff+120, SEEK_SET);
     white[0][1] = get2(ifp);
     white[0][0] = get2(ifp);
     white[1][0] = get2(ifp);
     white[1][1] = get2(ifp);
       } else {
-    fseek (ifp, aoff+100, SEEK_SET);
+    fseek_nofail (ifp, aoff+100, SEEK_SET);
     goto common;
       }
     }
     if (type == 0x0032) {       /* Get white balance (D30 & G3) */
       if (!strcmp(model,"Canon EOS D30")) {
-    fseek (ifp, aoff+72, SEEK_SET);
+    fseek_nofail (ifp, aoff+72, SEEK_SET);
 common:
     camera_red   = get2(ifp) ^ key[0];
     camera_red   =(get2(ifp) ^ key[1]) / camera_red;
@@ -1214,13 +1215,13 @@ common:
     camera_blue /= get2(ifp) ^ key[1];
       } else if (!strcmp(model,"Canon PowerShot G6") ||
          !strcmp(model,"Canon PowerShot S70")) {
-    fseek (ifp, aoff+96 + remap_s70[wbi]*8, SEEK_SET);
+    fseek_nofail (ifp, aoff+96 + remap_s70[wbi]*8, SEEK_SET);
     goto common;
       } else if (!strcmp(model,"Canon PowerShot Pro1")) {
-    fseek (ifp, aoff+96 + wbi*8, SEEK_SET);
+    fseek_nofail (ifp, aoff+96 + wbi*8, SEEK_SET);
     goto common;
       } else {
-    fseek (ifp, aoff+80 + (wbi < 6 ? remap[wbi]*8 : 0), SEEK_SET);
+    fseek_nofail (ifp, aoff+80 + (wbi < 6 ? remap[wbi]*8 : 0), SEEK_SET);
     if (!camera_red)
       goto common;
       }
@@ -1228,38 +1229,38 @@ common:
     if (type == 0x10a9) {       /* Get white balance (D60) */
       if (!strcmp(model,"Canon EOS 10D"))
     wbi = remap_10d[wbi];
-      fseek (ifp, aoff+2 + wbi*8, SEEK_SET);
+      fseek_nofail (ifp, aoff+2 + wbi*8, SEEK_SET);
       camera_red  = get2(ifp);
       camera_red /= get2(ifp);
       camera_blue = get2(ifp);
       camera_blue = get2(ifp) / camera_blue;
     }
     if (type == 0x1030 && (wbi == 6 || wbi == 15)) {
-      fseek (ifp, aoff, SEEK_SET);  /* Get white sample */
+      fseek_nofail (ifp, aoff, SEEK_SET);  /* Get white sample */
       ciff_block_1030();
     }
     if (type == 0x1031) {       /* Get the raw width and height */
-      fseek (ifp, aoff+2, SEEK_SET);
+      fseek_nofail (ifp, aoff+2, SEEK_SET);
       raw_width  = get2(ifp);
       raw_height = get2(ifp);
     }
     if (type == 0x180e) {       /* Get the timestamp */
-      fseek (ifp, aoff, SEEK_SET);
+      fseek_nofail (ifp, aoff, SEEK_SET);
       timestamp = get4(ifp);
     }
     if (type == 0x580e)
       timestamp = len;
     if (type == 0x1810) {       /* Get the rotation */
-      fseek (ifp, aoff+12, SEEK_SET);
+      fseek_nofail (ifp, aoff+12, SEEK_SET);
       flip = get4(ifp);
     }
     if (type == 0x1835) {       /* Get the decoder table */
-      fseek (ifp, aoff, SEEK_SET);
+      fseek_nofail (ifp, aoff, SEEK_SET);
       crw_init_tables (get4(ifp));
     }
     if (type >> 8 == 0x28 || type >> 8 == 0x30) /* Get sub-tables */
       parse_ciff(ifp, aoff, len);
-    fseek (ifp, save, SEEK_SET);
+    fseek_nofail (ifp, save, SEEK_SET);
   }
   if (wbi == 0 && !strcmp(model,"Canon EOS D30"))
     camera_red = -1;            /* Use my auto WB for this photo */
@@ -1273,9 +1274,9 @@ parse_rollei(FILE * const ifp)
   struct tm t;
   time_t ts;
 
-  fseek (ifp, 0, SEEK_SET);
+  fseek_nofail (ifp, 0, SEEK_SET);
   do {
-    fgets (line, 128, ifp);
+    fgets_nofail (line, 128, ifp);
     if ((val = strchr(line,'=')))
       *val++ = 0;
     else
@@ -1314,13 +1315,13 @@ parse_mos(FILE * const ifp,
     char data[40];
     int skip, from, i, neut[4];
 
-    fseek (ifp, offset, SEEK_SET);
+    fseek_nofail (ifp, offset, SEEK_SET);
     while (1) {
-        fread (data, 1, 8, ifp);
+        fread_nofail (data, 1, 8, ifp);
         if (strcmp(data,"PKTS")) break;
-        fread (data, 1, 40, ifp);
+        fread_nofail (data, 1, 40, ifp);
         skip = get4(ifp);
-        from = ftell(ifp);
+        from = ftell_nofail(ifp);
         if (!strcmp(data,"NeutObj_neutrals")) {
             for (i=0; i < 4; i++)
                 fscanf (ifp, "%d", neut+i);
@@ -1328,7 +1329,7 @@ parse_mos(FILE * const ifp,
             camera_blue = (float) neut[2] / neut[3];
         }
         parse_mos(ifp, from);
-        fseek (ifp, skip+from, SEEK_SET);
+        fseek_nofail (ifp, skip+from, SEEK_SET);
     }
 }
 
@@ -1369,43 +1370,43 @@ parse_makernote(FILE * const ifp)
    its own byte-order!), or it might just be a table.
  */
   sorder = order;
-  fread (buf, 1, 10, ifp);
+  fread_nofail (buf, 1, 10, ifp);
   if (!strncmp (buf,"KC" ,2) ||     /* these aren't TIFF format */
       !strncmp (buf,"MLY",3)) return;
   if (!strcmp (buf,"Nikon")) {
-    base = ftell(ifp);
+    base = ftell_nofail(ifp);
     order = get2(ifp);
     if (get2(ifp) != 42) goto quit;
     offset = get4(ifp);
-    fseek (ifp, offset-8, SEEK_CUR);
+    fseek_nofail (ifp, offset-8, SEEK_CUR);
   } else if (!strncmp (buf,"FUJIFILM",8) ||
          !strcmp  (buf,"Panasonic")) {
     order = 0x4949;
-    fseek (ifp,  2, SEEK_CUR);
+    fseek_nofail (ifp,  2, SEEK_CUR);
   } else if (!strcmp (buf,"OLYMP") ||
          !strcmp (buf,"LEICA") ||
          !strcmp (buf,"EPSON"))
-    fseek (ifp, -2, SEEK_CUR);
+    fseek_nofail (ifp, -2, SEEK_CUR);
   else if (!strcmp (buf,"AOC") ||
        !strcmp (buf,"QVC"))
-    fseek (ifp, -4, SEEK_CUR);
-  else fseek (ifp, -10, SEEK_CUR);
+    fseek_nofail (ifp, -4, SEEK_CUR);
+  else fseek_nofail (ifp, -10, SEEK_CUR);
 
   entries = get2(ifp);
   while (entries--) {
     tag  = get2(ifp);
     type = get2(ifp);
     len  = get4(ifp);
-    save = ftell(ifp);
+    save = ftell_nofail(ifp);
     if (len * size[type < 13 ? type:0] > 4)
-      fseek (ifp, get4(ifp)+base, SEEK_SET);
+      fseek_nofail (ifp, get4(ifp)+base, SEEK_SET);
 
     if (tag == 0xc && len == 4) {
       camera_red  = getrat();
       camera_blue = getrat();
     }
     if (tag == 0x14 && len == 2560 && type == 7) {
-      fseek (ifp, 1248, SEEK_CUR);
+      fseek_nofail (ifp, 1248, SEEK_CUR);
       goto get2_256;
     }
     if (strstr(make,"PENTAX")) {
@@ -1413,19 +1414,19 @@ parse_makernote(FILE * const ifp)
       if (tag == 0x1c) tag = 0x1017;
     }
     if (tag == 0x8c)
-      nikon_curve_offset = ftell(ifp) + 2112;
+      nikon_curve_offset = ftell_nofail(ifp) + 2112;
     if (tag == 0x96)
-      nikon_curve_offset = ftell(ifp) + 2;
+      nikon_curve_offset = ftell_nofail(ifp) + 2;
     if (tag == 0x97) {
       if (!strcmp(model,"NIKON D100 ")) {
-    fseek (ifp, 72, SEEK_CUR);
+    fseek_nofail (ifp, 72, SEEK_CUR);
     camera_red  = get2(ifp) / 256.0;
     camera_blue = get2(ifp) / 256.0;
       } else if (!strcmp(model,"NIKON D2H")) {
-    fseek (ifp, 10, SEEK_CUR);
+    fseek_nofail (ifp, 10, SEEK_CUR);
     goto get2_rggb;
       } else if (!strcmp(model,"NIKON D70")) {
-    fseek (ifp, 20, SEEK_CUR);
+    fseek_nofail (ifp, 20, SEEK_CUR);
     camera_red  = get2(ifp);
     camera_red /= get2(ifp);
     camera_blue = get2(ifp);
@@ -1449,12 +1450,12 @@ parse_makernote(FILE * const ifp)
       black = (get4(ifp)+get4(ifp)+get4(ifp)+get4(ifp))/4;
     }
     if (tag == 0xe80 && len == 256 && type == 7) {
-      fseek (ifp, 48, SEEK_CUR);
+      fseek_nofail (ifp, 48, SEEK_CUR);
       camera_red  = get2(ifp) * 508 * 1.078 / 0x10000;
       camera_blue = get2(ifp) * 382 * 1.173 / 0x10000;
     }
     if (tag == 0xf00 && len == 614 && type == 7) {
-      fseek (ifp, 188, SEEK_CUR);
+      fseek_nofail (ifp, 188, SEEK_CUR);
       goto get2_256;
     }
     if (tag == 0x1017)
@@ -1468,14 +1469,14 @@ get2_256:
       camera_blue = get2(ifp) / 256.0;
     }
     if (tag == 0x4001) {
-      fseek (ifp, strstr(model,"EOS-1D") ? 68:50, SEEK_CUR);
+      fseek_nofail (ifp, strstr(model,"EOS-1D") ? 68:50, SEEK_CUR);
 get2_rggb:
       camera_red  = get2(ifp);
       camera_red /= get2(ifp);
       camera_blue = get2(ifp);
       camera_blue = get2(ifp) / camera_blue;
     }
-    fseek (ifp, save+4, SEEK_SET);
+    fseek_nofail (ifp, save+4, SEEK_SET);
   }
 quit:
   order = sorder;
@@ -1514,8 +1515,8 @@ parse_exif(FILE * const ifp, int base)
     /* type = */ get2(ifp);
     len  = get4(ifp);
     val  = get4(ifp);
-    save = ftell(ifp);
-    fseek (ifp, base+val, SEEK_SET);
+    save = ftell_nofail(ifp);
+    fseek_nofail (ifp, base+val, SEEK_SET);
     if (tag == 0x9003 || tag == 0x9004)
       get_timestamp(ifp);
     if (tag == 0x927c) {
@@ -1524,7 +1525,7 @@ parse_exif(FILE * const ifp, int base)
       else
     parse_makernote(ifp);
     }
-    fseek (ifp, save, SEEK_SET);
+    fseek_nofail (ifp, save, SEEK_SET);
   }
 }
 
@@ -1550,10 +1551,10 @@ parse_tiff_ifd(FILE * const ifp, int base, int level)
     tag  = get2(ifp);
     type = get2(ifp);
     len  = get4(ifp);
-    save = ftell(ifp);
+    save = ftell_nofail(ifp);
     if (tag > 50700 && tag < 50800) done = 1;
     if (len * size[type < 13 ? type:0] > 4)
-      fseek (ifp, get4(ifp)+base, SEEK_SET);
+      fseek_nofail (ifp, get4(ifp)+base, SEEK_SET);
     switch (tag) {
       case 0x11:
     camera_red  = get4(ifp) / 256.0;
@@ -1580,10 +1581,10 @@ parse_tiff_ifd(FILE * const ifp, int base, int level)
     kodak_data_compression = get2(ifp);
     break;
       case 0x10f:           /* Make */
-    fgets (make, 64, ifp);
+    fgets_nofail (make, 64, ifp);
     break;
       case 0x110:           /* Model */
-    fgets (model, 64, ifp);
+    fgets_nofail (model, 64, ifp);
     break;
       case 0x111:           /* StripOffset */
     data_offset = get4(ifp);
@@ -1595,7 +1596,7 @@ parse_tiff_ifd(FILE * const ifp, int base, int level)
     tiff_samples = get2(ifp);
     break;
       case 0x131:           /* Software tag */
-    fgets (software, 64, ifp);
+    fgets_nofail (software, 64, ifp);
     if (!strncmp(software,"Adobe",5))
       make[0] = 0;
     break;
@@ -1604,7 +1605,7 @@ parse_tiff_ifd(FILE * const ifp, int base, int level)
     break;
       case 0x144:           /* TileOffsets */
     if (level) {
-      data_offset = ftell(ifp);
+      data_offset = ftell_nofail(ifp);
     } else {
       strcpy (make, "Leaf");
       data_offset = get4(ifp);
@@ -1614,18 +1615,18 @@ parse_tiff_ifd(FILE * const ifp, int base, int level)
     if (len > 2 && !is_dng && !strcmp(make,"Kodak"))
         len = 2;
     while (len--) {
-      i = ftell(ifp);
-      fseek (ifp, get4(ifp)+base, SEEK_SET);
+      i = ftell_nofail(ifp);
+      fseek_nofail (ifp, get4(ifp)+base, SEEK_SET);
       if (parse_tiff_ifd(ifp, base, level+1)) break;
-      fseek (ifp, i+4, SEEK_SET);
+      fseek_nofail (ifp, i+4, SEEK_SET);
     }
     break;
       case 33405:           /* Model2 */
-    fgets (model2, 64, ifp);
+    fgets_nofail (model2, 64, ifp);
     break;
       case 33422:           /* CFAPattern */
     if ((plen=len) > 16) plen = 16;
-    fread (cfa_pat, 1, plen, ifp);
+    fread_nofail (cfa_pat, 1, plen, ifp);
     for (colors=cfa=i=0; i < plen; i++) {
       colors += !(cfa & (1 << cfa_pat[i]));
       cfa |= 1 << cfa_pat[i];
@@ -1634,7 +1635,7 @@ parse_tiff_ifd(FILE * const ifp, int base, int level)
     if (cfa == 072) memcpy (cfa_pc,"\005\003\004\001",4);   /* GMCY */
     goto guess_cfa_pc;
       case 34665:           /* EXIF tag */
-    fseek (ifp, get4(ifp)+base, SEEK_SET);
+    fseek_nofail (ifp, get4(ifp)+base, SEEK_SET);
     parse_exif(ifp, base);
     break;
       case 50706:           /* DNGVersion */
@@ -1644,7 +1645,7 @@ parse_tiff_ifd(FILE * const ifp, int base, int level)
       case 50710:           /* CFAPlaneColor */
     if (len > 4) len = 4;
     colors = len;
-    fread (cfa_pc, 1, colors, ifp);
+    fread_nofail (cfa_pc, 1, colors, ifp);
 guess_cfa_pc:
     FORC4 tab[cfa_pc[c]] = c;
     for (i=16; i--; )
@@ -1701,7 +1702,7 @@ guess_cfa_pc:
     xyz[1] = getrat();
     xyz[2] = 1 - xyz[0] - xyz[1];
     }
-    fseek (ifp, save+4, SEEK_SET);
+    fseek_nofail (ifp, save+4, SEEK_SET);
   }
   for (i=0; i < colors; i++)
     FORC4 cc[i][c] *= ab[i];
@@ -1729,16 +1730,16 @@ parse_tiff(FILE * const ifp, int base)
 {
   int doff;
 
-  fseek (ifp, base, SEEK_SET);
+  fseek_nofail (ifp, base, SEEK_SET);
   order = get2(ifp);
   if (order != 0x4949 && order != 0x4d4d) return;
   get2(ifp);
   while ((doff = get4(ifp))) {
-    fseek (ifp, doff+base, SEEK_SET);
+    fseek_nofail (ifp, doff+base, SEEK_SET);
     if (parse_tiff_ifd(ifp, base, 0)) break;
   }
   if (!is_dng && !strncmp(make,"Kodak",5)) {
-    fseek (ifp, 12+base, SEEK_SET);
+    fseek_nofail (ifp, 12+base, SEEK_SET);
     parse_tiff_ifd(ifp, base, 2);
   }
 }
diff --git a/converter/other/cameratopam/cameratopam.c b/converter/other/cameratopam/cameratopam.c
index 2c832714..78eb6854 100644
--- a/converter/other/cameratopam/cameratopam.c
+++ b/converter/other/cameratopam/cameratopam.c
@@ -10,7 +10,7 @@
 #define _DEFAULT_SOURCE 1 /* New name for SVID & BSD source defines */
 #define _BSD_SOURCE 1   /* Make sure string.h contains strdup() */
 #define _XOPEN_SOURCE 500
-   /* Make sure unistd.h contains swab(), string.h constains strdup() */
+   /* Make sure unistd.h contains swab(), string.h contains strdup() */
 
 #include "pm_config.h"
 
diff --git a/converter/other/cameratopam/canon.c b/converter/other/cameratopam/canon.c
index 96a6210b..cbf5ece0 100644
--- a/converter/other/cameratopam/canon.c
+++ b/converter/other/cameratopam/canon.c
@@ -6,9 +6,10 @@
 #include "decode.h"
 #include "bayer.h"
 #include "canon.h"
+#include "stdio_nofail.h"
 
 
-void 
+void
 canon_600_load_raw(Image const image) {
     unsigned char  data[1120], *dp;
     unsigned short pixel[896], *pix;
@@ -16,7 +17,7 @@ canon_600_load_raw(Image const image) {
 
     for (irow=orow=0; irow < height; irow++)
     {
-        fread (data, 1120, 1, ifp);
+        fread_nofail (data, 1120, 1, ifp);
         for (dp=data, pix=pixel; dp < data+1120; dp+=10, pix+=8)
         {
             pix[0] = (dp[0] << 2) + (dp[1] >> 6    );
@@ -48,7 +49,7 @@ canon_a5_load_raw(Image const image) {
     int row, col;
 
     for (row=0; row < height; row++) {
-        fread (data, raw_width * 10 / 8, 1, ifp);
+        fread_nofail (data, raw_width * 10 / 8, 1, ifp);
         for (dp=data, pix=pixel; pix < pixel+raw_width; dp+=10, pix+=8)
         {
             pix[0] = (dp[1] << 2) + (dp[0] >> 6);
@@ -84,8 +85,8 @@ canon_has_lowbits()
     unsigned char test[0x4000];
     int ret=1, i;
 
-    fseek (ifp, 0, SEEK_SET);
-    fread (test, 1, sizeof test, ifp);
+    fseek_nofail (ifp, 0, SEEK_SET);
+    fread_nofail (test, 1, sizeof test, ifp);
     for (i=540; i < sizeof test - 1; i++)
         if (test[i] == 0xff) {
             if (test[i+1]) return 1;
@@ -96,7 +97,7 @@ canon_has_lowbits()
 
 
 
-void 
+void
 canon_compressed_load_raw(Image const image) {
     unsigned short *pixel, *prow;
     int lowbits, i, row, r, col, save, val;
@@ -110,7 +111,7 @@ canon_compressed_load_raw(Image const image) {
         pm_error("Unable to allocate space for %u pixels", raw_width*8);
     lowbits = canon_has_lowbits();
     if (!lowbits) maximum = 0x3ff;
-    fseek (ifp, 540 + lowbits*raw_height*raw_width/4, SEEK_SET);
+    fseek_nofail (ifp, 540 + lowbits*raw_height*raw_width/4, SEEK_SET);
     zero_after_ff = 1;
     getbits(ifp, -1);
     for (row = 0; row < raw_height; row += 8) {
@@ -141,17 +142,17 @@ canon_compressed_load_raw(Image const image) {
             }
         }
         if (lowbits) {
-            save = ftell(ifp);
-            fseek (ifp, 26 + row*raw_width/4, SEEK_SET);
+            save = ftell_nofail(ifp);
+            fseek_nofail (ifp, 26 + row*raw_width/4, SEEK_SET);
             for (prow=pixel, i=0; i < raw_width*2; i++) {
-                c = fgetc(ifp);
+                c = fgetc_nofail(ifp);
                 for (r=0; r < 8; r+=2, prow++) {
                     val = (*prow << 2) + ((c >> r) & 3);
                     if (raw_width == 2672 && val < 512) val += 2;
                     *prow = val;
                 }
             }
-            fseek (ifp, save, SEEK_SET);
+            fseek_nofail (ifp, save, SEEK_SET);
         }
         for (r=0; r < 8; r++) {
             irow = row - top_margin + r;
@@ -169,4 +170,3 @@ canon_compressed_load_raw(Image const image) {
     if (raw_width > width)
         black /= (raw_width - width) * height;
 }
-
diff --git a/converter/other/cameratopam/foveon.c b/converter/other/cameratopam/foveon.c
index 992f3883..5a26777b 100644
--- a/converter/other/cameratopam/foveon.c
+++ b/converter/other/cameratopam/foveon.c
@@ -2,7 +2,6 @@
 
 #define _XOPEN_SOURCE 500  /* get M_PI in math.h */
 
-#include <stdio.h>
 #include <assert.h>
 #include <string.h>
 #include <float.h>
@@ -13,6 +12,7 @@
 #include "global_variables.h"
 #include "decode.h"
 #include "foveon.h"
+#include "stdio_nofail.h"
 
 #if HAVE_INT64
    typedef int64_t INT64;
@@ -32,13 +32,13 @@
 
 
 
-static char *  
-foveon_gets(int    const offset, 
-            char * const str, 
+static char *
+foveon_gets(int    const offset,
+            char * const str,
             int    const len) {
 
     unsigned int i;
-    fseek (ifp, offset, SEEK_SET);
+    fseek_nofail (ifp, offset, SEEK_SET);
     for (i=0; i < len-1; ++i) {
         /* It certains seems wrong that we're reading a 16 bit integer
            and assigning it to char, but that's what Dcraw does.
@@ -55,7 +55,7 @@ foveon_gets(int    const offset,
 
 
 
-void 
+void
 parse_foveon(FILE * const ifp) {
     long fliplong;
     long pos;
@@ -63,14 +63,14 @@ parse_foveon(FILE * const ifp) {
     long junk;
     long entries;
 
-    fseek (ifp, 36, SEEK_SET);
+    fseek_nofail (ifp, 36, SEEK_SET);
     pm_readlittlelong(ifp, &fliplong);
     flip = fliplong;
-    fseek (ifp, -4, SEEK_END);
+    fseek_nofail (ifp, -4, SEEK_END);
     pm_readlittlelong(ifp, &pos);
-    fseek (ifp, pos, SEEK_SET);
+    fseek_nofail (ifp, pos, SEEK_SET);
     pm_readlittlelong(ifp, &magic);
-    if (magic != 0x64434553) 
+    if (magic != 0x64434553)
         return; /* SECd */
     pm_readlittlelong(ifp, &junk);
     pm_readlittlelong(ifp, &entries);
@@ -85,17 +85,17 @@ parse_foveon(FILE * const ifp) {
         pm_readlittlelong(ifp, &off);
         pm_readlittlelong(ifp, &len);
         pm_readlittlelong(ifp, &tag);
-            
-        save = ftell(ifp);
-        fseek (ifp, off, SEEK_SET);
+
+        save = ftell_nofail(ifp);
+        fseek_nofail (ifp, off, SEEK_SET);
         pm_readlittlelong(ifp, &sec_);
         if (sec_ != (0x20434553 | (tag << 24))) return;
         switch (tag) {
         case 0x47414d49:          /* IMAG */
-            if (data_offset) 
+            if (data_offset)
                 break;
             data_offset = off + 28;
-            fseek (ifp, 12, SEEK_CUR);
+            fseek_nofail (ifp, 12, SEEK_CUR);
             {
                 long wlong, hlong;
                 pm_readlittlelong(ifp, &wlong);
@@ -113,7 +113,7 @@ parse_foveon(FILE * const ifp) {
         case 0x504f5250:          /* PROP */
             pm_readlittlelong(ifp, &junk);
             pm_readlittlelong(ifp, &pent);
-            fseek (ifp, 12, SEEK_CUR);
+            fseek_nofail (ifp, 12, SEEK_CUR);
             off += pent*8 + 24;
             if (pent > 256) pent=256;
             for (i=0; i < pent*2; i++) {
@@ -133,14 +133,14 @@ parse_foveon(FILE * const ifp) {
                     timestamp = atoi (foveon_gets (poff[i][1], name, 64));
             }
         }
-        fseek (ifp, save, SEEK_SET);
+        fseek_nofail (ifp, save, SEEK_SET);
     }
     is_foveon = 1;
 }
 
 
 
-void  
+void
 foveon_coeff(int * const useCoeffP,
              float       coeff[3][4]) {
 
@@ -159,8 +159,8 @@ foveon_coeff(int * const useCoeffP,
 
 
 
-static void  
-foveon_decoder (unsigned int const huff[1024], 
+static void
+foveon_decoder (unsigned int const huff[1024],
                 unsigned int const code) {
 
     struct decode *cur;
@@ -180,7 +180,7 @@ foveon_decoder (unsigned int const huff[1024],
             }
         }
     }
-    if ((len = code >> 27) > 26) 
+    if ((len = code >> 27) > 26)
         return;
     code2 = (len+1) << 27 | (code & 0x3ffffff) << 1;
 
@@ -192,14 +192,14 @@ foveon_decoder (unsigned int const huff[1024],
 
 
 
-static void  
+static void
 foveon_load_camf() {
     unsigned int i, val;
     long key;
 
-    fseek (ifp, meta_offset, SEEK_SET);
+    fseek_nofail (ifp, meta_offset, SEEK_SET);
     pm_readlittlelong(ifp, &key);
-    fread (meta_data, 1, meta_length, ifp);
+    fread_nofail (meta_data, 1, meta_length, ifp);
     for (i=0; i < meta_length; i++) {
         key = (key * 1597 + 51749) % 244944;
         assert(have64BitArithmetic);
@@ -210,7 +210,7 @@ foveon_load_camf() {
 
 
 
-void  
+void
 foveon_load_raw(Image const image) {
 
     struct decode *dindex;
@@ -234,14 +234,14 @@ foveon_load_raw(Image const image) {
     for (row=0; row < height; row++) {
         long junk;
         memset (pred, 0, sizeof pred);
-        if (!bit) 
+        if (!bit)
             pm_readlittlelong(ifp, &junk);
         for (col=bit=0; col < width; col++) {
             FORC3 {
                 for (dindex=first_decode; dindex->branch[0]; ) {
                     if ((bit = (bit-1) & 31) == 31)
                         for (i=0; i < 4; i++)
-                            bitbuf = (bitbuf << 8) + fgetc(ifp);
+                            bitbuf = (bitbuf << 8) + fgetc_nofail(ifp);
                     dindex = dindex->branch[bitbuf >> bit & 1];
                 }
                 pred[c] += diff[dindex->leaf];
@@ -262,8 +262,8 @@ sget4(char const s[]) {
 
 
 
-static char *  
-foveon_camf_param (const char * const block, 
+static char *
+foveon_camf_param (const char * const block,
                    const char * const param) {
     unsigned idx, num;
     char *pos, *cp, *dp;
@@ -287,8 +287,8 @@ foveon_camf_param (const char * const block,
 
 
 
-static void *  
-foveon_camf_matrix (int                dim[3], 
+static void *
+foveon_camf_matrix (int                dim[3],
                     const char * const name) {
 
     unsigned i, idx, type, ndim, size, *mat;
@@ -325,9 +325,9 @@ foveon_camf_matrix (int                dim[3],
 
 
 
-static int  
-foveon_fixed (void *       const ptr, 
-              int          const size, 
+static int
+foveon_fixed (void *       const ptr,
+              int          const size,
               const char * const name) {
     void *dp;
     int dim[3];
@@ -345,7 +345,7 @@ static float  foveon_avg (unsigned short *pix, int range[2], float cfilt)
     float val, min=FLT_MAX, max=-FLT_MAX, sum=0;
 
     for (i=range[0]; i <= range[1]; i++) {
-        sum += val = 
+        sum += val =
             (short)pix[i*4] + ((short)pix[i*4]-(short)pix[(i-1)*4]) * cfilt;
         if (min > val) min = val;
         if (max < val) max = val;
@@ -390,11 +390,11 @@ static int  foveon_apply_curve (short *curve, int i)
     return i < 0 ? -(unsigned short)curve[1-i] : (unsigned short)curve[1+i];
 }
 
-void  
+void
 foveon_interpolate(Image const image,
                    float coeff[3][4]) {
 
-    static const short hood[] = { 
+    static const short hood[] = {
         -1,-1, -1,0, -1,1, 0,-1, 0,1, 1,-1, 1,0, 1,1 };
     short *pix, prev[3], *curve[8], (*shrink)[3];
     float cfilt=0.8, ddft[3][3][2], ppm[3][3][3];
@@ -441,7 +441,7 @@ foveon_interpolate(Image const image,
         for (i=0; i < 3; i++)
             FORC3 diag[c][i] = LAST(1,1)*LAST(2,2) - LAST(1,2)*LAST(2,1);
 #undef LAST
-        FORC3 div[c] = 
+        FORC3 div[c] =
             diag[c][0]*0.3127 + diag[c][1]*0.329 + diag[c][2]*0.3583;
     }
     num = 0;
@@ -494,11 +494,11 @@ foveon_interpolate(Image const image,
     for (row=1; row < height-1; row++) {
         FORC3 if (last[1][c] > last[0][c]) {
             if (last[1][c] > last[2][c])
-                black[row][c] = 
+                black[row][c] =
                     (last[0][c] > last[2][c]) ? last[0][c]:last[2][c];
         } else
             if (last[1][c] < last[2][c])
-                black[row][c] = 
+                black[row][c] =
                     (last[0][c] < last[2][c]) ? last[0][c]:last[2][c];
         memmove (last, last+1, 2*sizeof last[0]);
         memcpy (last[2], black[row+1], sizeof last[2]);
@@ -547,8 +547,8 @@ foveon_interpolate(Image const image,
                 diff = pix[c] - prev[c];
                 prev[c] = pix[c];
                 ipix[c] = pix[c] + floor ((diff + (diff*diff >> 14)) * cfilt
-                                          - ddft[0][c][1] 
-                                          - ddft[0][c][0] 
+                                          - ddft[0][c][1]
+                                          - ddft[0][c][0]
                                             * ((float) col/width - 0.5)
                                           - black[row][c] );
             }
@@ -563,7 +563,7 @@ foveon_interpolate(Image const image,
                         val += ppm[c][i][j] * work[i][j];
                 ipix[c] = floor ((ipix[c] + floor(val)) *
                                  ( sgrow[col/sgx  ][c] * (sgx - col%sgx) +
-                                   sgrow[col/sgx+1][c] * (col%sgx) ) / sgx / 
+                                   sgrow[col/sgx+1][c] * (col%sgx) ) / sgx /
                                  div[c]);
                 if (ipix[c] > 32000) ipix[c] = 32000;
                 pix[c] = ipix[c];
@@ -584,7 +584,7 @@ foveon_interpolate(Image const image,
             memset (fsum, 0, sizeof fsum);
             for (sum=j=0; j < 8; j++)
                 if (badpix[i] & (1 << j)) {
-                    FORC3 fsum[c] += 
+                    FORC3 fsum[c] +=
                         image[(row+hood[j*2])*width+col+hood[j*2+1]][c];
                     sum++;
                 }
@@ -665,8 +665,8 @@ foveon_interpolate(Image const image,
         pix = (short*)image[row*width+2];
         for (col=2; col < width-2; col++) {
             FORC3 dev[c] = -foveon_apply_curve (curve[7], pix[c] -
-                                                ((smrow[1][col][c] + 
-                                                  2*smrow[2][col][c] + 
+                                                ((smrow[1][col][c] +
+                                                  2*smrow[2][col][c] +
                                                   smrow[3][col][c]) >> 2));
             sum = (dev[0] + dev[1] + dev[2]) >> 3;
             FORC3 pix[c] += dev[c] - sum;
@@ -695,7 +695,7 @@ foveon_interpolate(Image const image,
             if (sum < 0) sum = 0;
             j = total[3] > 375 ? (sum << 16) / total[3] : sum * 174;
             FORC3 pix[c] += foveon_apply_curve (curve[6],
-                                                ((j*total[c] + 0x8000) >> 16) 
+                                                ((j*total[c] + 0x8000) >> 16)
                                                 - pix[c]);
             pix += 4;
         }
@@ -732,7 +732,7 @@ foveon_interpolate(Image const image,
                     shrink[row*(width/4)+col][c] = ipix[c] >> 4;
                 else
                     shrink[row*(width/4)+col][c] =
-                        (shrink[(row+1)*(width/4)+col][c]*1840 + 
+                        (shrink[(row+1)*(width/4)+col][c]*1840 +
                          ipix[c]*141 + 2048) >> 12;
         }
     }
@@ -742,7 +742,7 @@ foveon_interpolate(Image const image,
         if ((row & 3) == 0)
             for (col = width & ~3 ; col--; )
                 FORC3 smrow[0][col][c] = ipix[c] =
-                    (shrink[(row/4)*(width/4)+col/4][c]*1485 + 
+                    (shrink[(row/4)*(width/4)+col/4][c]*1485 +
                      ipix[c]*6707 + 4096) >> 13;
 
         /* Then smooth left-to-right */
@@ -757,7 +757,7 @@ foveon_interpolate(Image const image,
         else
             for (col=0; col < (width & ~3); col++)
                 FORC3 smrow[2][col][c] =
-                    (smrow[2][col][c]*6707 + smrow[1][col][c]*1485 + 4096) 
+                    (smrow[2][col][c]*6707 + smrow[1][col][c]*1485 + 4096)
                         >> 13;
 
         /* Adjust the chroma toward the smooth values */
@@ -770,7 +770,7 @@ foveon_interpolate(Image const image,
             for (sum=c=0; c < 3; c++) {
                 ipix[c] = foveon_apply_curve(
                     curve[c+3],
-                    ((smrow[2][col][c] * j + 0x8000) >> 16) - 
+                    ((smrow[2][col][c] * j + 0x8000) >> 16) -
                     image[row*width+col][c]);
                 sum += ipix[c];
             }
diff --git a/converter/other/cameratopam/identify.c b/converter/other/cameratopam/identify.c
index 26fa329e..e5df6b22 100644
--- a/converter/other/cameratopam/identify.c
+++ b/converter/other/cameratopam/identify.c
@@ -13,6 +13,7 @@
 #include "dng.h"
 #include "ljpeg.h"
 #include "camera.h"
+#include "stdio_nofail.h"
 
 #include "identify.h"
 
@@ -38,7 +39,7 @@ static const char *memmem_internal (const char *haystack, size_t haystacklen,
 
 
 
-static void 
+static void
 adobeCoeff(const char * const make,
            const char * const model) {
     /*
@@ -47,7 +48,7 @@ adobeCoeff(const char * const make,
     struct CoeffTableEntry {
         const char * prefix;
         short trans[12];
-    }; 
+    };
 
     static struct CoeffTableEntry const table[] = {
         { "Canon EOS D2000C",
@@ -331,17 +332,17 @@ identify(FILE *       const ifp,
 
     order = get2(ifp);
     hlen = get4(ifp);
-    fseek (ifp, 0, SEEK_SET);
-    fread (head, 1, 32, ifp);
-    fseek (ifp, 0, SEEK_END);
-    fsize = ftell(ifp);
+    fseek_nofail (ifp, 0, SEEK_SET);
+    fread_nofail (head, 1, 32, ifp);
+    fseek_nofail (ifp, 0, SEEK_END);
+    fsize = ftell_nofail(ifp);
     if ((c = (char*)memmem_internal(head, 32, "MMMMRawT", 8))) {
         strcpy (make, "Phase One");
         data_offset = c - head;
-        fseek (ifp, data_offset + 8, SEEK_SET);
-        fseek (ifp, get4(ifp) + 136, SEEK_CUR);
+        fseek_nofail (ifp, data_offset + 8, SEEK_SET);
+        fseek_nofail (ifp, get4(ifp) + 136, SEEK_CUR);
         raw_width = get4(ifp);
-        fseek (ifp, 12, SEEK_CUR);
+        fseek_nofail (ifp, 12, SEEK_CUR);
         raw_height = get4(ifp);
     } else if (order == 0x4949 || order == 0x4d4d) {
         if (!memcmp (head+6, "HEAPCCDR", 8)) {
@@ -356,14 +357,14 @@ identify(FILE *       const ifp,
         parse_minolta(ifp);
     else if (!memcmp (head, "\xff\xd8\xff\xe1", 4) &&
              !memcmp (head+6, "Exif", 4)) {
-        fseek (ifp, 4, SEEK_SET);
-        fseek (ifp, 4 + get2(ifp), SEEK_SET);
-        if (fgetc(ifp) != 0xff)
+        fseek_nofail (ifp, 4, SEEK_SET);
+        fseek_nofail (ifp, 4 + get2(ifp), SEEK_SET);
+        if (fgetc_nofail(ifp) != 0xff)
             parse_tiff(ifp, 12);
     } else if (!memcmp (head, "BM", 2)) {
         data_offset = 0x1000;
         order = 0x4949;
-        fseek (ifp, 38, SEEK_SET);
+        fseek_nofail (ifp, 38, SEEK_SET);
         if (get4(ifp) == 2834 && get4(ifp) == 2834) {
             strcpy (model, "BMQ");
             flip = 3;
@@ -374,7 +375,7 @@ identify(FILE *       const ifp,
     nucore:
         strcpy (make, "Nucore");
         order = 0x4949;
-        fseek (ifp, 10, SEEK_SET);
+        fseek_nofail (ifp, 10, SEEK_SET);
         data_offset += get4(ifp);
         get4(ifp);
         raw_width  = get4(ifp);
@@ -386,16 +387,16 @@ identify(FILE *       const ifp,
     } else if (!memcmp (head+25, "ARECOYK", 7)) {
         strcpy (make, "Contax");
         strcpy (model,"N Digital");
-        fseek (ifp, 60, SEEK_SET);
+        fseek_nofail (ifp, 60, SEEK_SET);
         camera_red  = get4(ifp);
         camera_red /= get4(ifp);
         camera_blue = get4(ifp);
         camera_blue = get4(ifp) / camera_blue;
     } else if (!memcmp (head, "FUJIFILM", 8)) {
         long data_offset_long;
-        fseek (ifp, 84, SEEK_SET);
+        fseek_nofail (ifp, 84, SEEK_SET);
         parse_tiff(ifp, get4(ifp)+12);
-        fseek (ifp, 100, SEEK_SET);
+        fseek_nofail (ifp, 100, SEEK_SET);
         pm_readbiglong(ifp, &data_offset_long);
         data_offset = data_offset_long;
     } else if (!memcmp (head, "DSC-Image", 9))
@@ -737,13 +738,13 @@ identify(FILE *       const ifp,
         width  = 2312;
         raw_width = 2336;
         data_offset = 4034;
-        fseek (ifp, 2032, SEEK_SET);
+        fseek_nofail (ifp, 2032, SEEK_SET);
         goto konica_400z;
     } else if (!strcmp(model,"Digital Camera KD-510Z")) {
         data_offset = 4032;
         pre_mul[0] = 1.297;
         pre_mul[2] = 1.438;
-        fseek (ifp, 2032, SEEK_SET);
+        fseek_nofail (ifp, 2032, SEEK_SET);
         goto konica_510z;
     } else if (!strcasecmp(make,"MINOLTA")) {
         load_raw = unpacked_load_raw;
@@ -767,19 +768,19 @@ identify(FILE *       const ifp,
                 data_offset = 5056;
                 pre_mul[0] = 1.602;
                 pre_mul[2] = 1.441;
-                fseek (ifp, 2078, SEEK_SET);
+                fseek_nofail (ifp, 2078, SEEK_SET);
                 height = 1716;
                 width  = 2304;
             } else if (model[8] == '5') {
                 data_offset = 4016;
-                fseek (ifp, 1936, SEEK_SET);
+                fseek_nofail (ifp, 1936, SEEK_SET);
             konica_510z:
                 height = 1956;
                 width  = 2607;
                 raw_width = 2624;
             } else if (model[8] == '6') {
                 data_offset = 4032;
-                fseek (ifp, 2030, SEEK_SET);
+                fseek_nofail (ifp, 2030, SEEK_SET);
                 height = 2136;
                 width  = 2848;
             }
@@ -885,7 +886,7 @@ identify(FILE *       const ifp,
         pre_mul[0] = 1.963;
         pre_mul[2] = 1.430;
     } else if (!strcmp(make,"Sinar") && !memcmp(head,"8BPS",4)) {
-        fseek (ifp, 14, SEEK_SET);
+        fseek_nofail (ifp, 14, SEEK_SET);
         height = get4(ifp);
         width  = get4(ifp);
         filters = 0x61616161;
@@ -1199,7 +1200,7 @@ dng_skip:
             for (i=0; i < 3; i++)
                 coeff[i][3] = coeff[i][1] /= 2;
     }
-    fseek (ifp, data_offset, SEEK_SET);
+    fseek_nofail (ifp, data_offset, SEEK_SET);
 
     *loadRawFnP = load_raw;
 
diff --git a/converter/other/cameratopam/ljpeg.c b/converter/other/cameratopam/ljpeg.c
index 331d258c..35f50f4b 100644
--- a/converter/other/cameratopam/ljpeg.c
+++ b/converter/other/cameratopam/ljpeg.c
@@ -2,7 +2,6 @@
 #define _BSD_SOURCE    /* Make sure string.h containst strcasecmp() */
 #include <stdlib.h>
 #include <string.h>
-#include <stdio.h>
 #include <limits.h>
 
 #include "pm.h"
@@ -11,6 +10,7 @@
 #include "util.h"
 #include "decode.h"
 #include "bayer.h"
+#include "stdio_nofail.h"
 
 #include "ljpeg.h"
 
@@ -20,7 +20,7 @@
    enough to decode Canon, Kodak and Adobe DNG images.
  */
 
-int  
+int
 ljpeg_start(FILE *         const ifP,
             struct jhead * const jhP) {
 
@@ -30,12 +30,12 @@ ljpeg_start(FILE *         const ifP,
     init_decoder();
     for (i=0; i < 4; i++)
         jhP->huff[i] = free_decode;
-    fread (data, 2, 1, ifP);
+    fread_nofail (data, 2, 1, ifP);
     if (data[0] != 0xff || data[1] != 0xd8) return 0;
     do {
         unsigned int len;
 
-        fread (data, 2, 2, ifP);
+        fread_nofail (data, 2, 2, ifP);
         tag =  data[0] << 8 | data[1];
         len = data[2] << 8 | data[3];
 
@@ -45,7 +45,7 @@ ljpeg_start(FILE *         const ifP,
             unsigned int const dataLen = len - 2;
 
             if (tag <= 0xff00 || dataLen > 255) return 0;
-            fread (data, 1, dataLen, ifP);
+            fread_nofail (data, 1, dataLen, ifP);
             switch (tag) {
             case 0xffc3:
                 jhP->bits = data[0];
@@ -73,7 +73,7 @@ ljpeg_start(FILE *         const ifP,
 
 
 
-int 
+int
 ljpeg_diff(FILE *          const ifP,
            struct decode * const dindexHeadP) {
 
@@ -111,7 +111,7 @@ ljpeg_row(FILE *         const ifP,
 
 
 
-void  
+void
 lossless_jpeg_load_raw(Image  const image) {
 
     int jwide, jrow, jcol, val, jidx, i, row, col;
@@ -161,5 +161,3 @@ lossless_jpeg_load_raw(Image  const image) {
     if (!strcasecmp(make,"KODAK"))
         black = min;
 }
-
-
diff --git a/converter/other/cameratopam/stdio_nofail.c b/converter/other/cameratopam/stdio_nofail.c
new file mode 100644
index 00000000..97a8796d
--- /dev/null
+++ b/converter/other/cameratopam/stdio_nofail.c
@@ -0,0 +1,120 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <netpbm/pm.h>
+
+#include "stdio_nofail.h"
+
+
+
+size_t
+fread_or_eof_nofail(void * const ptr,
+                    size_t const size,
+                    size_t const nmemb,
+                    FILE * const streamP) {
+
+    size_t rc;
+
+    rc = fread(ptr, size, nmemb, streamP);
+
+    if (rc < nmemb) {
+        if (!feof(streamP))
+            pm_error("File read failed.  Errno=%d (%s)",
+                     errno, strerror(errno));
+    }
+    return rc;
+}
+
+
+
+void
+fread_nofail(void * const ptr,
+             size_t const size,
+             size_t const nmemb,
+             FILE * const streamP) {
+
+    size_t rc;
+
+    rc = fread(ptr, size, nmemb, streamP);
+
+    if (rc < nmemb) {
+        if (feof(streamP))
+            pm_error("File read failed.  Premature end of file");
+        else
+            pm_error("File read failed.  Errno=%d (%s)",
+                     errno, strerror(errno));
+    }
+}
+
+
+
+int
+fgetc_nofail(FILE * streamP) {
+
+    int rc;
+
+    rc = fgetc(streamP);
+
+    if (rc == EOF) {
+        if (feof(streamP))
+            pm_error("File read failed.  Premature end of file");
+        else
+            pm_error("File read failed.  Errno=%d (%s)",
+                     errno, strerror(errno));
+    }
+    return rc;
+}
+
+
+
+int
+fseek_nofail(FILE * const streamP,
+             long   const offset,
+             int    const whence) {
+
+    int rc;
+
+    rc = fseek(streamP, offset, whence);
+
+    if (rc < 0)
+        pm_error("File seek failed.  Errno=%d (%s)", errno, strerror(errno));
+
+    return rc;
+}
+
+
+
+long
+ftell_nofail(FILE * const streamP) {
+
+    long rc;
+
+    rc = ftell(streamP);
+
+    if (rc < 0)
+        pm_error("File position query failed.  Errno=%d (%s)",
+                 errno, strerror(errno));
+
+    return rc;
+}
+
+
+
+char *
+fgets_nofail(char * const s,
+             int    const size,
+             FILE * const streamP) {
+
+    char * rc;
+
+    rc = fgets(s, size, streamP);
+
+    if (ferror(streamP))
+        pm_error("File read failed.  Errno=%d (%s)", errno, strerror(errno));
+
+    return rc;
+}
+
+
+
diff --git a/converter/other/cameratopam/stdio_nofail.h b/converter/other/cameratopam/stdio_nofail.h
new file mode 100644
index 00000000..8f45b537
--- /dev/null
+++ b/converter/other/cameratopam/stdio_nofail.h
@@ -0,0 +1,29 @@
+#include <stdio.h>
+
+size_t
+fread_or_eof_nofail(void * const ptr,
+                    size_t const size,
+                    size_t const nmemb,
+                    FILE * const streamP);
+
+void
+fread_nofail(void * const ptr,
+             size_t const size,
+             size_t const nmemb,
+             FILE * const streamP);
+
+int
+fgetc_nofail(FILE * const streamP);
+
+int
+fseek_nofail(FILE * const streamP,
+             long   const offset,
+             int    const whence);
+
+long
+ftell_nofail(FILE * const streamP);
+
+char *
+fgets_nofail(char * const s,
+             int    const size,
+             FILE * const streamP);
diff --git a/converter/other/cameratopam/util.c b/converter/other/cameratopam/util.c
index b3ccf7e9..ede5ef69 100644
--- a/converter/other/cameratopam/util.c
+++ b/converter/other/cameratopam/util.c
@@ -1,10 +1,12 @@
 #define _XOPEN_SOURCE   /* Make sure unistd.h contains swab() */
 #include <unistd.h>
-#include <stdio.h>
 
-#include "pm.h"
+#include "netpbm/pm.h"
+#include "netpbm/mallocvar.h"
+
 #include "global_variables.h"
 #include "util.h"
+#include "stdio_nofail.h"
 
 #ifndef LONG_BITS
 #define LONG_BITS (8 * sizeof(long))
@@ -18,7 +20,7 @@ get2(FILE * const ifp)
 {
     unsigned char a, b;
 
-    a = fgetc(ifp);  b = fgetc(ifp);
+    a = fgetc_nofail(ifp);  b = fgetc_nofail(ifp);
 
     if (order == 0x4949)      /* "II" means little-endian */
         return a | b << 8;
@@ -34,8 +36,8 @@ get4(FILE * const ifp)
 {
     unsigned char a, b, c, d;
 
-    a = fgetc(ifp);  b = fgetc(ifp);
-    c = fgetc(ifp);  d = fgetc(ifp);
+    a = fgetc_nofail(ifp);  b = fgetc_nofail(ifp);
+    c = fgetc_nofail(ifp);  d = fgetc_nofail(ifp);
 
     if (order == 0x4949)
         return a | b << 8 | c << 16 | d << 24;
@@ -49,9 +51,21 @@ get4(FILE * const ifp)
 void
 read_shorts (FILE * const ifp, unsigned short *pixel, int count)
 {
-    fread (pixel, 2, count, ifp);
-    if ((order == 0x4949) == (BYTE_ORDER == BIG_ENDIAN))
-        swab (pixel, pixel, count*2);
+    unsigned short * buffer;
+
+    MALLOCARRAY(buffer, count);
+
+    if (!buffer)
+        pm_error("Failed to allocate a buffer for reading %u short "
+                 "integers from file", count);
+    else {
+        fread_nofail(buffer, 2, count, ifp);
+
+        if ((order == 0x4949) == (BYTE_ORDER == BIG_ENDIAN))
+            swab(buffer, pixel, count*2);
+
+        free(buffer);
+    }
 }
 
 /*
@@ -73,10 +87,10 @@ getbits (FILE * const ifp, int nbits)
         vbits -= nbits;
     }
     while (vbits < LONG_BITS - 7) {
-        c = fgetc(ifp);
+        c = fgetc_nofail(ifp);
         bitbuf = (bitbuf << 8) + c;
         if (c == 0xff && zero_after_ff)
-            fgetc(ifp);
+            fgetc_nofail(ifp);
         vbits += 8;
     }
     return ret;
diff --git a/converter/other/fiasco/codec/coder.c b/converter/other/fiasco/codec/coder.c
index 1e21994d..dc774a19 100644
--- a/converter/other/fiasco/codec/coder.c
+++ b/converter/other/fiasco/codec/coder.c
@@ -2,7 +2,7 @@
  *  coder.c:        WFA coder toplevel functions
  *
  *  Written by:     Ullrich Hafner
- *      
+ *
  *  This file is part of FIASCO (Fractal Image And Sequence COdec)
  *  Copyright (C) 1994-2000 Ullrich Hafner
  */
@@ -56,7 +56,7 @@
 /*****************************************************************************
 
                 global variables
-  
+
 *****************************************************************************/
 
 const real_t MAXCOSTS = 1e20;
@@ -64,7 +64,7 @@ const real_t MAXCOSTS = 1e20;
 /*****************************************************************************
 
                 private code
-  
+
 *****************************************************************************/
 
 static char *
@@ -109,44 +109,44 @@ get_input_image_name (char const * const *templptr, unsigned ith_image)
 
             strcpy (prefix, template);
             prefix [s - template] = '\0';
-   
+
             for (s2 = ++s, n_digits = 0; ISDIGIT (*s2); s2++, n_digits++)
                 ;
             if (sscanf (s, "%d", &dummy) == 0 || dummy < 0)
                 error ("Input name template conversion failure.\n"
                        "Check spelling of template.");
             first = (unsigned) dummy;
-     
+
             if (*s2++ != '-')
                 error ("Input name template conversion failure.\n"
                        "Check spelling of template.");
-   
+
             for (s = s2; ISDIGIT (*s2); s2++)
                 ;
             if (sscanf (s, "%d", &dummy) == 0 || dummy < 0)
                 error ("Input name template conversion failure.\n"
                        "Check spelling of template.");
             last = (unsigned) dummy;
-     
-            if (*s2 == '+' || *s2 == '-') 
+
+            if (*s2 == '+' || *s2 == '-')
             {
                 for (s = s2++; ISDIGIT (*s2); s2++)
                     ;
                 if (sscanf (s, "%d", &increment) == 0)
                     error ("Input name template conversion failure.\n"
                            "Check spelling of template.");
-            }   
+            }
             if (*s2 != ']')
                 error ("Input name template conversion failure.\n"
                        "Check spelling of template.");
             suffix = s2 + 1;
-   
+
             image_num = first + increment * ith_image;
             if (image_num < 0)
                 error ("Input name template conversion failure.\n"
                        "Check spelling of template.");
-     
-            if ((increment >  0 && (unsigned) image_num > last) || 
+
+            if ((increment >  0 && (unsigned) image_num > last) ||
                 (increment <= 0 && (unsigned) image_num < last))
             {
                 /* TODO: check this */
@@ -158,7 +158,7 @@ get_input_image_name (char const * const *templptr, unsigned ith_image)
                     /* format string for image filename */
                 char image_name [MAXSTRLEN];
                     /* image file name to be composed */
-        
+
                 strcpy (formatstr, "%s%0?d%s");
                 formatstr [4] = '0' + (char) n_digits;
                 sprintf (image_name, formatstr, prefix, image_num, suffix);
@@ -167,7 +167,7 @@ get_input_image_name (char const * const *templptr, unsigned ith_image)
         }
     }
     return NULL;
-}   
+}
 
 
 
@@ -191,7 +191,7 @@ alloc_coder (char const * const * const inputname,
     coding_t * c;
 
     c = NULL;  /* initial value */
-   
+
    /*
     *  Check whether all specified image frames are readable and of same type
     */
@@ -200,7 +200,7 @@ alloc_coder (char const * const * const inputname,
         int     width, w = 0, height, h = 0;
         bool_t  color, c = NO;
         unsigned    n;
-      
+
         for (n = 0; (filename = get_input_image_name (inputname, n)); n++)
         {
             xelval maxval;
@@ -220,7 +220,7 @@ alloc_coder (char const * const * const inputname,
                 pm_close(file);
             }
             color = (PNM_FORMAT_TYPE(format) == PPM_FORMAT) ? TRUE: FALSE;
-                
+
             if (n > 0)
             {
                 if (w != width || h != height || c != color)
@@ -249,13 +249,13 @@ alloc_coder (char const * const * const inputname,
     */
     {
         unsigned lx, ly;
-      
+
         lx = (unsigned) (log2 (wi->width - 1) + 1);
         ly = (unsigned) (log2 (wi->height - 1) + 1);
-      
+
         wi->level = MAX(lx, ly) * 2 - ((ly == lx + 1) ? 1 : 0);
     }
-   
+
     c = Calloc (1, sizeof (coding_t));
 
     c->options             = *options;
@@ -278,10 +278,10 @@ alloc_coder (char const * const * const inputname,
                  c->options.lc_max_level, wi->level - c->tiling->exponent - 1);
         c->options.lc_max_level = wi->level - c->tiling->exponent - 1;
     }
-   
+
     if (c->options.lc_min_level > c->options.lc_max_level)
         c->options.lc_min_level = c->options.lc_max_level;
-   
+
     /*
      *  p_min_level, p_max_level min and max level for ND/MC prediction
      *  [p_min_level, p_max_level] must be a subset of [min_level, max_level] !
@@ -293,7 +293,7 @@ alloc_coder (char const * const * const inputname,
 
     c->options.images_level = MIN(c->options.images_level,
                                   c->options.lc_max_level - 1);
-   
+
     c->products_level  = MAX(0, ((signed int) c->options.lc_max_level
                                  - (signed int) c->options.images_level - 1));
     c->pixels         = Calloc (size_of_level (c->options.lc_max_level),
@@ -301,7 +301,7 @@ alloc_coder (char const * const * const inputname,
     c->images_of_state = Calloc (MAXSTATES, sizeof (real_t *));
     c->ip_images_state = Calloc (MAXSTATES, sizeof (real_t *));
     c->ip_states_state = Calloc (MAXSTATES * MAXLEVEL, sizeof (real_t *));
-   
+
     debug_message ("Imageslevel :%d, Productslevel :%d",
                    c->options.images_level, c->products_level);
     debug_message ("Memory : (%d + %d + %d * 'states') * 'states' + %d",
@@ -309,7 +309,7 @@ alloc_coder (char const * const * const inputname,
                    size_of_tree (c->products_level) * 4,
                    (c->options.lc_max_level - c->options.images_level),
                    size_of_level (c->options.lc_max_level));
-   
+
     /*
     *  Domain pools ...
     */
@@ -333,7 +333,7 @@ alloc_coder (char const * const * const inputname,
      */
     wi->title   = strdup (options->title);
     wi->comment = strdup (options->comment);
-   
+
     /*
      *  Reduced precision format
      */
@@ -345,7 +345,7 @@ alloc_coder (char const * const * const inputname,
         = alloc_rpf (options->d_rpf_mantissa, options->d_rpf_range);
     wi->d_dc_rpf
         = alloc_rpf (options->d_dc_rpf_mantissa, options->d_dc_rpf_range);
-   
+
     /*
      *  Color image options ...
      */
@@ -361,7 +361,7 @@ alloc_coder (char const * const * const inputname,
     wi->cross_B_search = options->half_pixel_prediction;
     wi->B_as_past_ref  = options->B_as_past_ref;
     wi->smoothing      = options->smoothing;
-   
+
     c->mt = alloc_motion (wi);
 
     return c;
@@ -383,7 +383,7 @@ free_coder (coding_t *c)
 {
    free_tiling (c->tiling);
    free_motion (c->mt);
-   
+
    Free (c->pixels);
    Free (c->images_of_state);
    Free (c->ip_images_state);
@@ -424,13 +424,13 @@ print_statistics (char c, real_t costs, const wfa_t *wfa, const image_t *image,
           const range_t *range)
 {
    unsigned max_level, min_level, state, label, lincomb;
-   
+
    for (max_level = 0, min_level = MAXLEVEL, state = wfa->basis_states;
     state < wfa->states; state++)
    {
       for (lincomb = 0, label = 0; label < MAXLABELS; label++)
      lincomb += isrange(wfa->tree[state][label]) ? 1 : 0;
-     
+
       if (lincomb)
       {
      max_level = MAX(max_level,
@@ -483,10 +483,10 @@ print_statistics (char c, real_t costs, const wfa_t *wfa, const image_t *image,
 
 
 
-static void 
+static void
 frame_coder (wfa_t *wfa, coding_t *c, bitfile_t *output)
 /*
- * 
+ *
  *  WFA Coding of next frame.  All important coding parameters are
  *  stored in 'c'.  The generated 'wfa' is written to stream 'output'
  *  immediately after coding.
@@ -499,11 +499,11 @@ frame_coder (wfa_t *wfa, coding_t *c, bitfile_t *output)
    real_t   costs;          /* total costs (minimized quantity) */
    unsigned bits;           /* number of bits written on disk */
    clock_t  ptimer;
-   
+
    prg_timer (&ptimer, START);
 
    bits = bits_processed (output);
-   
+
    init_tree_model (&c->tree);
    init_tree_model (&c->p_tree);
 
@@ -552,9 +552,9 @@ frame_coder (wfa_t *wfa, coding_t *c, bitfile_t *output)
        int     YCb_node = -1;
        int     tree [3];         /* 3 root states of each color comp. */
        color_e band;
-      
+
        /*
-        *  When compressing color images, the three color components (YCbCr) 
+        *  When compressing color images, the three color components (YCbCr)
         *  are copied into a large image:
         *  [  Y  Cr ]
         *  [  Cb 0  ]
@@ -573,14 +573,14 @@ frame_coder (wfa_t *wfa, coding_t *c, bitfile_t *output)
                c->domain_pool->chroma (wfa->wfainfo->chroma_max_states, wfa,
                                        c->domain_pool->model);
                /*
-                *  Don't use a finer partioning for the chrominancy bands than
-                *  for the luminancy band.
+                *  Don't use a finer partitioning for the chrominancy bands
+                *  than for the luminancy band.
                 */
                for (min_level = MAXLEVEL, state = wfa->basis_states;
                     state < wfa->states; state++)
                {
                    unsigned lincomb, label;
-           
+
                    for (lincomb = 0, label = 0; label < MAXLABELS; label++)
                        lincomb += isrange (wfa->tree [state][label]) ? 1 : 0;
                    if (lincomb)
@@ -596,23 +596,23 @@ frame_coder (wfa_t *wfa, coding_t *c, bitfile_t *output)
 
            memset (&range, 0, sizeof (range_t));
            range.level = wfa->wfainfo->level;
-     
+
            costs = subdivide (MAXCOSTS, band, tree [Y], &range, wfa, c,
                               c->mt->frame_type != I_FRAME && band == Y, NO);
            if (c->options.progress_meter != FIASCO_PROGRESS_NONE)
                message ("");
            {
                char colors [] = {'Y', 'B', 'R'};
-        
+
                print_statistics (colors [band], costs, wfa,
                                  c->mt->original, &range);
            }
-     
+
            if (isrange (range.tree))  /* whole image is approx. by a l.c. */
                error ("No root state generated for color component %d!", band);
            else
                tree[band] = range.tree;
-     
+
            if (band == Cb)
            {
                wfa->tree [wfa->states][0] = tree[Y];
@@ -623,13 +623,13 @@ frame_coder (wfa_t *wfa, coding_t *c, bitfile_t *output)
            }
       }
       /*
-       *  generate two virtual states (*) 
+       *  generate two virtual states (*)
        *
        *              *
        *            /   \
        *           +     *
-       *          / \   /  
-       *         Y   CbCr 
+       *          / \   /
+       *         Y   CbCr
        */
       wfa->tree [wfa->states][0] = tree[Cr];
       wfa->tree [wfa->states][1] = RANGE;
@@ -646,7 +646,7 @@ frame_coder (wfa_t *wfa, coding_t *c, bitfile_t *output)
    for (state = wfa->basis_states; state < MAXSTATES; state++)
    {
       unsigned level;
-      
+
       if (c->images_of_state [state])
       {
      Free (c->images_of_state [state]);
@@ -665,12 +665,12 @@ frame_coder (wfa_t *wfa, coding_t *c, bitfile_t *output)
         Free (c->ip_states_state [state][level]);
         c->ip_states_state [state][level] = NULL;
      }
-      
+
    }
-   
+
    locate_delta_images (wfa);
    write_next_wfa (wfa, c, output);
-   
+
    bits = bits_processed (output) - bits;
    debug_message ("Total number of bits written: %d (%d bytes, %5.3f bpp)",
           bits, bits >> 3,
@@ -712,7 +712,7 @@ video_coder(char const * const * const image_template,
         /* image name of current frame.  File name or "-" for Standard Input */
     image_t  *reconst      = NULL;   /* decoded reference image */
     bool_t    future_frame = NO;     /* YES if last frame was in future */
-   
+
     debug_message ("Generating %d WFA's ...", wfa->wfainfo->frames);
 
     future_display = -1;
@@ -722,7 +722,7 @@ video_coder(char const * const * const image_template,
     while ((image_name = get_input_image_name (image_template, display)))
     {
         frame_type_e type;        /* current frame type: I, B, P */
-      
+
         /*
          *  Determine type of next frame.
          *  Skip already coded frames (future reference!)
@@ -731,7 +731,7 @@ video_coder(char const * const * const image_template,
             type = I_FRAME;        /* Force first frame to be intra */
         else
             type = pattern2type (display, c->options.pattern);
-      
+
         if (type != I_FRAME && c->options.reference_filename)
             /* Load reference from disk */
         {
@@ -741,12 +741,12 @@ video_coder(char const * const * const image_template,
             c->options.reference_filename = NULL;
         }
         if ((int) display == future_display)
-        {             
+        {
             /* Skip already coded future ref */
             display++;
             continue;
-        }   
-        else if (type == B_FRAME && (int) display > future_display) 
+        }
+        else if (type == B_FRAME && (int) display > future_display)
         {
             unsigned i = display;
             /*
@@ -758,7 +758,7 @@ video_coder(char const * const * const image_template,
 
                 i++;
                 name = get_input_image_name (image_template, i);
-        
+
                 if (!name)          /* Force last valid frame to be 'P' */
                 {
                     future_display = i - 1;
@@ -766,7 +766,7 @@ video_coder(char const * const * const image_template,
                 }
                 else
                 {
-                    future_display = i;    
+                    future_display = i;
                     image_name     = name;
                     type           = pattern2type (i, c->options.pattern);
                 }
@@ -781,7 +781,7 @@ video_coder(char const * const * const image_template,
 
         debug_message ("Coding \'%s\' [%c-frame].", image_name,
                        type == I_FRAME ? 'I' : (type == P_FRAME ? 'P' : 'B'));
-       
+
         /*
          *  Depending on current frame type update past and future frames
          *  which are needed as reference frames.
@@ -846,10 +846,10 @@ video_coder(char const * const * const image_template,
             c->mt->original = read_image_stream(stdin,
                                                 stdinwidth, stdinheight,
                                                 stdinmaxval, stdinformat);
-        else 
+        else
             c->mt->original = read_image_file(image_name);
 
-        if (c->tiling->exponent && type == I_FRAME) 
+        if (c->tiling->exponent && type == I_FRAME)
             perform_tiling (c->mt->original, c->tiling);
 
         frame_coder (wfa, c, output);
@@ -869,7 +869,7 @@ video_coder(char const * const * const image_template,
         if (c->mt->original)
             free_image (c->mt->original);
         c->mt->original = NULL;
-      
+
         remove_states (wfa->basis_states, wfa); /* Clear WFA structure */
     }
 
@@ -927,7 +927,7 @@ read_stdin_header(const char * const * const template,
 /*****************************************************************************
 
                 public code
-  
+
 *****************************************************************************/
 
 int
@@ -957,7 +957,7 @@ fiasco_coder (char const * const *inputname, const char *outputname,
             unsigned int stdinheight, stdinwidth;
             xelval stdinmaxval;
             int stdinformat;
-      
+
             /*
              *  Check parameters
              */
@@ -965,7 +965,7 @@ fiasco_coder (char const * const *inputname, const char *outputname,
                 template = default_input;
             else
                 template = inputname;
-      
+
             if (quality <= 0)
             {
                 set_error (_("Compression quality has to be positive."));
@@ -1013,20 +1013,20 @@ fiasco_coder (char const * const *inputname, const char *outputname,
                     coding_t *c   = alloc_coder(template, cop, wfa->wfainfo,
                                                 stdinwidth, stdinheight,
                                                 stdinmaxval, stdinformat);
-     
+
                     read_basis (cop->basis_name, wfa);
                     append_basis_states (wfa->basis_states, wfa, c);
-     
+
                     c->price = 128 * 64 / quality;
-     
+
                     video_coder (template, output, wfa, c,
                                  stdinwidth, stdinheight, stdinmaxval,
                                  stdinformat);
-     
+
                     close_bitfile (output);
                     free_wfa (wfa);
                     free_coder (c);
-     
+
                     if (default_options)
                         fiasco_c_options_delete (default_options);
                 }
diff --git a/converter/other/fiasco/codec/cwfa.h b/converter/other/fiasco/codec/cwfa.h
index dd86fbfc..e8e2d474 100644
--- a/converter/other/fiasco/codec/cwfa.h
+++ b/converter/other/fiasco/codec/cwfa.h
@@ -33,7 +33,7 @@ extern const real_t MAXCOSTS;
 typedef struct motion
 {
    image_t	 *original;		/* Current image */
-   image_t	 *past;			/* Preceeding image */
+   image_t	 *past;			/* Preceding image */
    image_t	 *future;		/* Succeeding image */
    frame_type_e	  frame_type;		/* frame type: B_, P_ I_FRAME */
    unsigned	  number;		/* display number of frame */
diff --git a/converter/other/fiasco/codec/dfiasco.c b/converter/other/fiasco/codec/dfiasco.c
index d45c9e39..ce25654a 100644
--- a/converter/other/fiasco/codec/dfiasco.c
+++ b/converter/other/fiasco/codec/dfiasco.c
@@ -2,11 +2,11 @@
  *  dfiasco.c:		Decoder public interface
  *
  *  Written by:		Ullrich Hafner
- *		
+ *
  *  This file is part of FIASCO (Fractal Image And Sequence COdec)
  *  Copyright (C) 1994-2000 Ullrich Hafner
  */
- 
+
 /*
  *  $Date: 2000/10/28 17:39:30 $
  *  $Author: hafner $
@@ -38,7 +38,7 @@
 /*****************************************************************************
 
 				prototypes
-  
+
 *****************************************************************************/
 
 static dfiasco_t *
@@ -52,7 +52,7 @@ alloc_dfiasco (wfa_t *wfa, video_t *video, bitfile_t *input,
 /*****************************************************************************
 
 				public code
-  
+
 *****************************************************************************/
 
 fiasco_decoder_t *
@@ -79,7 +79,7 @@ fiasco_decoder_new (const char *filename, const fiasco_d_options_t *options)
 	 default_options = fiasco_d_options_new ();
 	 dop 		 = cast_d_options (default_options);
       }
-      
+
       wfa   = alloc_wfa (NO);
       video = alloc_video (NO);
       input = open_wfa (filename, wfa->wfainfo);
@@ -102,7 +102,7 @@ fiasco_decoder_new (const char *filename, const fiasco_d_options_t *options)
 					dop->magnification,
 					dop->smoothing,
 					dop->image_format);
-   
+
       if (default_options)
 	 fiasco_d_options_delete (default_options);
       if (dfiasco->enlarge_factor >= 0)
@@ -115,7 +115,7 @@ fiasco_decoder_new (const char *filename, const fiasco_d_options_t *options)
 	    if (pixels << (n << 1) > 2048 * 2048)
 	    {
 	       set_error (_("Magnifaction factor `%d' is too large. "
-			    "Maximium value is %d."),
+			    "Maximum value is %d."),
 			  dfiasco->enlarge_factor, MAX(0, n - 1));
 	       fiasco_decoder_delete (decoder);
 	       return NULL;
@@ -152,7 +152,7 @@ fiasco_decoder_write_frame (fiasco_decoder_t *decoder,
 			    const char *filename)
 {
    dfiasco_t *dfiasco = cast_dfiasco (decoder);
-   
+
    if (!dfiasco)
       return 0;
    else
@@ -177,7 +177,7 @@ fiasco_image_t *
 fiasco_decoder_get_frame (fiasco_decoder_t *decoder)
 {
    dfiasco_t *dfiasco = cast_dfiasco (decoder);
-   
+
    if (!dfiasco)
       return NULL;
    else
@@ -197,7 +197,7 @@ fiasco_decoder_get_frame (fiasco_decoder_t *decoder)
 	 image->get_width  = fiasco_image_get_width;
 	 image->get_height = fiasco_image_get_height;
 	 image->is_color   = fiasco_image_is_color;
-	 
+
 	 return image;
       }
       catch
@@ -211,7 +211,7 @@ unsigned
 fiasco_decoder_get_length (fiasco_decoder_t *decoder)
 {
    dfiasco_t *dfiasco = cast_dfiasco (decoder);
-   
+
    if (!dfiasco)
       return 0;
    else
@@ -222,7 +222,7 @@ unsigned
 fiasco_decoder_get_rate (fiasco_decoder_t *decoder)
 {
    dfiasco_t *dfiasco = cast_dfiasco (decoder);
-   
+
    if (!dfiasco)
       return 0;
    else
@@ -239,12 +239,12 @@ fiasco_decoder_get_width (fiasco_decoder_t *decoder)
    else
    {
       unsigned width;
-      
+
       if (dfiasco->enlarge_factor >= 0)
 	 width = dfiasco->wfa->wfainfo->width << dfiasco->enlarge_factor;
       else
 	 width = dfiasco->wfa->wfainfo->width >> - dfiasco->enlarge_factor;
-      
+
       return width & 1 ? width + 1 : width;
    }
 }
@@ -259,7 +259,7 @@ fiasco_decoder_get_height (fiasco_decoder_t *decoder)
    else
    {
       unsigned height;
-      
+
       if (dfiasco->enlarge_factor >= 0)
 	 height = dfiasco->wfa->wfainfo->height << dfiasco->enlarge_factor;
       else
@@ -306,10 +306,10 @@ int
 fiasco_decoder_delete (fiasco_decoder_t *decoder)
 {
    dfiasco_t *dfiasco = cast_dfiasco (decoder);
-   
+
    if (!dfiasco)
       return 1;
-   
+
    try
    {
       free_wfa (dfiasco->wfa);
@@ -330,7 +330,7 @@ fiasco_decoder_delete (fiasco_decoder_t *decoder)
 /*****************************************************************************
 
 				private code
-  
+
 *****************************************************************************/
 
 static dfiasco_t *
@@ -347,14 +347,14 @@ alloc_dfiasco (wfa_t *wfa, video_t *video, bitfile_t *input,
    dfiasco_t *dfiasco = Calloc (1, sizeof (dfiasco_t));
 
    strcpy (dfiasco->id, "DFIASCO");
-   
+
    dfiasco->wfa 	   = wfa;
    dfiasco->video 	   = video;
    dfiasco->input 	   = input;
    dfiasco->enlarge_factor = enlarge_factor;
    dfiasco->smoothing  	   = smoothing;
    dfiasco->image_format   = image_format;
-   
+
    return dfiasco;
 }
 
diff --git a/converter/other/fiasco/codec/ip.c b/converter/other/fiasco/codec/ip.c
index 56b0ae9a..18257a06 100644
--- a/converter/other/fiasco/codec/ip.c
+++ b/converter/other/fiasco/codec/ip.c
@@ -2,7 +2,7 @@
  *  ip.c:		Computation of inner products
  *
  *  Written by:		Ullrich Hafner
- *		
+ *
  *  This file is part of FIASCO (Fractal Image And Sequence COdec)
  *  Copyright (C) 1994-2000 Ullrich Hafner
  */
@@ -27,40 +27,40 @@
 /*****************************************************************************
 
 				prototypes
-  
+
 *****************************************************************************/
 
-static real_t 
+static real_t
 standard_ip_image_state (unsigned address, unsigned level, unsigned domain,
 			 const coding_t *c);
-static real_t 
+static real_t
 standard_ip_state_state (unsigned domain1, unsigned domain2, unsigned level,
 			 const coding_t *c);
 
 /*****************************************************************************
 
 				public code
-  
+
 *****************************************************************************/
 
-real_t 
+real_t
 get_ip_image_state (unsigned image, unsigned address, unsigned level,
 		    unsigned domain, const coding_t *c)
 /*
  *  Return value:
  *	Inner product between 'image' ('address') and
- *      'domain' at given 'level' 
+ *      'domain' at given 'level'
  */
 {
    if (level <= c->options.images_level)
    {
       /*
-       *  Compute the inner product in the standard way by multiplying 
+       *  Compute the inner product in the standard way by multiplying
        *  the pixel-values of the given domain and range image.
-       */ 
+       */
       return standard_ip_image_state (address, level, domain, c);
    }
-   else 
+   else
    {
       /*
        *  Use the already computed inner products stored in 'ip_images_states'
@@ -69,29 +69,29 @@ get_ip_image_state (unsigned image, unsigned address, unsigned level,
    }
 }
 
-void 
+void
 compute_ip_images_state (unsigned image, unsigned address, unsigned level,
 			 unsigned n, unsigned from,
 			 const wfa_t *wfa, coding_t *c)
 /*
  *  Compute the inner products between all states
  *  'from', ... , 'wfa->max_states' and the range images 'image'
- *  (and childs) up to given level.
+ *  (and children) up to given level.
  *
  *  No return value.
  *
  *  Side effects:
  *	inner product tables 'c->ip_images_states' are updated
- */ 
+ */
 {
-   if (level > c->options.images_level) 
+   if (level > c->options.images_level)
    {
       unsigned state, label;
 
       if (level > c->options.images_level + 1)	/* recursive computation */
 	 compute_ip_images_state (MAXLABELS * image + 1, address * MAXLABELS,
 				  level - 1, MAXLABELS * n, from, wfa, c);
-      
+
       /*
        *  Compute inner product <f, Phi_i>
        */
@@ -102,7 +102,7 @@ compute_ip_images_state (unsigned image, unsigned address, unsigned level,
 	       unsigned  edge, count;
 	       int     	 domain;
 	       real_t 	*dst, *src;
-	       
+
 	       if (ischild (domain = wfa->tree [state][label]))
 	       {
 		  if (level > c->options.images_level + 1)
@@ -116,9 +116,9 @@ compute_ip_images_state (unsigned image, unsigned address, unsigned level,
 		  else
 		  {
 		     unsigned newadr = address * MAXLABELS + label;
-		     
+
 		     dst = c->ip_images_state [state] + image;
-		     
+
 		     for (count = n; count; count--, newadr += MAXLABELS)
 			*dst++ += standard_ip_image_state (newadr, level - 1,
 							   domain, c);
@@ -128,7 +128,7 @@ compute_ip_images_state (unsigned image, unsigned address, unsigned level,
 		    edge++)
 	       {
 		  real_t weight = wfa->weight [state][label][edge];
-		  
+
 		  if (level > c->options.images_level + 1)
 		  {
 		     dst = c->ip_images_state [state] + image;
@@ -142,7 +142,7 @@ compute_ip_images_state (unsigned image, unsigned address, unsigned level,
 		     unsigned newadr = address * MAXLABELS + label;
 
 		     dst = c->ip_images_state [state] + image;
-		     
+
 		     for (count = n; count; count--, newadr += MAXLABELS)
 			*dst++ += weight *
 				  standard_ip_image_state (newadr, level - 1,
@@ -153,7 +153,7 @@ compute_ip_images_state (unsigned image, unsigned address, unsigned level,
    }
 }
 
-real_t 
+real_t
 get_ip_state_state (unsigned domain1, unsigned domain2, unsigned level,
 		    const coding_t *c)
 /*
@@ -164,12 +164,12 @@ get_ip_state_state (unsigned domain1, unsigned domain2, unsigned level,
    if (level <= c->options.images_level)
    {
       /*
-       *  Compute the inner product in the standard way by multiplying 
+       *  Compute the inner product in the standard way by multiplying
        *  the pixel-values of both state-images
-       */ 
+       */
       return standard_ip_state_state (domain1, domain2, level, c);
    }
-   else 
+   else
    {
       /*
        *  Use already computed inner products stored in 'ip_images_states'
@@ -181,7 +181,7 @@ get_ip_state_state (unsigned domain1, unsigned domain2, unsigned level,
    }
 }
 
-void 
+void
 compute_ip_states_state (unsigned from, unsigned to,
 			 const wfa_t *wfa, coding_t *c)
 /*
@@ -192,7 +192,7 @@ compute_ip_states_state (unsigned from, unsigned to,
  *
  *  Side effects:
  *	inner product tables 'c->ip_states_state' are computed.
- */ 
+ */
 {
    unsigned level;
    unsigned state1, state2;
@@ -204,25 +204,25 @@ compute_ip_states_state (unsigned from, unsigned to,
    for (level = c->options.images_level + 1;
 	level <= c->options.lc_max_level; level++)
       for (state1 = from; state1 <= to; state1++)
-	 for (state2 = 0; state2 <= state1; state2++) 
+	 for (state2 = 0; state2 <= state1; state2++)
 	    if (need_image (state2, wfa))
 	    {
 	       unsigned	label;
 	       real_t	ip = 0;
-	       
+
 	       for (label = 0; label < MAXLABELS; label++)
 	       {
 		  int	   domain1, domain2;
 		  unsigned edge1, edge2;
 		  real_t   sum, weight2;
-		  
+
 		  if (ischild (domain1 = wfa->tree [state1][label]))
 		  {
 		     sum = 0;
 		     if (ischild (domain2 = wfa->tree [state2][label]))
 			sum = get_ip_state_state (domain1, domain2,
 						  level - 1, c);
-		     
+
 		     for (edge2 = 0;
 			  isedge (domain2 = wfa->into [state2][label][edge2]);
 			  edge2++)
@@ -238,12 +238,12 @@ compute_ip_states_state (unsigned from, unsigned to,
 		       edge1++)
 		  {
 		     real_t weight1 = wfa->weight [state1][label][edge1];
-		     
+
 		     sum = 0;
 		     if (ischild (domain2 = wfa->tree [state2][label]))
 			sum = get_ip_state_state (domain1, domain2,
 						  level - 1, c);
-		     
+
 		     for (edge2 = 0;
 			  isedge (domain2 = wfa->into [state2][label][edge2]);
 			  edge2++)
@@ -262,10 +262,10 @@ compute_ip_states_state (unsigned from, unsigned to,
 /*****************************************************************************
 
 				private code
-  
+
 *****************************************************************************/
 
-static real_t 
+static real_t
 standard_ip_image_state (unsigned address, unsigned level, unsigned domain,
 			 const coding_t *c)
 /*
@@ -283,18 +283,18 @@ standard_ip_image_state (unsigned address, unsigned level, unsigned domain,
 
    if (level > c->options.images_level)
       error ("We cannot interpret a Level %d image.", level);
-   
+
    imageptr = &c->pixels [address * size_of_level (level)];
 
    stateptr = c->images_of_state [domain] + address_of_level (level);
-   
+
    for (i = size_of_level (level); i; i--)
       ip += *imageptr++ * *stateptr++;
 
    return ip;
 }
 
-static real_t 
+static real_t
 standard_ip_state_state (unsigned domain1, unsigned domain2, unsigned level,
 			 const coding_t *c)
 /*
@@ -315,7 +315,7 @@ standard_ip_state_state (unsigned domain1, unsigned domain2, unsigned level,
 
    state1ptr = c->images_of_state [domain1] + address_of_level (level);
    state2ptr = c->images_of_state [domain2] + address_of_level (level);
-   
+
    for (i = size_of_level (level); i; i--)
       ip += *state1ptr++ * *state2ptr++;
 
diff --git a/converter/other/fiasco/codec/prediction.c b/converter/other/fiasco/codec/prediction.c
index e78e5acc..c592baa5 100644
--- a/converter/other/fiasco/codec/prediction.c
+++ b/converter/other/fiasco/codec/prediction.c
@@ -1,9 +1,9 @@
 /*
- *  prediction.c:	Range image prediction with MC or ND	
+ *  prediction.c:	Range image prediction with MC or ND
  *
  *  Written by:		Ullrich Hafner
  *			Michael Unger
- *		
+ *
  *  This file is part of FIASCO (Fractal Image And Sequence COdec)
  *  Copyright (C) 1994-2000 Ullrich Hafner
  */
@@ -41,7 +41,7 @@
 /*****************************************************************************
 
 			     local variables
-  
+
 *****************************************************************************/
 
 typedef struct state_data
@@ -71,7 +71,7 @@ typedef struct state_data
 /*****************************************************************************
 
 				prototypes
-  
+
 *****************************************************************************/
 
 static real_t
@@ -90,9 +90,9 @@ restore_state_data (unsigned from, unsigned to, unsigned max_level,
 /*****************************************************************************
 
 				public code
-  
+
 *****************************************************************************/
- 
+
 real_t
 predict_range (real_t max_costs, real_t price, range_t *range, wfa_t *wfa,
 	       coding_t *c, unsigned band, int y_state, unsigned states,
@@ -124,11 +124,11 @@ predict_range (real_t max_costs, real_t price, range_t *range, wfa_t *wfa,
    rec_d_coeff_model  = c->d_coeff->model;
    rec_tree_model     = c->tree;
    rec_p_tree_model   = c->p_tree;
-   rec_states         = wfa->states;	
+   rec_states         = wfa->states;
    rec_pixels         = c->pixels;
    rec_state_data     = store_state_data (states, rec_states - 1,
 					  c->options.lc_max_level, wfa, c);
-   
+
    /*
     *  Restore probability models to the state before the recursive subdivision
     *  has been started.
@@ -141,14 +141,14 @@ predict_range (real_t max_costs, real_t price, range_t *range, wfa_t *wfa,
    c->coeff->model   	   = c->coeff->model_duplicate (c->coeff, coeff_model);
    c->d_coeff->model   	   = c->d_coeff->model_duplicate (c->d_coeff,
 							  d_coeff_model);
-   
+
    if (c->mt->frame_type == I_FRAME)
-      costs = nd_prediction (max_costs, price, band, y_state, range, wfa, c); 
+      costs = nd_prediction (max_costs, price, band, y_state, range, wfa, c);
    else
       costs = mc_prediction (max_costs, price, band, y_state, range, wfa, c);
-   
+
    c->pixels = rec_pixels;
-   
+
    if (costs < MAXCOSTS)
    {
       /*
@@ -187,25 +187,25 @@ predict_range (real_t max_costs, real_t price, range_t *range, wfa_t *wfa,
       c->d_domain_pool->model_free (c->d_domain_pool->model);
       c->coeff->model_free (c->coeff->model);
       c->d_coeff->model_free (c->d_coeff->model);
-      
+
       c->domain_pool->model   = rec_domain_model;
       c->d_domain_pool->model = rec_d_domain_model;
       c->coeff->model         = rec_coeff_model;
       c->d_coeff->model       = rec_d_coeff_model;
       c->tree                 = rec_tree_model;
       c->p_tree               = rec_p_tree_model;
-      
+
       range->prediction = NO;
-      
+
       if (wfa->states != states)
 	 remove_states (states, wfa);
       restore_state_data (states, rec_states - 1, c->options.lc_max_level,
 			  rec_state_data, wfa, c);
       costs = MAXCOSTS;
    }
- 
+
    return costs;
-} 
+}
 
 void
 clear_norms_table (unsigned level, const wfa_info_t *wi, motion_t *mt)
@@ -238,11 +238,11 @@ update_norms_table (unsigned level, const wfa_info_t *wi, motion_t *mt)
    unsigned  range_size = wi->half_pixel
 			  ? square (wi->search_range)
 			  : square (2 * wi->search_range);
-   
+
    if (level > wi->p_min_level)
    {
       unsigned index;			/* index of motion vector */
-      
+
       for (index = 0; index < range_size; index++)
 	 mt->mc_forward_norms [level][index]
 	    += mt->mc_forward_norms [level - 1][index];
@@ -256,7 +256,7 @@ update_norms_table (unsigned level, const wfa_info_t *wi, motion_t *mt)
 /*****************************************************************************
 
 				private code
-  
+
 *****************************************************************************/
 
 static real_t
@@ -273,7 +273,7 @@ mc_prediction (real_t max_costs, real_t price, unsigned band, int y_state,
     *  If we are at the bottom level of the mc tree:
     *  Fill in the norms table
     */
-   if (prange.level == wfa->wfainfo->p_min_level) 
+   if (prange.level == wfa->wfainfo->p_min_level)
       fill_norms_table (prange.x, prange.y, prange.level, wfa->wfainfo, c->mt);
    /*
     *  Predict 'range' with motion compensation according to frame type.
@@ -283,19 +283,19 @@ mc_prediction (real_t max_costs, real_t price, unsigned band, int y_state,
       find_P_frame_mc (mcpe, price, &prange, wfa->wfainfo, c->mt);
    else
       find_B_frame_mc (mcpe, price, &prange, wfa->wfainfo, c->mt);
-   
+
    costs = (prange.mv_tree_bits + prange.mv_coord_bits) * price;
-   
+
    if (costs < max_costs)		/* motion vector not too expensive */
    {
       unsigned  last_state;		/* last WFA state before recursion */
       real_t   *ipi [MAXSTATES];	/* inner products pointers */
       unsigned  state;
       real_t  	mvt, mvc;
-      
+
       c->pixels = Calloc (width * height, sizeof (real_t));
       cut_to_bintree (c->pixels, mcpe, width, height, 0, 0, width, height);
-   
+
       /*
        *  Approximate MCPE recursively.
        */
@@ -310,7 +310,7 @@ mc_prediction (real_t max_costs, real_t price, unsigned band, int y_state,
 
       mvc = prange.mv_coord_bits;
       mvt = prange.mv_tree_bits;
-      
+
       prange.image           = 0;
       prange.address         = 0;
       prange.tree_bits       = 0;
@@ -329,7 +329,7 @@ mc_prediction (real_t max_costs, real_t price, unsigned band, int y_state,
       if (costs < max_costs)		/* use motion compensation */
       {
 	 unsigned img, adr;		/* temp. values */
-	 
+
 	 img                  = range->image;
 	 adr                  = range->address;
 	 *range               = prange;
@@ -362,7 +362,7 @@ mc_prediction (real_t max_costs, real_t price, unsigned band, int y_state,
    }
    else
       costs = MAXCOSTS;
-   
+
    Free (mcpe);
 
    return costs;
@@ -374,7 +374,7 @@ nd_prediction (real_t max_costs, real_t price, unsigned band, int y_state,
 {
    real_t  costs;			/* current approximation costs */
    range_t lrange = *range;
-   
+
    /*
     *  Predict 'range' with DC component approximation
     */
@@ -397,11 +397,11 @@ nd_prediction (real_t max_costs, real_t price, unsigned band, int y_state,
       lrange.weights_bits    = c->coeff->bits (&w, s, range->level, c->coeff);
    }
    costs = price * (lrange.weights_bits + lrange.nd_tree_bits);
-   
+
    /*
-    *  Recursive aproximation of difference image
+    *  Recursive approximation of difference image
     */
-   if (costs < max_costs)		
+   if (costs < max_costs)
    {
       unsigned  state;
       range_t  	rrange;			/* range: recursive subdivision */
@@ -418,14 +418,14 @@ nd_prediction (real_t max_costs, real_t price, unsigned band, int y_state,
 	 unsigned  n;
 	 real_t *src, *dst;		/* pointers to image data */
 	 real_t w = - lrange.weight [0] * c->images_of_state [0][0];
-		     
-	 src = c->pixels + range->address * size_of_level (range->level); 
+
+	 src = c->pixels + range->address * size_of_level (range->level);
 	 dst = c->pixels = pixels = Calloc (width * height, sizeof (real_t));
 
 	 for (n = width * height; n; n--)
 	    *dst++ = *src++ + w;
       }
-      
+
       /*
        *  Approximate difference recursively.
        */
@@ -448,13 +448,13 @@ nd_prediction (real_t max_costs, real_t price, unsigned band, int y_state,
 	    c->ip_images_state[state]
 	       = Calloc (size_of_tree (c->products_level), sizeof (real_t));
 	 }
-      
+
       compute_ip_images_state (rrange.image, rrange.address, rrange.level,
 			       1, 0, wfa, c);
-      
+
       costs += subdivide (max_costs - costs, band, y_state, &rrange, wfa, c,
 			  NO, YES);
-      
+
       Free (pixels);
 
       if (costs < max_costs && ischild (rrange.tree)) /* use prediction */
@@ -469,7 +469,7 @@ nd_prediction (real_t max_costs, real_t price, unsigned band, int y_state,
 	 range->address          = adr;
 	 range->nd_tree_bits    += lrange.nd_tree_bits;
 	 range->nd_weights_bits += lrange.weights_bits;
-	 
+
 	 for (edge = 0; isedge (lrange.into [edge]); edge++)
 	 {
 	    range->into [edge]   = lrange.into [edge];
@@ -485,7 +485,7 @@ nd_prediction (real_t max_costs, real_t price, unsigned band, int y_state,
       }
       else
 	 costs = MAXCOSTS;
-      
+
       for (state = 0; state <= last_state; state++)
 	 if (need_image (state, wfa))
 	 {
@@ -515,9 +515,9 @@ store_state_data (unsigned from, unsigned to, unsigned max_level,
 
    if (to < from)
       return NULL;			/* nothing to do */
-   
+
    data = Calloc (to - from + 1, sizeof (state_data_t));
-   
+
    for (state = from; state <= to; state++)
    {
       sd = &data [state - from];
@@ -527,12 +527,12 @@ store_state_data (unsigned from, unsigned to, unsigned max_level,
       sd->domain_type        = wfa->domain_type [state];
       sd->images_of_state    = c->images_of_state [state];
       sd->inner_products     = c->ip_images_state [state];
-      
+
       wfa->domain_type [state]   = 0;
       c->images_of_state [state] = NULL;
       c->ip_images_state [state] = NULL;
-				   
-      for (label = 0; label < MAXLABELS; label++) 
+
+      for (label = 0; label < MAXLABELS; label++)
       {
 	 sd->tree [label]     	= wfa->tree [state][label];
 	 sd->y_state [label]  	= wfa->y_state [state][label];
@@ -542,11 +542,11 @@ store_state_data (unsigned from, unsigned to, unsigned max_level,
 	 sd->y [label]        	= wfa->y [state][label];
 	 sd->prediction [label] = wfa->prediction [state][label];
 
-	 memcpy (sd->weight [label], wfa->weight [state][label], 
+	 memcpy (sd->weight [label], wfa->weight [state][label],
 		 sizeof (real_t) * (MAXEDGES + 1));
-	 memcpy (sd->int_weight [label], wfa->int_weight [state][label], 
+	 memcpy (sd->int_weight [label], wfa->int_weight [state][label],
 		 sizeof (word_t) * (MAXEDGES + 1));
-	 memcpy (sd->into [label], wfa->into [state][label], 
+	 memcpy (sd->into [label], wfa->into [state][label],
 		 sizeof (word_t) * (MAXEDGES + 1));
 
 	 wfa->into [state][label][0] = NO_EDGE;
@@ -569,7 +569,7 @@ restore_state_data (unsigned from, unsigned to, unsigned max_level,
 		    state_data_t *data, wfa_t *wfa, coding_t *c)
 /*
  *  Restore all state data starting from state 'from'.
- *  
+ *
  *  No return value.
  */
 {
@@ -578,15 +578,15 @@ restore_state_data (unsigned from, unsigned to, unsigned max_level,
 
    if (to < from)
       return;				/* nothing to do */
-   
+
    for (state = from; state <= to; state++)
    {
       sd = &data [state - from];
-      
+
       wfa->final_distribution [state] = sd->final_distribution;
       wfa->level_of_state [state]     = sd->level_of_state;
       wfa->domain_type [state]        = sd->domain_type;
-      
+
       if (c->images_of_state [state] != NULL)
 	 Free (c->images_of_state [state]);
       c->images_of_state [state] = sd->images_of_state;
@@ -603,14 +603,14 @@ restore_state_data (unsigned from, unsigned to, unsigned max_level,
 	 wfa->x [state][label]        	= sd->x [label];
 	 wfa->y [state][label]        	= sd->y [label];
 	 wfa->prediction [state][label] = sd->prediction [label];
-	 
-	 memcpy (wfa->weight [state][label], sd->weight [label], 
+
+	 memcpy (wfa->weight [state][label], sd->weight [label],
 		 sizeof(real_t) * (MAXEDGES + 1));
-	 memcpy (wfa->int_weight [state][label], sd->int_weight [label], 
+	 memcpy (wfa->int_weight [state][label], sd->int_weight [label],
 		 sizeof(word_t) * (MAXEDGES + 1));
-	 memcpy (wfa->into [state][label], sd->into [label],  
+	 memcpy (wfa->into [state][label], sd->into [label],
 		 sizeof(word_t) * (MAXEDGES + 1));
-      }	 
+      }
       for (level = c->options.images_level + 1; level <= max_level;
 	   level++)
       {
diff --git a/converter/other/fiasco/codec/subdivide.c b/converter/other/fiasco/codec/subdivide.c
index 348f838a..3ddf1ffc 100644
--- a/converter/other/fiasco/codec/subdivide.c
+++ b/converter/other/fiasco/codec/subdivide.c
@@ -2,7 +2,7 @@
  *  subdivide.c:	Recursive subdivision of range images
  *
  *  Written by:		Ullrich Hafner
- *		
+ *
  *  This file is part of FIASCO (Fractal Image And Sequence COdec)
  *  Copyright (C) 1994-2000 Ullrich Hafner
  */
@@ -56,10 +56,10 @@ init_range (range_t *range, const image_t *image, unsigned band,
 /*****************************************************************************
 
 				public code
-  
+
 *****************************************************************************/
 
-real_t 
+real_t
 subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
 	   wfa_t *wfa, coding_t *c, bool_t prediction, bool_t delta)
 /*
@@ -71,7 +71,7 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
  *  If 'prediction' is TRUE then also test motion compensation or
  *  nondeterministic approximation.
  *  If 'delta' is TRUE then current range is already predicted.
- *  
+ *
  *  Return value:
  *	costs of the best approximation or MAXCOSTS if costs exceed 'max_costs'
  *
@@ -82,7 +82,7 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
  */
 {
    real_t    subdivide_costs;        /* Costs arising from approx. the current
-				       range with two childs */
+				       range with two children */
    real_t    lincomb_costs;          /* Costs arising from approx. the current
 				       range with a linear combination */
    int	     new_y_state [MAXLABELS];	/* Corresponding state of Y */
@@ -91,7 +91,7 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
    bool_t    try_nd;			/* YES: try ND prediction */
    unsigned  states;			/* Number of states before the
 					   recursive subdivision starts */
-   void     *domain_model;		/* copy of domain pool model */      
+   void     *domain_model;		/* copy of domain pool model */
    void     *d_domain_model;		/* copy of delta domain pool model */
    void     *lc_domain_model;		/* copy of domain pool model */
    void     *lc_d_domain_model;		/* copy of delta domain pool model */
@@ -103,17 +103,17 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
    tree_t    p_tree_model;		/* copy of pred. tree model */
    range_t   lrange;			/* range of lin. comb. approx. */
    range_t   rrange;			/* range of recursive approx. */
-   range_t   child [MAXLABELS];		/* new childs of the current range */
+   range_t   child [MAXLABELS];		/* new children of the current range */
    static unsigned percent = 0;		/* status of progress meter */
 
    if (wfa->wfainfo->level == range->level)
       percent = 0;
-   
+
    range->into [0] = NO_EDGE;		/* default approximation: empty */
    range->tree     = RANGE;
 
    if (range->level < 3)		/* Don't process small ranges */
-      return MAXCOSTS;	
+      return MAXCOSTS;
 
    /*
     *  If image permutation (tiling) is performed and the tiling level
@@ -123,7 +123,7 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
        && range->level == wfa->wfainfo->level - c->tiling->exponent)
    {
       unsigned width, height;		/* size of range (dummies)*/
-      
+
       if (c->tiling->vorder [range->global_address] < 0)
 	 return 0;			/* nothing to do */
       else
@@ -140,7 +140,7 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
     *  Check whether prediction is allowed or not
     *  mc == motion compensation, nd == nondeterminism
     */
-   try_mc = (prediction && c->mt->frame_type != I_FRAME			
+   try_mc = (prediction && c->mt->frame_type != I_FRAME
 	     && range->level >= wfa->wfainfo->p_min_level
 	     && range->level <= wfa->wfainfo->p_max_level
 	     && (range->x + width_of_level (range->level)
@@ -155,21 +155,21 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
    if (try_mc)
       clear_norms_table (range->level, wfa->wfainfo, c->mt);
 
-   
+
    /*
     *  Check if current range must be initialized. I.e. range pixels must
     *  be copied from entire image to bintree pixel buffer. Moreover,
     *  all inner products tables must be initialized.
     */
-   if (range->level == c->options.lc_max_level)	
+   if (range->level == c->options.lc_max_level)
       init_range (range, c->mt->original, band, wfa, c);
-   
+
    price = c->price;
-   if (band != Y)			
+   if (band != Y)
       price *= c->options.chroma_decrease; /* less quality for chroma bands */
 
    /*
-    *  Compute childs of corresponding state in Y band
+    *  Compute children of corresponding state in Y band
     */
    if (band != Y)			/* Cb and Cr bands only */
    {
@@ -183,7 +183,7 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
    }
    else
       new_y_state [0] = new_y_state [1] = RANGE;
-   
+
    /*
     *  Store contents of all models that may get modified during recursion
     */
@@ -193,8 +193,8 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
    d_coeff_model  = c->d_coeff->model_duplicate (c->d_coeff, c->d_coeff->model);
    tree_model     = c->tree;
    p_tree_model   = c->p_tree;
-   states         = wfa->states;	
-   
+   states         = wfa->states;
+
    /*
     *  First alternative of range approximation:
     *  Compute costs of linear combination.
@@ -208,10 +208,10 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
       lrange.weights_bits    = 0;
       lrange.mv_tree_bits    = try_mc ? 1 : 0; /* mc allowed but not used */
       lrange.mv_coord_bits   = 0;
-      lrange.nd_tree_bits    = 0;	
-      lrange.nd_weights_bits = 0;	
+      lrange.nd_tree_bits    = 0;
+      lrange.nd_weights_bits = 0;
       lrange.prediction	     = NO;
-      
+
       lincomb_costs
 	 = approximate_range (max_costs, price, c->options.max_elements,
 			      y_state, &lrange,
@@ -219,7 +219,7 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
 			      (delta ? c->d_coeff : c->coeff), wfa, c);
    }
    else
-      lincomb_costs = MAXCOSTS;		
+      lincomb_costs = MAXCOSTS;
 
    /*
     *  Store contents of models that have been modified
@@ -237,7 +237,7 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
    c->coeff->model         = c->coeff->model_duplicate (c->coeff, coeff_model);
    c->d_coeff->model       = c->d_coeff->model_duplicate (c->d_coeff,
 							  d_coeff_model);
-   
+
    /*
     *  Second alternative of range approximation:
     *  Compute costs of recursive subdivision.
@@ -245,8 +245,8 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
    if (range->level > c->options.lc_min_level) /* range is large enough */
    {
       unsigned label;
-      
-      memset (&child [0], 0, 2 * sizeof (range_t)); /* initialize childs */
+
+      memset (&child [0], 0, 2 * sizeof (range_t)); /* initialize children */
 
       /*
        *  Initialize a new range for recursive approximation
@@ -260,7 +260,7 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
       rrange.mv_coord_bits   = 0;
       rrange.nd_tree_bits    = try_nd ?
 			       tree_bits (CHILD, lrange.level, &c->p_tree): 0;
-      rrange.nd_weights_bits = 0;	
+      rrange.nd_weights_bits = 0;
       rrange.prediction	     = NO;
 
       /*
@@ -271,11 +271,11 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
 			 + rrange.matrix_bits + rrange.mv_tree_bits
 			 + rrange.mv_coord_bits + rrange.nd_tree_bits
 			 + rrange.nd_weights_bits) * price;
-      
-      for (label = 0; label < MAXLABELS; label++) 
+
+      for (label = 0; label < MAXLABELS; label++)
       {
 	 real_t remaining_costs;	/* upper limit for next recursion */
-	 
+
 	 child[label].image          = rrange.image * MAXLABELS + label + 1;
 	 child[label].address        = rrange.address * MAXLABELS + label;
 	 child[label].global_address = rrange.global_address * MAXLABELS
@@ -289,8 +289,8 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
 			  ? (rrange.y
 			     + label * height_of_level (rrange.level - 1))
 			  : rrange.y;
-	 
-	 /* 
+
+	 /*
 	  *  If necessary compute the inner products of the new states
 	  *  (generated during the recursive approximation of child [0])
 	  */
@@ -298,7 +298,7 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
 	    compute_ip_images_state (child[label].image, child[label].address,
 				     child[label].level, 1, states, wfa, c);
 	 /*
-	  *  Call subdivide() for both childs. 
+	  *  Call subdivide() for both children.
 	  *  Abort the recursion if 'subdivide_costs' exceed 'lincomb_costs'
 	  *  or 'max_costs'.
 	  */
@@ -315,10 +315,10 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
 	    fill_norms_table (child[label].x, child[label].y,
 			      child[label].level, wfa->wfainfo, c->mt);
 	 }
-	 
+
 	 if (try_mc)
 	    update_norms_table (rrange.level, wfa->wfainfo, c->mt);
-	 
+
 	 /*
 	  *  Update of progress meter
 	  */
@@ -327,7 +327,7 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
 	    if (c->options.progress_meter == FIASCO_PROGRESS_PERCENT)
 	    {
 	       unsigned	new_percent; 	/* new status of progress meter */
-	 
+
 	       new_percent = (child[label].global_address + 1) * 100.0
 			     / (1 << (wfa->wfainfo->level - child[label].level));
 	       if (new_percent > percent)
@@ -339,7 +339,7 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
 	    else if (c->options.progress_meter == FIASCO_PROGRESS_BAR)
 	    {
 	       unsigned	new_percent;	/* new status of progress meter */
-	 
+
 	       new_percent = (child[label].global_address + 1) * 50.0
 			     / (1 << (wfa->wfainfo->level
 				      - child[label].level));
@@ -349,15 +349,15 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
 	       }
 	    }
 	 }
-   
+
 	 /*
-	  *  If costs of subdivision exceed costs of linear combination 
+	  *  If costs of subdivision exceed costs of linear combination
 	  *  then abort recursion.
 	  */
-	 if (subdivide_costs >= MIN(lincomb_costs, max_costs)) 
+	 if (subdivide_costs >= MIN(lincomb_costs, max_costs))
 	 {
 	    subdivide_costs = MAXCOSTS;
-	    break; 
+	    break;
 	 }
 	 rrange.err             += child [label].err;
 	 rrange.tree_bits       += child [label].tree_bits;
@@ -379,8 +379,8 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
 
    /*
     *  Third alternative of range approximation:
-    *  Predict range via motion compensation or nondeterminism and 
-    *  approximate delta image. 
+    *  Predict range via motion compensation or nondeterminism and
+    *  approximate delta image.
     */
    if (try_mc || try_nd)		/* try prediction */
    {
@@ -403,7 +403,7 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
            c->d_coeff->model_free (d_coeff_model);
            c->coeff->model_free (lc_coeff_model);
            c->d_coeff->model_free (lc_d_coeff_model);
-	 
+
            return prediction_costs;
        }
    }
@@ -423,25 +423,25 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
       c->d_coeff->model_free (c->d_coeff->model);
       c->coeff->model_free (lc_coeff_model);
       c->d_coeff->model_free (lc_d_coeff_model);
-	 
+
       c->domain_pool->model   = domain_model;
       c->d_domain_pool->model = d_domain_model;
       c->coeff->model	      = coeff_model;
       c->d_coeff->model	      = d_coeff_model;
       c->tree                 = tree_model;
       c->p_tree               = p_tree_model;
-      
+
       if (wfa->states != states)
 	 remove_states (states, wfa);
 
       return MAXCOSTS;
    }
-   else if (lincomb_costs < subdivide_costs) 
+   else if (lincomb_costs < subdivide_costs)
    {
       /*
        *  Use the linear combination: The factors of the linear combination
        *  are stored already in 'range', so revert the probability models
-       *  only. 
+       *  only.
        */
       c->domain_pool->model_free (c->domain_pool->model);
       c->d_domain_pool->model_free (c->d_domain_pool->model);
@@ -452,7 +452,7 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
       c->d_coeff->model_free (c->d_coeff->model);
       c->coeff->model_free (coeff_model);
       c->d_coeff->model_free (d_coeff_model);
-      
+
       c->domain_pool->model   = lc_domain_model;
       c->d_domain_pool->model = lc_d_domain_model;
       c->coeff->model	      = lc_coeff_model;
@@ -461,7 +461,7 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
       c->p_tree               = p_tree_model;
 
       *range = lrange;
-      
+
       if (wfa->states != states)
 	 remove_states (states, wfa);
 
@@ -474,8 +474,8 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
        *  given in child[].
        *  Don't use state in linear combinations in any of the following cases:
        *  - if color component is Cb or Cr
-       *  - if level of state > tiling level 
-       *  - if state is (partially) outside image geometry 
+       *  - if level of state > tiling level
+       *  - if state is (partially) outside image geometry
        */
       if (band > Y
 	  || (c->tiling->exponent
@@ -545,7 +545,7 @@ cut_to_bintree (real_t *dst, const word_t *src,
 /*****************************************************************************
 
 				private code
-  
+
 *****************************************************************************/
 
 static void
@@ -558,7 +558,7 @@ init_new_state (bool_t auxiliary_state, bool_t delta, range_t *range,
  *  If flag 'delta' is set then state represents a delta image (prediction via
  *  nondeterminism or motion compensation).
  *  'range' the current range image,
- *   'child []' the left and right childs of 'range'.
+ *   'child []' the left and right children of 'range'.
  *
  *  No return value.
  *
@@ -583,11 +583,11 @@ init_new_state (bool_t auxiliary_state, bool_t delta, range_t *range,
    }
    else
       state_is_domain = NO;
-   
+
    range->into [0] = NO_EDGE;
    range->tree     = wfa->states;
-   
-   for (label = 0; label < MAXLABELS; label++) 
+
+   for (label = 0; label < MAXLABELS; label++)
    {
       wfa->tree [wfa->states][label]       = child [label].tree;
       wfa->y_state [wfa->states][label]    = y_state [label];
@@ -605,7 +605,7 @@ init_new_state (bool_t auxiliary_state, bool_t delta, range_t *range,
       warning ("Negative image norm: %f, %f", child [0].err, child [1].err);
 
 /*    state_is_domain = YES; */
-   
+
    append_state (!state_is_domain,
 		 compute_final_distribution (wfa->states, wfa),
 		 range->level, wfa, c);
@@ -621,13 +621,13 @@ init_range (range_t *range, const image_t *image, unsigned band,
  *  No return value.
  *
  *  Side effects:
- *	'c->pixels' are filled with pixel values of image block 
- *	'c->ip_images_state' are computed with respect to new image block 
+ *	'c->pixels' are filled with pixel values of image block
+ *	'c->ip_images_state' are computed with respect to new image block
  *	'range->address' and 'range->image' are initialized with zero
  */
 {
    unsigned state;
-   
+
    /*
     *  Clear already computed products
     */
@@ -640,7 +640,7 @@ init_range (range_t *range, const image_t *image, unsigned band,
 		   image->width, image->height,
 		   range->x, range->y, width_of_level (range->level),
 		   height_of_level (range->level));
-   
+
    range->address = range->image = 0;
    compute_ip_images_state (0, 0, range->level, 1, 0, wfa, c);
 }
diff --git a/converter/other/fiasco/codec/wfa.h b/converter/other/fiasco/codec/wfa.h
index 59020fc1..4e66ccbd 100644
--- a/converter/other/fiasco/codec/wfa.h
+++ b/converter/other/fiasco/codec/wfa.h
@@ -2,7 +2,7 @@
  *  wfa.h
  *
  *  Written by:		Ullrich Hafner
- *		
+ *
  *  This file is part of FIASCO (Fractal Image And Sequence COdec)
  *  Copyright (C) 1994-2000 Ullrich Hafner
  */
@@ -20,7 +20,7 @@
 #define MAXEDGES  5
 #define MAXSTATES 6000
 #define MAXLABELS 2			/* only bintree possible anymore */
-#define MAXLEVEL  22 
+#define MAXLEVEL  22
 
 #define FIASCO_BINFILE_RELEASE   2
 #define FIASCO_MAGIC	         "FIASCO" /* FIASCO magic number */
@@ -85,7 +85,7 @@ typedef struct wfa_info
    char	    *basis_name;		/* filename of the initial basis */
    char     *title;			/* title of FIASCO stream */
    char     *comment;			/* comment for FIASCO stream */
-   
+
    unsigned  max_states;		/* max. cardinality of domain pool */
    unsigned  chroma_max_states;		/* max. cardinality of domain pool for
 					   chroma band coding */
@@ -111,7 +111,7 @@ typedef struct wfa_info
 
 typedef struct wfa
 /*
- *  Used to store all informations and data structures of a WFA
+ *  Used to store all information and data structures of a WFA
  */
 {
    wfa_info_t	*wfainfo;		/* misc. information about the WFA */
diff --git a/converter/other/fiasco/doc/fiasco_c_options_new.3 b/converter/other/fiasco/doc/fiasco_c_options_new.3
index d873b642..a7a96409 100644
--- a/converter/other/fiasco/doc/fiasco_c_options_new.3
+++ b/converter/other/fiasco/doc/fiasco_c_options_new.3
@@ -407,11 +407,10 @@ during coding. The following types are available:
 
 .SH RETURN VALUES
 The function \fBfiasco_c_options_new()\fP returns a pointer to the
-newly allocated coder option object. If an error has been catched, a
+newly allocated coder option object. If an error has been caught, a
 NULL pointer is returned.
 
-All set functions return 1 on success and 0 if an error has been
-catched.  
+All set functions return 1 on success and 0 if an error has been caught.
 
 In case of an error, use the function fiasco_get_error_message(3) to
 get a string with the last error message of FIASCO.
diff --git a/converter/other/fiasco/doc/fiasco_coder.3 b/converter/other/fiasco/doc/fiasco_coder.3
index 9f2e0f8e..ce32bb4d 100644
--- a/converter/other/fiasco/doc/fiasco_coder.3
+++ b/converter/other/fiasco/doc/fiasco_coder.3
@@ -73,7 +73,7 @@ available to change the default values.
 
 .SH RETURN VALUE
 The function \fBfiasco_coder()\fP returns 1 if the FIASCO file has
-been successfully written. If an error has been catched during
+been successfully written. If an error has been caught during
 compression, 0 is returned - use the function
 fiasco_get_error_message(3) to get the last error message of FIASCO.
 
diff --git a/converter/other/fiasco/doc/fiasco_d_options_new.3 b/converter/other/fiasco/doc/fiasco_d_options_new.3
index d7f2181a..02feabb0 100644
--- a/converter/other/fiasco/doc/fiasco_d_options_new.3
+++ b/converter/other/fiasco/doc/fiasco_d_options_new.3
@@ -97,11 +97,11 @@ channel is only one half of the width and height of the luminance.
 
 .SH RETURN VALUES
 The function \fBfiasco_d_options_new()\fP returns a pointer to the
-newly allocated decoder option object. If an error has been catched, a
+newly allocated decoder option object. If an error has been caught, a
 NULL pointer is returned.
 
 All set functions return 1 on success and 0 if an error has been
-catched.  
+caught.  
 
 In case of an error, use the function fiasco_get_error_message(3) to
 get a string with the last error message of FIASCO.
diff --git a/converter/other/fiasco/doc/fiasco_decoder_new.3 b/converter/other/fiasco/doc/fiasco_decoder_new.3
index 5d1d0d08..2af44f43 100644
--- a/converter/other/fiasco/doc/fiasco_decoder_new.3
+++ b/converter/other/fiasco/doc/fiasco_decoder_new.3
@@ -125,37 +125,37 @@ store the internal state of the decoder.
 
 .SH RETURN VALUES
 The function \fBfiasco_decoder_new()\fP returns a pointer to the newly
-allocated decoder object. If an error has been catched, a NULL pointer
+allocated decoder object. If an error has been caught, a NULL pointer
 is returned.
 
 The function \fBfiasco_decoder_write_frame()\fP returns 1 if the file
 has been successfully written. Otherwise, the function returns 0.
 
 The function \fBfiasco_decoder_get_frame()\fP returns a pointer to the
-newly allocated FIASCO image object. If an error has been catched, a NULL
+newly allocated FIASCO image object. If an error has been caught, a NULL
 pointer is returned.
 
 The function \fBfiasco_decoder_get_length()\fP returns the number of
-frames of the FIASCO file. If an error has been catched, 0 is
+frames of the FIASCO file. If an error has been caught, 0 is
 returned. 
 
 The function \fBfiasco_decoder_get_rate()\fP returns the
 framerate (number of frames per second) of the FIASCO file. If an
-error has been catched, 0 is returned.
+error has been caught, 0 is returned.
 
 The function \fBfiasco_decoder_get_width()\fP returns the width of the
-decoded frames of the FIASCO file. If an error has been catched, 0 is
+decoded frames of the FIASCO file. If an error has been caught, 0 is
 returned.
 
 The function \fBfiasco_decoder_get_height()\fP returns the height of the
-decoded frames of the FIASCO file. If an error has been catched, 0 is
+decoded frames of the FIASCO file. If an error has been caught, 0 is
 returned.
 
 The function \fBfiasco_decoder_get_title()\fP returns an optional
-title of the FIASCO file. If an error has been catched, 0 is returned.
+title of the FIASCO file. If an error has been caught, 0 is returned.
 
 The function \fBfiasco_decoder_get_comment()\fP returns an optional
-comment of the FIASCO file. If an error has been catched, 0 is returned.
+comment of the FIASCO file. If an error has been caught, 0 is returned.
 
 The function \fBfiasco_decoder_is_color()\fP returns 0 if the decoded
 frames are grayscale images, otherwise a non-zero value is
diff --git a/converter/other/fiasco/doc/fiasco_get_error_message.3 b/converter/other/fiasco/doc/fiasco_get_error_message.3
index ce53e6d9..da32c94e 100644
--- a/converter/other/fiasco/doc/fiasco_get_error_message.3
+++ b/converter/other/fiasco/doc/fiasco_get_error_message.3
@@ -3,7 +3,7 @@
 
 .SH NAME
 .B  fiasco_get_error_message
-\- return string describing last error catched in FIASCO library
+\- return string describing last error caught in FIASCO library
 
 .SH SYNOPSIS
 .B #include <fiasco.h>
@@ -15,11 +15,11 @@
 
 .SH DESCRIPTION
 The \fBfiasco_get_error_message()\fP function returns a string
-describing the last error that has been catched in the FIASCO library.
+describing the last error that has been caught in the FIASCO library.
 
 .SH RETURN VALUE
 The function \fBfiasco_get_error_message()\fP returns the appropriate
-description string, or an empty string if no error has been catched so
+description string, or an empty string if no error has been caught so
 far.
 
 .SH "SEE ALSO"
diff --git a/converter/other/fiasco/doc/fiasco_image_new.3 b/converter/other/fiasco/doc/fiasco_image_new.3
index ac3297bf..e4701a14 100644
--- a/converter/other/fiasco/doc/fiasco_image_new.3
+++ b/converter/other/fiasco/doc/fiasco_image_new.3
@@ -61,14 +61,14 @@ the environment variable \fBFIASCO_IMAGES\fP.
 
 .SH RETURN VALUE
 The function \fBfiasco_image_new()\fP returns a pointer to the newly
-allocated image object. If an error has been catched, a NULL pointer
+allocated image object. If an error has been caught, a NULL pointer
 is returned.
 
 The function \fBfiasco_image_get_width()\fP returns the width of the
-image. If an error has been catched, 0 is returned.
+image. If an error has been caught, 0 is returned.
 
 The function \fBfiasco_image_get_height()\fP returns the height of the
-image. If an error has been catched, 0 is returned.
+image. If an error has been caught, 0 is returned.
 
 The function \fBfiasco_image_is_color()\fP returns 0 if the image
 object is a grayscale image, otherwise a non-zero value is returned.
diff --git a/converter/other/fiasco/doc/fiasco_options_new.3 b/converter/other/fiasco/doc/fiasco_options_new.3
index f26586a7..884876c7 100644
--- a/converter/other/fiasco/doc/fiasco_options_new.3
+++ b/converter/other/fiasco/doc/fiasco_options_new.3
@@ -416,11 +416,11 @@ during coding. The following types are available:
 
 .SH RETURN VALUES
 The function \fBfiasco_decoder_new()\fP returns a pointer to the newly
-allocated option object. If an error has been catched, a NULL pointer
+allocated option object. If an error has been caught, a NULL pointer
 is returned.
 
 All set functions return 1 on success and 0 if an error has been
-catched.  
+caught.  
 
 In case of an error, use the function fiasco_get_error_message(3) to
 get a string with the last error message of FIASCO.
diff --git a/converter/other/fiasco/doc/fiasco_renderer_new.3 b/converter/other/fiasco/doc/fiasco_renderer_new.3
index 8b5e47cd..54bbdbcf 100644
--- a/converter/other/fiasco/doc/fiasco_renderer_new.3
+++ b/converter/other/fiasco/doc/fiasco_renderer_new.3
@@ -97,7 +97,7 @@ fiasco_image_new(3).
 
 .SH RETURN VALUE
 The function \fBfiasco_renderer_new()\fP returns a pointer to the newly
-allocated renderer object. If an error has been catched, a NULL pointer
+allocated renderer object. If an error has been caught, a NULL pointer
 is returned.
 
 The function \fBfiasco_renderer_render()\fP returns 1 if the image
diff --git a/converter/other/fiasco/input/basis.c b/converter/other/fiasco/input/basis.c
index aa371ea1..e5ced0d0 100644
--- a/converter/other/fiasco/input/basis.c
+++ b/converter/other/fiasco/input/basis.c
@@ -1,8 +1,8 @@
 /*
- *  basis.c:		WFA initial basis files	
+ *  basis.c:		WFA initial basis files
  *
  *  Written by:		Ullrich Hafner
- *		
+ *
  *  This file is part of FIASCO (Fractal Image And Sequence COdec)
  *  Copyright (C) 1994-2000 Ullrich Hafner
  */
@@ -44,29 +44,29 @@ typedef struct
 /*****************************************************************************
 
 				prototypes
-  
+
 *****************************************************************************/
 
 static void
 small_init (basis_values_t *bv);
 
-static basis_file_t const basis_files[] = { 
+static basis_file_t const basis_files[] = {
     {"small.fco", small_init},
     {"small.wfa", small_init},
-    {NULL, NULL} 
+    {NULL, NULL}
 };
 
 /*****************************************************************************
 
 				public code
-  
+
 *****************************************************************************/
 
 bool_t
 get_linked_basis (const char *basis_name, wfa_t *wfa)
 /*
- *  Check wether given WFA initial basis 'basis_name' is already linked
- *  with the excecutable. If the basis is available then fill the 'wfa' struct
+ *  Check whether given WFA initial basis 'basis_name' is already linked
+ *  with the executable. If the basis is available then fill the 'wfa' struct
  *  according to the stored data, otherwise print a warning message.
  *
  *  Return value:
@@ -79,18 +79,18 @@ get_linked_basis (const char *basis_name, wfa_t *wfa)
    bool_t	  success = NO;		/* indicates if basis is found */
    unsigned	  n;			/* counter */
    basis_values_t bv;			/* basis values */
-   
+
    for (n = 0; basis_files [n].filename != NULL; n++)
       if (streq (basis_files [n].filename, basis_name))	/* basis is stored */
       {
-	 unsigned state, edge;		
-	 
+	 unsigned state, edge;
+
 	 (*basis_files [n].function) (&bv); /* initialize local variables */
 	 /*
 	  *  Generate WFA
 	  */
 	 wfa->basis_states = wfa->states = bv.states + 1;
-	 wfa->domain_type[0]             = USE_DOMAIN_MASK; 
+	 wfa->domain_type[0]             = USE_DOMAIN_MASK;
 	 wfa->final_distribution[0]      = 128;
 	 append_edge (0, 0, 1.0, 0, wfa);
 	 append_edge (0, 0, 1.0, 1, wfa);
@@ -105,13 +105,13 @@ get_linked_basis (const char *basis_name, wfa_t *wfa)
 	    append_edge (bv.transitions [edge][0], bv.transitions [edge][1],
 			 bv.transitions [edge][2], bv.transitions [edge][3],
 			 wfa);
-	 
+
 	 success = YES;
 	 break;
       }
 
    if (!success)
-      warning ("WFA initial basis '%s' isn't linked with the excecutable yet."
+      warning ("WFA initial basis '%s' isn't linked with the executable yet."
 	       "\nLoading basis from disk instead.", basis_name);
 
    return success;
@@ -120,7 +120,7 @@ get_linked_basis (const char *basis_name, wfa_t *wfa)
 /*****************************************************************************
 
 				private code
-  
+
 *****************************************************************************/
 
 /*****************************************************************************
@@ -141,3 +141,6 @@ small_init (basis_values_t *bv)
    bv->use_domain  = use_domain_small;
    bv->transitions = transitions_small;
 }
+
+
+
diff --git a/converter/other/fiasco/input/matrices.c b/converter/other/fiasco/input/matrices.c
index 388855ea..d20a27eb 100644
--- a/converter/other/fiasco/input/matrices.c
+++ b/converter/other/fiasco/input/matrices.c
@@ -2,7 +2,7 @@
  *  matrices.c:		Input of transition matrices
  *
  *  Written by:		Ullrich Hafner
- *  
+ *
  *  This file is part of FIASCO (Fractal Image And Sequence COdec)
  *  Copyright (C) 1994-2000 Ullrich Hafner
  */
@@ -34,7 +34,7 @@
 /*****************************************************************************
 
 				prototypes
-  
+
 *****************************************************************************/
 
 static unsigned
@@ -49,19 +49,19 @@ compute_y_state (int state, int y_state, wfa_t *wfa);
 /*****************************************************************************
 
 				public code
-  
+
 *****************************************************************************/
 
 unsigned
 read_matrices (wfa_t *wfa, bitfile_t *input)
-/* 
+/*
  *  Read transitions of WFA given from the stream 'input'.
  *
  *  Return value:
  *	number of edges
  *
  *  Side effects:
- *	'wfa->into' is filled with decoded values 
+ *	'wfa->into' is filled with decoded values
  */
 {
    unsigned total;			/* total number of edges in the WFA */
@@ -73,14 +73,14 @@ read_matrices (wfa_t *wfa, bitfile_t *input)
    total += delta_decoding (wfa, root_state, input);
    if (wfa->wfainfo->color)
       total += chroma_decoding (wfa, input);
-       
+
    return total;
 }
 
 /*****************************************************************************
 
 				private code
-  
+
 *****************************************************************************/
 
 static unsigned
@@ -94,7 +94,7 @@ delta_decoding (wfa_t *wfa, unsigned last_domain, bitfile_t *input)
  *	number of non-zero matrix elements (WFA edges)
  *
  *  Side effects:
- *	'wfa->into' is filled with decoded values 
+ *	'wfa->into' is filled with decoded values
  */
 {
    range_sort_t	 rs;			/* ranges are sorted as in the coder */
@@ -128,26 +128,26 @@ delta_decoding (wfa_t *wfa, unsigned last_domain, bitfile_t *input)
       arith_t  *decoder;
       model_t  *elements;
       unsigned 	max_edges = read_rice_code (3, input);
-      
+
       /*
        *  Get the probability array of the number of edges distribution
        *  and allocate the corresponding model.
        */
       {
 	 unsigned edge;
-	 
+
 	 for (edge = 0; edge <= max_edges; edge++)
 	    count [edge] = read_rice_code ((int) log2 (last_domain) - 2,
 					   input);
 	 elements = alloc_model (max_edges + 1, 0, 0, count);
       }
-      
+
       /*
        *  Get number of elements per matrix row
        */
       {
 	 unsigned row;
-      
+
 	 n_edges = Calloc (wfa->states, sizeof (unsigned));
 	 decoder = alloc_decoder (input);
 	 for (row = range = 0; range < rs.range_no; range++)
@@ -155,17 +155,17 @@ delta_decoding (wfa_t *wfa, unsigned last_domain, bitfile_t *input)
 	    {
 	       state = rs.range_state [range];
 	       label = rs.range_label [range];
-	       
+
 	       n_edges [row++]
 		  = decode_symbol (decoder, elements)
 		  - (isedge (wfa->into [state][label][0]) ? 1 : 0);
 	    }
-	 
+
 	 free_decoder (decoder);
 	 free_model (elements);
       }
    }
-   
+
    /*
     *  Get matrix elements
     */
@@ -177,18 +177,18 @@ delta_decoding (wfa_t *wfa, unsigned last_domain, bitfile_t *input)
       u_word_t *mapping_coder2     = Calloc (wfa->states, sizeof (word_t));
       bool_t	use_normal_domains = get_bit (input);
       bool_t	use_delta_domains  = get_bit (input);
-	  
+
       /*
        *  Generate array of states which are admitted domains.
        *  When coding intra frames 'mapping1' == 'mapping2' otherwise
-       *  'mapping1' is a list of 'normal' domains which are admitted for 
+       *  'mapping1' is a list of 'normal' domains which are admitted for
        *             coding intra blocks
        *  'mapping2' is a list of 'delta' domains which are admitted for
-       *             coding the motion compensated prediction error 
+       *             coding the motion compensated prediction error
        */
       {
 	 unsigned n1, n2, state;
-	    
+
 	 for (n1 = n2 = state = 0; state < wfa->states; state++)
 	 {
 	    mapping1 [n1] = state;
@@ -197,7 +197,7 @@ delta_decoding (wfa_t *wfa, unsigned last_domain, bitfile_t *input)
 		&& (state < wfa->basis_states
 		    || use_delta_domains || !wfa->delta_state [state]))
 	       n1++;
-	    
+
 	    mapping2 [n2] = state;
 	    mapping_coder2 [state] = n2;
 	    if (usedomain (state, wfa)
@@ -206,7 +206,7 @@ delta_decoding (wfa_t *wfa, unsigned last_domain, bitfile_t *input)
 	       n2++;
 	 }
       }
-	 
+
       for (row = 0, range = 0; range < rs.range_no; range++)
 	 if (!rs.range_subdivided [range])
 	 {
@@ -249,7 +249,7 @@ delta_decoding (wfa_t *wfa, unsigned last_domain, bitfile_t *input)
       Free (mapping2);
       Free (mapping_coder2);
    }
-      
+
    Free (n_edges);
    Free (rs.range_state);
    Free (rs.range_label);
@@ -265,12 +265,12 @@ column_0_decoding (wfa_t *wfa, unsigned last_row, bitfile_t *input)
  *  Read column 0 of the transition matrices of the 'wfa' which are coded
  *  with quasi arithmetic coding from stream 'input'.
  *  All rows from 'wfa->basis_states' up to 'last_row' are decoded.
- * 
+ *
  *  Return value:
  *	number of non-zero matrix elements (WFA edges)
  *
  *  Side effects:
- *	'wfa->into' is filled with decoded values 
+ *	'wfa->into' is filled with decoded values
  */
 {
    unsigned  row;			/* current matrix row */
@@ -294,9 +294,9 @@ column_0_decoding (wfa_t *wfa, unsigned last_row, bitfile_t *input)
       unsigned n;
       unsigned index;			/* probability index */
       unsigned exp;			/* current exponent */
-      
+
       prob = Calloc (1 << (MAX_PROB + 1), sizeof (unsigned));
-   
+
       for (index = 0, n = MIN_PROB; n <= MAX_PROB; n++)
 	 for (exp = 0; exp < 1U << n; exp++, index++)
 	    prob [index] = n;
@@ -304,12 +304,12 @@ column_0_decoding (wfa_t *wfa, unsigned last_row, bitfile_t *input)
 
    first = prob_ptr = new_prob_ptr = prob;
    last  = first + 1020;
-   
+
    is_leaf = wfa->tree [wfa->basis_states]; /* use pointer arithmetics ... */
 
    high = HIGH;				/* 1.0 */
    low  = LOW;				/* 0.0 */
-   code = get_bits (input, 16);		
+   code = get_bits (input, 16);
 
    /*
     *  Decode column 0 with a quasi arithmetic coder (QAC).
@@ -325,7 +325,7 @@ column_0_decoding (wfa_t *wfa, unsigned last_row, bitfile_t *input)
    for (row = wfa->basis_states; row <= last_row; row++)
    {
       unsigned count;			/* value in the current interval */
-      
+
       /*
        *  Read label 0 element
        */
@@ -397,7 +397,7 @@ column_0_decoding (wfa_t *wfa, unsigned last_row, bitfile_t *input)
    INPUT_BYTE_ALIGN (input);
 
    Free (prob);
-   
+
    return total;
 }
 
@@ -411,7 +411,7 @@ chroma_decoding (wfa_t *wfa, bitfile_t *input)
  *	number of non-zero matrix elements (WFA edges)
  *
  *  Side effects:
- *	'wfa->into' is filled with decoded values 
+ *	'wfa->into' is filled with decoded values
  */
 {
    unsigned  domain;			/* current domain, counter */
@@ -425,7 +425,7 @@ chroma_decoding (wfa_t *wfa, bitfile_t *input)
    u_word_t  low;			/* End of the current code range */
    u_word_t  code;			/* The present input code value */
    word_t   *y_domains;			/* domain images corresponding to Y */
-   int	     save_index;		/* YES: store current probabilty */
+   int	     save_index;		/* YES: store current probability */
 
    /*
     *  Compute the asymmetric probability array
@@ -436,9 +436,9 @@ chroma_decoding (wfa_t *wfa, bitfile_t *input)
       unsigned n;
       unsigned index;			/* probability index */
       unsigned exp;			/* current exponent */
-      
+
       prob = Calloc (1 << (MAX_PROB + 1), sizeof (unsigned));
-   
+
       for (index = 0, n = MIN_PROB; n <= MAX_PROB; n++)
 	 for (exp = 0; exp < 1U << n; exp++, index++)
 	    prob [index] = n;
@@ -454,7 +454,7 @@ chroma_decoding (wfa_t *wfa, bitfile_t *input)
    y_domains = compute_hits (wfa->basis_states,
 			     wfa->tree [wfa->tree [wfa->root_state][0]][0],
 			     wfa->wfainfo->chroma_max_states, wfa);
-   
+
    first = prob_ptr = new_prob_ptr = prob;
    last  = first + 1020;
 
@@ -554,7 +554,7 @@ chroma_decoding (wfa_t *wfa, bitfile_t *input)
 		    wfa->tree [wfa->tree [wfa->root_state][0]][0], wfa);
    compute_y_state (wfa->tree [wfa->tree [wfa->root_state][1]][0],
 		    wfa->tree [wfa->tree [wfa->root_state][0]][0], wfa);
-   
+
    first = prob_ptr = new_prob_ptr = prob;
 
    /*
@@ -566,7 +566,7 @@ chroma_decoding (wfa_t *wfa, bitfile_t *input)
     */
    {
       unsigned 	row;
-      
+
       for (row = wfa->tree [wfa->tree [wfa->root_state][0]][0] + 1;
 	   row < wfa->states; row++)
       {
@@ -629,7 +629,7 @@ compute_y_state (int state, int y_state, wfa_t *wfa)
  */
 {
    unsigned label;
-   
+
    for (label = 0; label < MAXLABELS; label++)
       if (isrange (y_state))
 	 wfa->y_state [state][label] = RANGE;
@@ -640,5 +640,7 @@ compute_y_state (int state, int y_state, wfa_t *wfa)
 	    compute_y_state (wfa->tree [state][label],
 			     wfa->y_state [state][label], wfa);
       }
-      
+
 }
+
+
diff --git a/converter/other/fiasco/input/mc.c b/converter/other/fiasco/input/mc.c
index 2d4a073d..afc0c1c3 100644
--- a/converter/other/fiasco/input/mc.c
+++ b/converter/other/fiasco/input/mc.c
@@ -1,9 +1,9 @@
 /*
- *  mc.c:	Input of motion compensation	
+ *  mc.c:	Input of motion compensation
  *
  *  written by: Michael Unger
  *		Ullrich Hafner
- *		
+ *
  *  This file is part of FIASCO (Fractal Image And Sequence COdec)
  *  Copyright (C) 1994-2000 Ullrich Hafner
  */
@@ -32,10 +32,10 @@
 /*****************************************************************************
 
 			     local variables
-  
+
 *****************************************************************************/
 
-typedef struct huff_node 
+typedef struct huff_node
 {
    int		     code_index;	/* leaf if index >= 0 */
    struct huff_node *left;		/* follow if '0' bit read */
@@ -46,7 +46,7 @@ typedef struct huff_node
 /*****************************************************************************
 
 				prototypes
-  
+
 *****************************************************************************/
 
 static void
@@ -64,7 +64,7 @@ create_huff_node (huff_node_t *hn, int bits_processed);
 /*****************************************************************************
 
 				public code
-  
+
 *****************************************************************************/
 
 void
@@ -90,7 +90,7 @@ read_mc (frame_type_e frame_type, wfa_t *wfa, bitfile_t *input)
 /*****************************************************************************
 
 				private code
-  
+
 *****************************************************************************/
 
 static void
@@ -114,8 +114,8 @@ decode_mc_tree (frame_type_e frame_type, unsigned max_state,
 
    /*
     *  Traverse tree in breadth first order (starting at level
-    *  'wfa->wfainfo->p_max_level'). Use a queue to store the childs
-    *  of each node ('last' is the next free queue element).  
+    *  'wfa->wfainfo->p_max_level'). Use a queue to store the children
+    *  of each node ('last' is the next free queue element).
     */
    queue = Calloc (MAXSTATES, sizeof (unsigned));
    for (last = 0, state = wfa->basis_states; state < max_state; state++)
@@ -126,7 +126,7 @@ decode_mc_tree (frame_type_e frame_type, unsigned max_state,
    {
       unsigned label;			/* current label */
       unsigned current;			/* current node to process */
-      
+
       for (current = 0; current < last; current++)
 	 for (label = 0; label < MAXLABELS; label++)
 	 {
@@ -147,7 +147,7 @@ decode_mc_tree (frame_type_e frame_type, unsigned max_state,
 	    if (wfa->mv_tree [state][label].type == NONE &&
 		!isrange (wfa->tree [state][label]) &&
 		wfa->level_of_state [state] - 1 >=
-		(int) wfa->wfainfo->p_min_level) 
+		(int) wfa->wfainfo->p_min_level)
 	       queue [last++] = wfa->tree [state][label]; /* append child  */
 	 }
    }
@@ -155,7 +155,7 @@ decode_mc_tree (frame_type_e frame_type, unsigned max_state,
    {
       unsigned label;			/* current label */
       unsigned current;			/* current node to process */
-      
+
       for (current = 0; current < last; current++)
 	 for (label = 0; label < MAXLABELS; label++)
 	 {
@@ -172,18 +172,18 @@ decode_mc_tree (frame_type_e frame_type, unsigned max_state,
 	       wfa->mv_tree[state][label].type = NONE;
 	    else if (get_bit (input))	/* 01  */
 	       wfa->mv_tree[state][label].type = INTERPOLATED;
-	    else if (get_bit (input))	/* 001 */ 
+	    else if (get_bit (input))	/* 001 */
 	       wfa->mv_tree[state][label].type = BACKWARD;
-	    else			/* 000 */ 
+	    else			/* 000 */
 	       wfa->mv_tree[state][label].type = FORWARD;
 	    if (wfa->mv_tree[state][label].type == NONE &&
 		!isrange (wfa->tree[state][label]) &&
 		wfa->level_of_state[state] - 1
-		>= (int) wfa->wfainfo->p_min_level) 
+		>= (int) wfa->wfainfo->p_min_level)
 	       queue[last++] = wfa->tree[state][label]; /* append child  */
 	 }
    }
-   
+
    INPUT_BYTE_ALIGN (input);
    Free (queue);
 }
@@ -205,10 +205,10 @@ decode_mc_coords (unsigned max_state, wfa_t *wfa, bitfile_t *input)
    unsigned	       state;		/* current state */
    mv_t		      *mv;		/* current motion vector */
    static huff_node_t *huff_mv_root = NULL; /* root of huffman tree */
- 
+
    if (huff_mv_root == NULL)
       huff_mv_root = create_huff_tree ();
-   
+
    for (state = wfa->basis_states; state < max_state; state++)
       for (label = 0; label < MAXLABELS; label++)
       {
@@ -220,12 +220,12 @@ decode_mc_coords (unsigned max_state, wfa_t *wfa, bitfile_t *input)
 	    case FORWARD:
 	       mv->fx = get_mv (1, huff_mv_root, input);
 	       mv->fy = get_mv (1, huff_mv_root, input);
-	       break;	    
-	    case BACKWARD:	    
+	       break;
+	    case BACKWARD:
 	       mv->bx = get_mv (1, huff_mv_root, input);
 	       mv->by = get_mv (1, huff_mv_root, input);
-	       break;	    
-	    case INTERPOLATED:   
+	       break;
+	    case INTERPOLATED:
 	       mv->fx = get_mv (1, huff_mv_root, input);
 	       mv->fy = get_mv (1, huff_mv_root, input);
 	       mv->bx = get_mv (1, huff_mv_root, input);
@@ -236,11 +236,11 @@ decode_mc_coords (unsigned max_state, wfa_t *wfa, bitfile_t *input)
 
    INPUT_BYTE_ALIGN (input);
 }
- 
+
 static int
 get_mv (int f_code, huff_node_t *hn, bitfile_t *input)
-/* 
- *  Decode next motion vector component in bitstream 
+/*
+ *  Decode next motion vector component in bitstream
  *  by traversing the huffman tree.
  */
 {
@@ -256,7 +256,7 @@ get_mv (int f_code, huff_node_t *hn, bitfile_t *input)
 	 hn = hn->left;
    }
    vlc_code = hn->code_index - 16;
-   if (vlc_code == 0 || f_code == 1) 
+   if (vlc_code == 0 || f_code == 1)
       return vlc_code;
 
    vlc_code_magnitude = abs (vlc_code) - 1;
@@ -265,7 +265,7 @@ get_mv (int f_code, huff_node_t *hn, bitfile_t *input)
    else
       residual = get_bits (input, f_code - 1);
    diffvec = (vlc_code_magnitude << (f_code - 1)) + residual + 1;
-   
+
    return vlc_code > 0 ? diffvec : - diffvec;
 }
 
@@ -277,7 +277,7 @@ create_huff_tree (void)
 {
    unsigned	i;
    huff_node_t *huff_root = Calloc (1, sizeof (huff_node_t));
-   
+
    /*
     *  The nodes' index set contains indices of all codewords that are
     *  still decodable by traversing further down from the node.
@@ -318,7 +318,7 @@ create_huff_node (huff_node_t *hn, int bits_processed)
       if (code_len == bits_processed)	/* generate leaf */
       {
 	 hn->code_index = ind;
-	 Free (hn->left); 
+	 Free (hn->left);
 	 Free (hn->right);
 	 return;
       }
@@ -332,3 +332,6 @@ create_huff_node (huff_node_t *hn, int bits_processed)
    create_huff_node (hn->left, bits_processed + 1);
    create_huff_node (hn->right, bits_processed + 1);
 }
+
+
+
diff --git a/converter/other/fiasco/input/nd.c b/converter/other/fiasco/input/nd.c
index 52d48e61..129a150e 100644
--- a/converter/other/fiasco/input/nd.c
+++ b/converter/other/fiasco/input/nd.c
@@ -1,8 +1,8 @@
 /*
- *  nd.c:		Input of prediction tree	
+ *  nd.c:		Input of prediction tree
  *
  *  Written by:		Ullrich Hafner
- *		
+ *
  *  This file is part of FIASCO (Fractal Image And Sequence COdec)
  *  Copyright (C) 1994-2000 Ullrich Hafner
  */
@@ -31,7 +31,7 @@
 /*****************************************************************************
 
 				prototypes
-  
+
 *****************************************************************************/
 
 static void
@@ -42,7 +42,7 @@ decode_nd_tree (wfa_t *wfa, bitfile_t *input);
 /*****************************************************************************
 
 				public code
-  
+
 *****************************************************************************/
 
 void
@@ -56,7 +56,7 @@ read_nd (wfa_t *wfa, bitfile_t *input)
  */
 {
    unsigned total = decode_nd_tree (wfa, input);
-   
+
    if (total > 0)
       decode_nd_coefficients (total, wfa, input);
 }
@@ -64,7 +64,7 @@ read_nd (wfa_t *wfa, bitfile_t *input)
 /*****************************************************************************
 
 				private code
-  
+
 *****************************************************************************/
 
 static unsigned
@@ -106,7 +106,7 @@ decode_nd_tree (wfa_t *wfa, bitfile_t *input)
    {
       unsigned label;
 
-      if (wfa->level_of_state [next] > wfa->wfainfo->p_max_level + 1) 
+      if (wfa->level_of_state [next] > wfa->wfainfo->p_max_level + 1)
       {
 	 /*
 	  *  Nondetermismn is not allowed at levels larger than
@@ -114,7 +114,7 @@ decode_nd_tree (wfa_t *wfa, bitfile_t *input)
 	  */
 	 for (label = 0; label < MAXLABELS; label++)
 	    if (ischild (state = wfa->tree [next][label]))
-	       queue_append (queue, &state); /* continue with childs */
+	       queue_append (queue, &state); /* continue with children */
       }
       else if (wfa->level_of_state [next] > wfa->wfainfo->p_min_level)
       {
@@ -123,7 +123,7 @@ decode_nd_tree (wfa_t *wfa, bitfile_t *input)
 	    {
 	       unsigned count;		/* Current interval count */
 	       unsigned range;		/* Current interval range */
-	       
+
 	       count = (((code - low) + 1) * sum1 - 1) / ((high - low) + 1);
 	       if (count < sum0)
 	       {
@@ -192,7 +192,7 @@ decode_nd_tree (wfa_t *wfa, bitfile_t *input)
 static void
 decode_nd_coefficients (unsigned total, wfa_t *wfa, bitfile_t *input)
 /*
- *  Read #'total' weights of nondeterministic part of 'wfa'  
+ *  Read #'total' weights of nondeterministic part of 'wfa'
  *  of given 'input' stream.
  *  'frame' gives the current frame number.
  *
@@ -204,24 +204,24 @@ decode_nd_coefficients (unsigned total, wfa_t *wfa, bitfile_t *input)
 {
    unsigned *coefficients;		/* array of factors to encode */
    unsigned *ptr;			/* pointer to current factor */
-   
+
    /*
     *  Decode array of coefficients stored with arithmetic coding
     */
    {
       const int	scaling  = 50;		/* scaling factor of prob. model */
       unsigned  c_symbols = 1 << (wfa->wfainfo->dc_rpf->mantissa_bits + 1);
-      
+
       ptr = coefficients = decode_array (input, NULL, &c_symbols, 1,
 					 total, scaling);
    }
-   
+
    /*
     *  Fill 'wfa->weights' with decoded coefficients
     */
    {
       unsigned state, label;
-      
+
       for (state = wfa->basis_states; state < wfa->states; state++)
 	 for (label = 0; label < MAXLABELS; label++)
 	    if (ischild (wfa->tree [state][label])
@@ -235,3 +235,6 @@ decode_nd_coefficients (unsigned total, wfa_t *wfa, bitfile_t *input)
    }
    Free (coefficients);
 }
+
+
+
diff --git a/converter/other/fiasco/input/read.c b/converter/other/fiasco/input/read.c
index 9f4ac993..c3aa77a8 100644
--- a/converter/other/fiasco/input/read.c
+++ b/converter/other/fiasco/input/read.c
@@ -2,7 +2,7 @@
  *  read.c:		Input of WFA files
  *
  *  Written by:		Ullrich Hafner
- *  
+ *
  *  This file is part of FIASCO (Fractal Image And Sequence COdec)
  *  Copyright (C) 1994-2000 Ullrich Hafner
  */
@@ -47,7 +47,7 @@
 /*****************************************************************************
 
 				prototypes
-  
+
 *****************************************************************************/
 
 static void
@@ -57,7 +57,7 @@ read_tiling (tiling_t *tiling, unsigned image_width, unsigned image_height,
 /*****************************************************************************
 
 				public code
-  
+
 *****************************************************************************/
 
 bitfile_t *
@@ -69,14 +69,14 @@ open_wfa (const char *filename, wfa_info_t *wi)
  *	Pointer to input stream (fileposition: first WFA frame)
  *
  *  Side effects:
- *	The values of the header of 'filename' are copied to 'wfainfo'. 
+ *	The values of the header of 'filename' are copied to 'wfainfo'.
  *
  */
 {
    bitfile_t *input;			/* pointer to WFA bitfile */
-   
+
    assert (filename && wi);
-   
+
    wi->wfa_name = strdup (filename);
 
    /*
@@ -85,16 +85,16 @@ open_wfa (const char *filename, wfa_info_t *wi)
    {
       unsigned 	n;
       const char     *str;
-      
+
       if (!(input = open_bitfile (filename, "FIASCO_DATA", READ_ACCESS)))
           file_error (filename);
-   
+
       for (str = FIASCO_MAGIC, n = strlen (FIASCO_MAGIC); n; n--)
           if (get_bits (input, 8) != (unsigned) *str++)
               error ("Input file %s is not a valid FIASCO file!", filename);
       get_bits (input, 8);		/* fetch newline */
    }
-   
+
    /*
     *  Read WFA header information
     */
@@ -102,13 +102,13 @@ open_wfa (const char *filename, wfa_info_t *wi)
       char	      basis_name [MAXSTRLEN]; /* temp. buffer */
       const unsigned  rice_k = 8; 	/* parameter of Rice Code */
       char     	     *str    = basis_name;
-      
+
       while ((*str++ = get_bits (input, 8)) != 0
 	     && str < basis_name + MAXSTRLEN)
 	 ;
       if (str == basis_name + MAXSTRLEN)
 	 error ("Input file %s is not a valid FIASCO file!", filename);
-      
+
       {
 	 wi->release = read_rice_code (rice_k, input);
 
@@ -121,12 +121,12 @@ open_wfa (const char *filename, wfa_info_t *wi)
       if (wi->release > 1)
       {
 	 header_type_e type;
-	 
+
 	 while ((type = read_rice_code (rice_k, input)) != HEADER_END)
 	 {
 	    char     buffer [MAXSTRLEN];
 	    unsigned n = 0;
-	    
+
 	    switch (type)
 	    {
 	       case HEADER_TITLE:
@@ -157,7 +157,7 @@ open_wfa (const char *filename, wfa_info_t *wi)
       {
 	 unsigned lx = log2 (wi->width - 1) + 1;
 	 unsigned ly = log2 (wi->height - 1) + 1;
-      
+
 	 wi->level = MAX(lx, ly) * 2 - ((ly == lx + 1) ? 1 : 0);
       }
       wi->chroma_max_states = wi->color ? read_rice_code (rice_k, input) : -1;
@@ -176,14 +176,14 @@ open_wfa (const char *filename, wfa_info_t *wi)
 	 mantissa = get_bits (input, 3) + 2;
 	 range    = get_bits (input, 2);
 	 wi->rpf  = alloc_rpf (mantissa, range);
-	 
+
 	 if (get_bit (input))		/* different DC model */
 	 {
 	    mantissa   = get_bits (input, 3) + 2;
 	    range      = get_bits (input, 2);
 	    wi->dc_rpf = alloc_rpf (mantissa, range);
 	 }
-	 else				/* use same model for DC coefficents */
+	 else				/* use same model for DC coefficients */
 	    wi->dc_rpf = alloc_rpf (wi->rpf->mantissa_bits,
 				    wi->rpf->range_e);
 
@@ -196,7 +196,7 @@ open_wfa (const char *filename, wfa_info_t *wi)
 	 else
 	    wi->d_rpf = alloc_rpf (wi->rpf->mantissa_bits,
 				   wi->rpf->range_e);
-	 
+
 	 if (get_bit (input))		/* different DC delta model */
 	 {
 	    mantissa  	 = get_bits (input, 3) + 2;
@@ -216,7 +216,7 @@ open_wfa (const char *filename, wfa_info_t *wi)
 	 wi->B_as_past_ref = get_bit (input) ? YES : NO;
       }
    }
-   
+
    INPUT_BYTE_ALIGN (input);
 
    return input;
@@ -246,10 +246,10 @@ read_basis (const char *filename, wfa_t *wfa)
 	 Free (wfa->wfainfo->basis_name);
       wfa->wfainfo->basis_name = strdup (filename);
    }
-   
+
    if (get_linked_basis (filename, wfa))
-      return;				/* basis is linked with excecutable */
-   
+      return;				/* basis is linked with executable */
+
    /*
     *  Check whether 'wfa_name' is a regular ASCII WFA initial basis file
     */
@@ -258,19 +258,19 @@ read_basis (const char *filename, wfa_t *wfa)
 
       if (!(input = open_file (filename, "FIASCO_DATA", READ_ACCESS)))
 	 file_error(filename);
-      
+
       if (fscanf (input, MAXSTRLEN_SCANF, magic) != 1)
 	 error ("Format error: ASCII FIASCO initial basis file %s", filename);
-      else if (strneq (FIASCO_BASIS_MAGIC, magic))
+      else if (!streq (FIASCO_BASIS_MAGIC, magic))
 	 error ("Input file %s is not an ASCII FIASCO initial basis!",
 		filename);
    }
-   
+
    /*
     *  WFA ASCII format:
     *
     *  Note: State 0 is assumed to be the constant function f(x, y) = 128.
-    *        Don't define any transitions of state 0 in an initial basis. 
+    *        Don't define any transitions of state 0 in an initial basis.
     *
     *  Header:
     *   type		|description
@@ -307,14 +307,14 @@ read_basis (const char *filename, wfa_t *wfa)
       /*
        *  State 0 is assumed to be the constant function f(x, y) = 128.
        */
-      wfa->domain_type [0]        = USE_DOMAIN_MASK; 
+      wfa->domain_type [0]        = USE_DOMAIN_MASK;
       wfa->final_distribution [0] = 128;
       wfa->states 		  = wfa->basis_states;
       wfa->basis_states++;
 
       append_edge (0, 0, 1.0, 0, wfa);
       append_edge (0, 0, 1.0, 1, wfa);
-   
+
       for (state = 1; state < wfa->basis_states; state++)
 	 wfa->domain_type [state]
 	    = read_int (input) ? USE_DOMAIN_MASK : AUXILIARY_MASK;
@@ -343,7 +343,7 @@ read_basis (const char *filename, wfa_t *wfa)
 	 }
       }
    }
-   
+
    fclose (input);
 }
 
@@ -353,7 +353,7 @@ read_next_wfa (wfa_t *wfa, bitfile_t *input)
  *  Read next WFA frame of the WFA stream 'input'.
  *  WFA header information has to be already present in the 'wfainfo' struct.
  *  (i.e. open_wfa must be called first!)
- *  
+ *
  *  No return value.
  *
  *  Side effects:
@@ -364,9 +364,9 @@ read_next_wfa (wfa_t *wfa, bitfile_t *input)
 {
    tiling_t tiling;			/* tiling information */
    unsigned frame_number;		/* current frame number */
-   
+
    assert (wfa && input);
-   
+
    /*
     *  Frame header information
     */
@@ -382,16 +382,16 @@ read_next_wfa (wfa_t *wfa, bitfile_t *input)
    {
       INPUT_BYTE_ALIGN (input);
    }
-   
+
    /*
-    *  Read image tiling info 
+    *  Read image tiling info
     */
    if (get_bit (input))			/* tiling performed ? */
       read_tiling (&tiling, wfa->wfainfo->width, wfa->wfainfo->height,
 		   wfa->wfainfo->level, input);
    else
       tiling.exponent = 0;
-   
+
    INPUT_BYTE_ALIGN (input);
 
    read_tree (wfa, &tiling, input);
@@ -402,7 +402,7 @@ read_next_wfa (wfa_t *wfa, bitfile_t *input)
     */
    {
       unsigned state;
-   
+
       for (state = wfa->basis_states; state < wfa->states; state++)
 	 if ((!wfa->wfainfo->color
 	      || (int) state <= wfa->tree [wfa->tree [wfa->root_state][0]][0])
@@ -420,7 +420,7 @@ read_next_wfa (wfa_t *wfa, bitfile_t *input)
 	 else
 	    wfa->domain_type [state] = 0;
    }
-   
+
    if (tiling.exponent)
       Free (tiling.vorder);
 
@@ -431,12 +431,12 @@ read_next_wfa (wfa_t *wfa, bitfile_t *input)
       read_mc (wfa->frame_type, wfa, input);
 
    locate_delta_images (wfa);
-   
+
    /*
     *  Read linear combinations (coefficients and indices)
     */
    {
-      unsigned edges = read_matrices (wfa, input); 
+      unsigned edges = read_matrices (wfa, input);
 
       if (edges)
 	 read_weights (edges, wfa, input);
@@ -447,7 +447,7 @@ read_next_wfa (wfa_t *wfa, bitfile_t *input)
     */
    {
       unsigned state;
-   
+
       for (state = wfa->basis_states; state <= wfa->states; state++)
 	 wfa->final_distribution[state]
 	    = compute_final_distribution (state, wfa);
@@ -459,7 +459,7 @@ read_next_wfa (wfa_t *wfa, bitfile_t *input)
 /*****************************************************************************
 
 				private code
-  
+
 *****************************************************************************/
 
 static void
@@ -468,14 +468,14 @@ read_tiling (tiling_t *tiling, unsigned image_width, unsigned image_height,
 /*
  *  Read image tiling information from the given file 'input'
  *  and store parameters in struct 'tiling'.
- *  
+ *
  *  No return value.
  */
 {
    const unsigned rice_k = 8;		/* parameter of Rice Code */
-   
+
    tiling->exponent = read_rice_code (rice_k, input);
-   
+
    if (get_bit (input))			/* variance order */
    {
       unsigned tile;			/* current image tile */
@@ -487,7 +487,7 @@ read_tiling (tiling_t *tiling, unsigned image_width, unsigned image_height,
       {
 	 locate_subimage (image_level, image_level - tiling->exponent, tile,
 			  &x0, &y0, &width, &height);
-	 if (x0 < image_width && y0 < image_height) 
+	 if (x0 < image_width && y0 < image_height)
 	    tiling->vorder [tile] = get_bits (input, tiling->exponent);
 	 else
 	    tiling->vorder [tile] = -1;
@@ -500,3 +500,6 @@ read_tiling (tiling_t *tiling, unsigned image_width, unsigned image_height,
 		      tiling->exponent, get_bit (input) ? YES : NO);
    }
 }
+
+
+
diff --git a/converter/other/fiasco/input/tree.c b/converter/other/fiasco/input/tree.c
index 0ac2b6ae..74ceeb68 100644
--- a/converter/other/fiasco/input/tree.c
+++ b/converter/other/fiasco/input/tree.c
@@ -2,7 +2,7 @@
  *  tree.c:		Input of bintree partitioning
  *
  *  Written by:		Ullrich Hafner
- *		
+ *
  *  This file is part of FIASCO (Fractal Image And Sequence COdec)
  *  Copyright (C) 1994-2000 Ullrich Hafner
  */
@@ -31,7 +31,7 @@
 /*****************************************************************************
 
 				prototypes
-  
+
 *****************************************************************************/
 
 static unsigned
@@ -39,14 +39,14 @@ restore_depth_first_order (unsigned src_state, unsigned level, unsigned x,
 			   unsigned y, unsigned *dst_state,
 			   word_t (*bfo_tree)[MAXLABELS],
 			   wfa_t *wfa, tiling_t *tiling);
-static void 
+static void
 decode_tree (bitfile_t *input, byte_t *data, unsigned n_data, unsigned scaling,
 	     u_word_t sum0, u_word_t sum1);
 
 /*****************************************************************************
 
 				public code
-  
+
 *****************************************************************************/
 
 void
@@ -64,7 +64,7 @@ read_tree (wfa_t *wfa, tiling_t *tiling, bitfile_t *input)
 {
    byte_t *bitstring;			/* the encoded data */
    word_t (*bfo_tree)[MAXLABELS];	/* node numbers in BFO */
-      
+
    /*
     *  Read WFA tree stored in breadth first order
     */
@@ -75,7 +75,7 @@ read_tree (wfa_t *wfa, tiling_t *tiling, bitfile_t *input)
       bitstring = Calloc (total, sizeof (byte_t));
       decode_tree (input, bitstring, total, scale, 1, 11);
    }
-   
+
    /*
     *  Generate tree using a breadth first traversal
     */
@@ -84,7 +84,7 @@ read_tree (wfa_t *wfa, tiling_t *tiling, bitfile_t *input)
       unsigned 	state;
       unsigned 	label;
       byte_t   *buffer = bitstring;	/* pointer to decoded data */
-      
+
       bfo_tree = Calloc (wfa->states * MAXLABELS, sizeof (word_t));
       for (state = 0, next = 1; state < next; state++)
 	 for (label = 0; label < MAXLABELS; label++)
@@ -110,7 +110,7 @@ read_tree (wfa_t *wfa, tiling_t *tiling, bitfile_t *input)
 /*****************************************************************************
 
 				private code
-  
+
 *****************************************************************************/
 
 static unsigned
@@ -119,13 +119,13 @@ restore_depth_first_order (unsigned src_state, unsigned level, unsigned x,
 			   word_t (*bfo_tree)[MAXLABELS],
 			   wfa_t *wfa, tiling_t *tiling)
 /*
- *  Map state 'src_state' (breadth first order) 
+ *  Map state 'src_state' (breadth first order)
  *  to state '*dst_state' (depth first order)
  *  Add a tree edge 'state' --> 'child' with label and weight 1.0
  *  if required.
  *  'x', 'y' give the coordinates of the current state in the 'color' image
- *  of size 'image_level'. 'tiling' defines the image partitioning. 
- *  
+ *  of size 'image_level'. 'tiling' defines the image partitioning.
+ *
  *  Return value:
  *	new node number in depth first order
  *
@@ -134,8 +134,8 @@ restore_depth_first_order (unsigned src_state, unsigned level, unsigned x,
  *      are filled with decoded values.
  */
 {
-   unsigned newx [MAXLABELS];		/* x coordinate of childs */
-   unsigned newy [MAXLABELS];		/* y coordinate of childs */
+   unsigned newx [MAXLABELS];		/* x coordinate of children */
+   unsigned newy [MAXLABELS];		/* y coordinate of children */
    unsigned x0, y0;			/* NW corner of image tile */
    unsigned width, height;		/* size of image tile */
 
@@ -145,7 +145,7 @@ restore_depth_first_order (unsigned src_state, unsigned level, unsigned x,
    if (tiling->exponent && level == wfa->wfainfo->level - tiling->exponent)
    {
       unsigned tile;
-      
+
       for (tile = 0; tile < 1U << tiling->exponent; tile++)
       {
 	 locate_subimage (wfa->wfainfo->level, level, tile,
@@ -159,7 +159,7 @@ restore_depth_first_order (unsigned src_state, unsigned level, unsigned x,
       }
    }
    /*
-    *  Coordinates of childs 0 and 1
+    *  Coordinates of children 0 and 1
     */
    if (wfa->wfainfo->color && level == wfa->wfainfo->level + 1)
       newx[0] = newy[0] = newx[1] = newy[1] = 0;
@@ -170,12 +170,12 @@ restore_depth_first_order (unsigned src_state, unsigned level, unsigned x,
       newx[1] = level & 1 ? x : x + width_of_level (level - 1);
       newy[1] = level & 1 ? y + height_of_level (level - 1) : y;
    }
-   
+
    /*
     *  Remap node numbers
     */
    {
-      int      child [MAXLABELS];	/* childs of current node (state) */
+      int      child [MAXLABELS];	/* children of current node (state) */
       int      domain;			/* current domain */
       unsigned label;
 
@@ -196,17 +196,17 @@ restore_depth_first_order (unsigned src_state, unsigned level, unsigned x,
       }
       wfa->level_of_state [*dst_state] = level;
    }
-   
+
    return (*dst_state)++;
-}	
+}
 
 /****************************************************************************
 
                  Binary adaptive arithmetic compression
- 
+
 ****************************************************************************/
 
-static void 
+static void
 decode_tree (bitfile_t *input, byte_t *data, unsigned n_data, unsigned scaling,
 	     u_word_t sum0, u_word_t sum1)
 /*
@@ -235,11 +235,11 @@ decode_tree (bitfile_t *input, byte_t *data, unsigned n_data, unsigned scaling,
    low  = 0;
    high = 0xffff;
 
-   for (n = n_data; n; n--) 
+   for (n = n_data; n; n--)
    {
       unsigned count;			/* Current interval count */
       unsigned range;			/* Current interval range */
-      
+
       count = (((code - low) + 1) * sum1 - 1) / ((high - low) + 1);
       if (count < sum0)
       {
diff --git a/converter/other/fiasco/lib/arith.c b/converter/other/fiasco/lib/arith.c
index 825d4757..e61e753e 100644
--- a/converter/other/fiasco/lib/arith.c
+++ b/converter/other/fiasco/lib/arith.c
@@ -2,7 +2,7 @@
  *  arith.c:		Adaptive arithmetic coding and decoding
  *
  *  Written by:		Ullrich Hafner
- *  
+ *
  *  This file is part of FIASCO (Fractal Image And Sequence COdec)
  *  Copyright (C) 1994-2000 Ullrich Hafner
  */
@@ -27,7 +27,7 @@
 /******************************************************************************
 
 				public code
-  
+
 ******************************************************************************/
 
 arith_t *
@@ -35,7 +35,7 @@ alloc_encoder (bitfile_t *output)
 /*
  *  Arithmetic coder constructor:
  *  Initialize the arithmetic coder.
- *  
+ *
  *  Return value:
  *	A pointer to the new coder structure
  */
@@ -43,7 +43,7 @@ alloc_encoder (bitfile_t *output)
    arith_t *arith = Calloc (1, sizeof (arith_t));
 
    assert (output);
-   
+
    arith->low       = LOW;
    arith->high      = HIGH;
    arith->underflow = 0;
@@ -58,7 +58,7 @@ free_encoder (arith_t *arith)
  *  Arithmetic encoder destructor.
  *  Flush the arithmetic coder. Append all remaining bits to the
  *  output stream. Append zero bits to get the output file byte aligned.
- *  
+ *
  *  No return value.
  */
 {
@@ -66,14 +66,14 @@ free_encoder (arith_t *arith)
    u_word_t   high;			/* end of the current code range    */
    u_word_t   underflow;		/* number of underflow bits pending */
    bitfile_t *output;
-   
+
    assert (arith);
 
    low       = arith->low;
    high      = arith->high;
    underflow = arith->underflow;
    output    = arith->file;
-   
+
    low = high;
 
    RESCALE_OUTPUT_INTERVAL;
@@ -92,7 +92,7 @@ encode_symbol (unsigned symbol, arith_t *arith, model_t *model)
  *
  *  The model is updated after encoding the symbol (if necessary the
  *  symbol counts are rescaled).
- *  
+ *
  *  Return value:
  *	information content of the encoded symbol.
  *
@@ -110,7 +110,7 @@ encode_symbol (unsigned symbol, arith_t *arith, model_t *model)
    u_word_t   high;			/* end of the current code range    */
    u_word_t   underflow;		/* number of underflow bits pending */
    bitfile_t *output;			/* output file */
-   
+
    assert (model && arith);
 
    /*
@@ -122,7 +122,7 @@ encode_symbol (unsigned symbol, arith_t *arith, model_t *model)
    output    = arith->file;
 
    assert (high > low);
-   
+
    if (model->order > 0)		/* order-'n' model*/
    {
       unsigned power;			/* multiplicator */
@@ -134,10 +134,10 @@ encode_symbol (unsigned symbol, arith_t *arith, model_t *model)
        */
       power = 1;			/* multiplicator */
       index = 0;			/* address of prob. model */
-	 
-      for (i = 0; i < model->order; i++) /* genarate a M-nary number */
+
+      for (i = 0; i < model->order; i++) /* generate a M-nary number */
       {
-	 index += model->context [i] * power;	
+	 index += model->context [i] * power;
 	 power *= model->symbols;
       }
 
@@ -160,9 +160,9 @@ encode_symbol (unsigned symbol, arith_t *arith, model_t *model)
    range = (high - low) + 1;
    high  = low + (u_word_t) ((range * high_count) / scale - 1);
    low   = low + (u_word_t) ((range * low_count) / scale);
-   
+
    RESCALE_OUTPUT_INTERVAL;
-   
+
    if (model->scale > 0)		/* adaptive model */
    {
       unsigned i;
@@ -189,7 +189,7 @@ encode_symbol (unsigned symbol, arith_t *arith, model_t *model)
    arith->low  	    = low;
    arith->high 	    = high;
    arith->underflow = underflow;
-   
+
    return - log2 ((high_count - low_count) / (real_t) scale);
 }
 
@@ -214,21 +214,21 @@ encode_array (bitfile_t *output, const unsigned *data, const unsigned *context,
 
    assert (output && c_symbols && data);
    assert (n_context == 1 || context);
-   
+
    /*
     *  Allocate probability models, start with uniform distribution
     */
    totals = Calloc (n_context, sizeof (u_word_t *));
    {
       unsigned c;
-      
+
       for (c = 0; c < n_context; c++)
       {
 	 unsigned i;
-      
+
 	 totals [c]    = Calloc (c_symbols [c] + 1, sizeof (u_word_t));
 	 totals [c][0] = 0;
-      
+
 	 for (i = 0; i < c_symbols [c]; i++)
 	    totals [c][i + 1] = totals [c][i] + 1;
       }
@@ -242,7 +242,7 @@ encode_array (bitfile_t *output, const unsigned *data, const unsigned *context,
       u_word_t high 	 = 0xffff;	/* End of the current code range */
       u_word_t underflow = 0;		/* Number of underflow bits pending */
       unsigned n;
-      
+
       for (n = 0; n < n_data; n++)
       {
 	 u_word_t low_count;		/* lower bound of 'symbol' interval */
@@ -253,8 +253,8 @@ encode_array (bitfile_t *output, const unsigned *data, const unsigned *context,
 	 int	  c;			/* context of current data symbol */
 
 	 d = data [n];
-	 c = n_context > 1 ? context [n] : 0; 
-      
+	 c = n_context > 1 ? context [n] : 0;
+
 	 scale	    = totals [c][c_symbols [c]];
 	 low_count  = totals [c][d];
 	 high_count = totals [c][d + 1];
@@ -266,7 +266,7 @@ encode_array (bitfile_t *output, const unsigned *data, const unsigned *context,
 	 high  = low + (u_word_t) ((range * high_count) / scale - 1);
 	 low   = low + (u_word_t) ((range * low_count) / scale);
 	 RESCALE_OUTPUT_INTERVAL;
-      
+
 	 /*
 	  *  Update probability models
 	  */
@@ -275,7 +275,7 @@ encode_array (bitfile_t *output, const unsigned *data, const unsigned *context,
 
 	    for (i = d + 1; i < c_symbols [c] + 1; i++)
 	       totals [c][i]++;
-	 
+
 	    if (totals [c][c_symbols [c]] > scaling) /* scaling */
 	       for (i = 1; i < c_symbols [c] + 1; i++)
 	       {
@@ -292,7 +292,7 @@ encode_array (bitfile_t *output, const unsigned *data, const unsigned *context,
       RESCALE_OUTPUT_INTERVAL;
       OUTPUT_BYTE_ALIGN (output);
    }
-   
+
    /*
     *  Cleanup ...
     */
@@ -310,16 +310,16 @@ alloc_decoder (bitfile_t *input)
  *  Arithmetic decoder constructor:
  *  Initialize the arithmetic decoder with the first
  *  16 input bits from the stream 'input'.
- *  
+ *
  *  Return value:
  *	A pointer to the new decoder structure
  */
 
 {
    arith_t *arith = Calloc (1, sizeof (arith_t));
-   
+
    assert (input);
-   
+
    arith->low  = LOW;
    arith->high = HIGH;
    arith->code = get_bits (input, 16);
@@ -333,8 +333,8 @@ free_decoder (arith_t *arith)
 /*
  *  Arithmetic decoder destructor:
  *  Flush the arithmetic decoder, i.e., read bits to get the input
- *  file byte aligned. 
- *  
+ *  file byte aligned.
+ *
  *  No return value.
  *
  *  Side effects:
@@ -354,8 +354,8 @@ decode_symbol (arith_t *arith, model_t *model)
  *  Decode the next symbol - the state of the arithmetic decoder
  *  is given in 'arith'. Read refinement bits from the stream 'input'
  *  and use the given probability 'model'. Update the probability model after
- *  deconding the symbol (if necessary also rescale the symbol counts).
- *  
+ *  decoding the symbol (if necessary also rescale the symbol counts).
+ *
  *  Return value:
  *	decoded symbol
  *
@@ -375,7 +375,7 @@ decode_symbol (arith_t *arith, model_t *model)
    bitfile_t *input;			/* input file */
 
    assert (arith && model);
-   
+
    /*
     * Get interval values
     */
@@ -385,22 +385,22 @@ decode_symbol (arith_t *arith, model_t *model)
    input = arith->file;
 
    assert (high > low);
-   
+
    if (model->order > 0)		/* order-'n' model */
    {
       unsigned power;			/* multiplicator */
       unsigned i;
-      
+
       /*
        *  Compute index of the probability model to use.
        *  See init_model() for more details.
        */
       power = 1;			/* multiplicator */
       index = 0;			/* address of prob. model */
-	 
-      for (i = 0; i < model->order; i++) /* genarate a m-nary number */
+
+      for (i = 0; i < model->order; i++) /* generate a m-nary number */
       {
-	 index += model->context[i] * power;	
+	 index += model->context[i] * power;
 	 power *= model->symbols;
       }
 
@@ -420,7 +420,7 @@ decode_symbol (arith_t *arith, model_t *model)
    if (model->order > 0)		/* order-'n' model */
    {
       unsigned i;
-      
+
       for (i = 0; i < model->order - 1; i++)
 	 model->context [i] = model->context [i + 1];
       model->context [i] = symbol;
@@ -432,15 +432,15 @@ decode_symbol (arith_t *arith, model_t *model)
    {
       u_word_t low_count;		/* lower bound of 'symbol' interval */
       u_word_t high_count;		/* upper bound of 'symbol' interval */
-      
+
       low_count  = model->totals [index + symbol];
       high_count = model->totals [index + symbol + 1];
       high       = low + (u_word_t) ((range * high_count) / scale - 1 );
       low        = low + (u_word_t) ((range * low_count) / scale );
    }
-   
+
    RESCALE_INPUT_INTERVAL;
-   
+
    if (model->scale > 0)		/* adaptive model */
    {
       unsigned i;
@@ -460,7 +460,7 @@ decode_symbol (arith_t *arith, model_t *model)
 	 }
       }
    }
-   
+
    /*
     *  Store interval values
     */
@@ -488,28 +488,28 @@ decode_array (bitfile_t *input, const unsigned *context,
 {
    unsigned  *data;			/* array to store decoded symbols */
    u_word_t **totals;			/* probability model */
-   
+
    if (n_context < 1)
       n_context = 1;			/* always use one context */
    assert (input && c_symbols);
    assert (n_context == 1 || context);
 
    data = Calloc (n_data, sizeof (unsigned));
-   
+
    /*
     *  Allocate probability models, start with uniform distribution
     */
    totals = Calloc (n_context, sizeof (u_word_t *));
    {
       unsigned c;
-      
+
       for (c = 0; c < n_context; c++)
       {
 	 unsigned i;
-      
+
 	 totals [c]    = Calloc (c_symbols [c] + 1, sizeof (u_word_t));
 	 totals [c][0] = 0;
-      
+
 	 for (i = 0; i < c_symbols [c]; i++)
 	    totals [c][i + 1] = totals [c][i] + 1;
       }
@@ -523,8 +523,8 @@ decode_array (bitfile_t *input, const unsigned *context,
       u_word_t low  = 0;		/* Start of the current code range */
       u_word_t high = 0xffff;		/* End of the current code range */
       unsigned n;
-      
-      for (n = 0; n < n_data; n++) 
+
+      for (n = 0; n < n_data; n++)
       {
 	 u_word_t scale;		/* range of all 'm' symbol intervals */
 	 u_word_t low_count;		/* lower bound of 'symbol' interval */
@@ -534,13 +534,13 @@ decode_array (bitfile_t *input, const unsigned *context,
 	 unsigned d;			/* current data symbol */
 	 unsigned c;			/* context of current data symbol */
 
-	 c = n_context > 1 ? context [n] : 0; 
+	 c = n_context > 1 ? context [n] : 0;
 
 	 assert (high > low);
 	 scale = totals [c][c_symbols [c]];
 	 range = (high - low) + 1;
 	 count = (((code - low) + 1 ) * scale - 1) / range;
-      
+
 	 for (d = c_symbols [c]; count < totals [c][d]; d--) /* next symbol */
 	    ;
 	 low_count  = totals [c][d];
@@ -558,7 +558,7 @@ decode_array (bitfile_t *input, const unsigned *context,
 
 	    for (i = d + 1; i < c_symbols [c] + 1; i++)
 	       totals [c][i]++;
-	 
+
 	    if (totals [c][c_symbols [c]] > scaling) /* scaling */
 	       for (i = 1; i < c_symbols [c] + 1; i++)
 	       {
@@ -577,12 +577,12 @@ decode_array (bitfile_t *input, const unsigned *context,
     */
    {
       unsigned c;
-      
+
       for (c = 0; c < n_context; c++)
 	 Free (totals [c]);
       Free (totals);
    }
-   
+
    return data;
 }
 
@@ -600,10 +600,10 @@ alloc_model (unsigned m, unsigned scale, unsigned n, unsigned *totals)
  *
  *  Return value:
  *	a pointer to the new probability model structure.
- *  
+ *
  *  Note: We recommend a small size of the alphabet because no escape codes
  *  are used to encode/decode previously unseen symbols.
- *  
+ *
  */
 {
    model_t  *model;			/* new probability model */
@@ -621,7 +621,7 @@ alloc_model (unsigned m, unsigned scale, unsigned n, unsigned *totals)
    model->order   = n;
    model->context = n > 0 ? Calloc (n, sizeof (unsigned)) : NULL;
    /*
-    *  Allocate memory for the probabilty model.
+    *  Allocate memory for the probability model.
     *  Each of the m^n different contexts requires its own probability model.
     */
    for (num = 1, i = 0; i < model->order; i++)
@@ -644,17 +644,17 @@ alloc_model (unsigned m, unsigned scale, unsigned n, unsigned *totals)
        */
       power = 1;			/* multiplicator */
       index = 0;			/* address of prob. model */
-	 
-      for (i = 0; i < model->order; i++)	/* genarate a m-nary number */
+
+      for (i = 0; i < model->order; i++)	/* generate a m-nary number */
       {
-	 index += model->context[i] * power;	
+	 index += model->context[i] * power;
 	 power *= model->symbols;
       }
 
       index *= model->symbols + 1;	/* size of each model is m + 1 */
 
       model->totals [index + 0] = 0;	/* always zero */
-	 
+
       for (i = 1; i <= model->symbols; i++) /* prob of each symbol is 1/m or
 					       as given in totals */
 	 model->totals[index + i] = model->totals [index + i - 1]
@@ -667,14 +667,14 @@ alloc_model (unsigned m, unsigned scale, unsigned n, unsigned *totals)
 	 {
 	    dec = NO;
 	    model->context[i]++;
-	    if (model->context[i] >= model->symbols) 
+	    if (model->context[i] >= model->symbols)
 	    {
 	       /* change previous context */
 	       model->context[i] = 0;
 	       if (i > 0)		/* there's still a context remaining */
 		  dec = YES;
 	       else
-		  cont = NO;		/* all context models initilized */
+		  cont = NO;		/* all context models initialized */
 	    }
 	 }
    }
diff --git a/converter/other/fiasco/lib/bit-io.c b/converter/other/fiasco/lib/bit-io.c
index f69343e6..04716f05 100644
--- a/converter/other/fiasco/lib/bit-io.c
+++ b/converter/other/fiasco/lib/bit-io.c
@@ -1,12 +1,12 @@
 /*
- *  bit-io.c:       Buffered and bit oriented file I/O 
+ *  bit-io.c:       Buffered and bit oriented file I/O
  *
  *  Written by:     Ullrich Hafner
- *  
+ *
  *  This file is part of FIASCO (Fractal Image And Sequence COdec)
  *  Copyright (C) 1994-2000 Ullrich Hafner
  */
- 
+
 /*
  *  $Date: 2000/06/14 20:49:37 $
  *  $Author: hafner $
@@ -35,7 +35,7 @@
 /*****************************************************************************
 
                  local constants
-  
+
 *****************************************************************************/
 
 static const unsigned BUFFER_SIZE = 16350;
@@ -48,7 +48,7 @@ static const unsigned mask[] = {0x0001, 0x0002, 0x0004, 0x0008,
 /*****************************************************************************
 
                 public code
-  
+
 *****************************************************************************/
 
 FILE *
@@ -57,7 +57,7 @@ open_file (const char *filename, const char *env_var, openmode_e mode)
  *  Try to open file 'filename' with mode 'mode' (READ_ACCESS, WRITE_ACCESS).
  *  Scan the current directory first and then cycle through the
  *  path given in the environment variable 'env_var', if set.
- * 
+ *
  *  Return value:
  *  Pointer to open file on success, else NULL.
  */
@@ -81,42 +81,42 @@ open_file (const char *filename, const char *env_var, openmode_e mode)
     {
         if (mode == READ_ACCESS)
             return stdin;
-        else 
+        else
             return stdout;
     }
-   
+
     /*
      *  Try to open 'readonly' file in the current directory
      */
     if (mode == READ_ACCESS && (fp = fopen (filename, read_mode)))
-        return fp; 
+        return fp;
 
     if (mode == WRITE_ACCESS && strchr (filename, '/')) /* contains path */
         return fopen (filename, write_mode);
-   
+
     /*
      *  Get value of environment variable 'env_var', if set
      *  else use DEFAULT_PATH ("./")
      */
     if (env_var != NULL)
         env_path = getenv (env_var);
-    if (env_path == NULL) 
+    if (env_path == NULL)
         env_path = strdup (DEFAULT_PATH);
     else
         env_path = strdup (env_path);
-   
+
     /*
      *  Try to open file in the directory given by the environment
-     *  variable env_var - individual path components are separated by PATH_SEP 
+     *  variable env_var - individual path components are separated by PATH_SEP
      */
     path = strtok (env_path, PATH_SEP);
-    do 
+    do
     {
-        if (ext_filename) 
+        if (ext_filename)
             Free (ext_filename);
         ext_filename =  Calloc (strlen (path) + strlen (filename) + 2,
                                 sizeof (char));
-        strcpy (ext_filename, path); 
+        strcpy (ext_filename, path);
         if (*(ext_filename + strlen (ext_filename) - 1) != '/')
             strcat (ext_filename, "/");
         strcat (ext_filename, filename);
@@ -125,7 +125,7 @@ open_file (const char *filename, const char *env_var, openmode_e mode)
     while (fp == NULL && (path = strtok (NULL, PATH_SEP)) != NULL);
 
     Free (env_path);
-   
+
     return fp;
 }
 
@@ -143,7 +143,7 @@ open_bitfile (const char *filename, const char *env_var, openmode_e mode)
  */
 {
     bitfile_t *bitfile = Calloc (1, sizeof (bitfile_t));
-   
+
     bitfile->file = open_file (filename, env_var, mode);
 
     if (bitfile->file == NULL)
@@ -164,8 +164,8 @@ open_bitfile (const char *filename, const char *env_var, openmode_e mode)
         bitfile->filename = filename ? strdup (filename) : strdup ("(stdout)");
     }
     else
-        error ("Unknow file access mode '%d'.", mode);
-   
+        error ("Unknown file access mode '%d'.", mode);
+
     bitfile->bits_processed = 0;
     bitfile->buffer         = Calloc (BUFFER_SIZE, sizeof (byte_t));
     bitfile->ptr            = bitfile->buffer;
@@ -187,7 +187,7 @@ get_bit (bitfile_t *bitfile)
  */
 {
     assert (bitfile);
-   
+
     if (!bitfile->bitpos--)      /* use next byte ? */
     {
         bitfile->ptr++;
@@ -226,7 +226,7 @@ get_bits (bitfile_t *bitfile, unsigned bits)
  */
 {
     unsigned value = 0;          /* input value */
-   
+
     while (bits--)
         value = (unsigned) (value << 1) | get_bit (bitfile);
 
@@ -235,7 +235,7 @@ get_bits (bitfile_t *bitfile, unsigned bits)
 
 void
 put_bit (bitfile_t *bitfile, unsigned value)
-/*     
+/*
  *  Put the bit 'value' to the bitfile buffer.
  *  The buffer is written to the file 'bitfile->file' if the number of
  *  buffer bytes exceeds 'BUFFER_SIZE'.
@@ -247,7 +247,7 @@ put_bit (bitfile_t *bitfile, unsigned value)
  */
 {
     assert (bitfile);
-   
+
     if (!bitfile->bitpos--)      /* use next byte ? */
     {
         bitfile->ptr++;
@@ -265,7 +265,7 @@ put_bit (bitfile_t *bitfile, unsigned value)
         }
         bitfile->bitpos = 7;
     }
-   
+
     if (value)
         *bitfile->ptr |= mask [bitfile->bitpos];
 
@@ -274,7 +274,7 @@ put_bit (bitfile_t *bitfile, unsigned value)
 
 void
 put_bits (bitfile_t *bitfile, unsigned value, unsigned bits)
-/*     
+/*
  *  Put #'bits' bits of integer 'value' to the bitfile buffer 'bitfile'.
  *
  *  No return value.
@@ -292,7 +292,7 @@ close_bitfile (bitfile_t *bitfile)
 /*
  *  Bitfile destructor:
  *  Close 'bitfile', if 'bitfile->mode' == WRITE_ACCESS write bit buffer
- *  to disk. 
+ *  to disk.
  *
  *  No return value.
  *
@@ -301,7 +301,7 @@ close_bitfile (bitfile_t *bitfile)
  */
 {
     assert (bitfile);
-   
+
     if (bitfile->mode == WRITE_ACCESS)
     {
         unsigned bytes = fwrite (bitfile->buffer, sizeof (byte_t),
diff --git a/converter/other/fiasco/lib/image.c b/converter/other/fiasco/lib/image.c
index a700fe88..705a56aa 100644
--- a/converter/other/fiasco/lib/image.c
+++ b/converter/other/fiasco/lib/image.c
@@ -2,7 +2,7 @@
  *  image.c:        Input and output of PNM images.
  *
  *  Written by:     Ullrich Hafner
- *      
+ *
  *  This file is part of FIASCO (Fractal Image And Sequence COdec)
  *  Copyright (C) 1994-2000 Ullrich Hafner
  */
@@ -31,7 +31,7 @@
 /*****************************************************************************
 
                 prototypes
-  
+
 *****************************************************************************/
 
 static void
@@ -40,7 +40,7 @@ init_chroma_tables (void);
 /*****************************************************************************
 
                 local variables
-  
+
 *****************************************************************************/
 static int *Cr_r_tab = NULL;
 static int *Cr_g_tab = NULL;
@@ -50,7 +50,7 @@ static int *Cb_b_tab = NULL;
 /*****************************************************************************
 
                 public code
-  
+
 *****************************************************************************/
 
 static fiasco_image_t *
@@ -197,7 +197,7 @@ cast_image (fiasco_image_t *image)
    image_t *this = (image_t *) image->private;
    if (this)
    {
-      if (!streq (this->id, "IFIASCO"))
+      if (!STRSEQ(this->id, "IFIASCO"))
       {
      set_error (_("Parameter `image' doesn't match required type."));
      return NULL;
@@ -240,7 +240,7 @@ alloc_image (unsigned width, unsigned height, bool_t color, format_e format)
    image->color       = color;
    image->format      = format;
    image->reference_count = 1;
-   
+
    STRSCPY(image->id, "IFIASCO");
 
    for (band = first_band (color); band <= last_band (color); band++)
@@ -249,7 +249,7 @@ alloc_image (unsigned width, unsigned height, bool_t color, format_e format)
                     sizeof (word_t));
       else
      image->pixels [band] = Calloc (width * height, sizeof (word_t));
-   
+
    return image;
 }
 
@@ -266,7 +266,7 @@ clone_image (image_t *image)
    image_t *new = alloc_image (image->width, image->height, image->color,
                    image->format);
    color_e band;
-   
+
    for (band = first_band (new->color); band <= last_band (new->color); band++)
       if (new->format == FORMAT_4_2_0 && band != Y)
       {
@@ -314,7 +314,7 @@ free_image (image_t *image)
 }
 
 
-static void 
+static void
 read_image_data(image_t * const image, FILE *input, const bool_t color,
                 const int width, const int height, const xelval maxval,
                 const int format) {
@@ -336,27 +336,27 @@ read_image_data(image_t * const image, FILE *input, const bool_t color,
 
    xelrow = pnm_allocrow(width);
 
-   i = 0; 
+   i = 0;
    for (row = 0; row < height; row++) {
        int col;
        pnm_readpnmrow(input, xelrow, width, maxval, format);
        for (col = 0; col < width; col++) {
            if (color) {
-               image->pixels[Y][i] = 
-                   coeff_lu_r * PPM_GETR(xelrow[col]) 
+               image->pixels[Y][i] =
+                   coeff_lu_r * PPM_GETR(xelrow[col])
                    + coeff_lu_g * PPM_GETG(xelrow[col])
                    + coeff_lu_b * PPM_GETB(xelrow[col]) - 2048;
-               image->pixels[Cb][i] = 
-                   coeff_cb_r * PPM_GETR(xelrow[col]) 
+               image->pixels[Cb][i] =
+                   coeff_cb_r * PPM_GETR(xelrow[col])
                    + coeff_cb_g * PPM_GETG(xelrow[col])
                    + coeff_cb_b * PPM_GETB(xelrow[col]);
-               image->pixels[Cr][i] = 
-                   coeff_cr_r * PPM_GETR(xelrow[col]) 
+               image->pixels[Cr][i] =
+                   coeff_cr_r * PPM_GETR(xelrow[col])
                    + coeff_cr_g * PPM_GETG(xelrow[col])
                    + coeff_cr_b * PPM_GETB(xelrow[col]);
 
                i++;
-           } else 
+           } else
                image->pixels[GRAY][i++] =
                    PNM_GET1(xelrow[col]) * 4095 / maxval - 2048;
        }
@@ -434,7 +434,7 @@ void
 write_image (const char *image_name, const image_t *image)
 /*
  *  Write given 'image' data to the file 'image_name'.
- *  
+ *
  *  No return value.
  */
 {
@@ -446,13 +446,13 @@ write_image (const char *image_name, const image_t *image)
    unsigned *gray_clip;         /* clipping table */
 
    assert (image && image_name);
-   
+
    if (image->format == FORMAT_4_2_0)
    {
       warning ("We cannot write images in 4:2:0 format.");
       return;
    }
-   
+
    if (image_name == NULL)
        output = stdout;
    else if (streq(image_name, "-"))
@@ -466,7 +466,7 @@ write_image (const char *image_name, const image_t *image)
    init_chroma_tables ();
 
    format = image->color ? PPM_TYPE : PGM_TYPE;
-   
+
    pnm_writepnminit(output, image->width, image->height, 255, format, 0);
 
    xelrow = pnm_allocrow(image->width);
@@ -481,18 +481,18 @@ write_image (const char *image_name, const image_t *image)
                cbval = image->pixels[Cb][i] / 16;
                crval = image->pixels[Cr][i] / 16;
 
-               PPM_ASSIGN(xelrow[col], 
+               PPM_ASSIGN(xelrow[col],
                           gray_clip[yval + Cr_r_tab[crval]],
                           gray_clip[yval + Cr_g_tab[crval] + Cb_g_tab [cbval]],
                           gray_clip[yval + Cb_b_tab[cbval]]);
 
            } else
                /* The 16 below should be 4095/255 = 16.0588 */
-               PNM_ASSIGN1(xelrow[col], 
+               PNM_ASSIGN1(xelrow[col],
                            gray_clip[image->pixels[GRAY][i]/16+128]);
            i++;
        }
-       pnm_writepnmrow(output, xelrow, 
+       pnm_writepnmrow(output, xelrow,
                        image->width, 255, format, 0);
    }
    pnm_freerow(xelrow);
@@ -511,7 +511,7 @@ same_image_type (const image_t *img1, const image_t *img2)
  */
 {
    assert (img1 && img2);
-   
+
    return ((img1->width == img2->width)
        && (img1->height == img2->height)
        && (img1->color == img2->color)
@@ -521,7 +521,7 @@ same_image_type (const image_t *img1, const image_t *img2)
 /*****************************************************************************
 
                 private code
-  
+
 *****************************************************************************/
 
 static void
@@ -547,21 +547,21 @@ init_chroma_tables (void)
 
       Cr_r_tab[i] =  1.4022 * crval + 0.5;
       Cr_g_tab[i] = -0.7145 * crval + 0.5;
-      Cb_g_tab[i] = -0.3456 * cbval + 0.5; 
+      Cb_g_tab[i] = -0.3456 * cbval + 0.5;
       Cb_b_tab[i] =  1.7710 * cbval + 0.5;
    }
    for (i = 0; i < 256; i++)
    {
       Cr_r_tab[i] = Cr_r_tab[256];
       Cr_g_tab[i] = Cr_g_tab[256];
-      Cb_g_tab[i] = Cb_g_tab[256]; 
+      Cb_g_tab[i] = Cb_g_tab[256];
       Cb_b_tab[i] = Cb_b_tab[256];
    }
    for (i = 512; i < 768; i++)
    {
       Cr_r_tab[i] = Cr_r_tab[511];
       Cr_g_tab[i] = Cr_g_tab[511];
-      Cb_g_tab[i] = Cb_g_tab[511]; 
+      Cb_g_tab[i] = Cb_g_tab[511];
       Cb_b_tab[i] = Cb_b_tab[511];
    }
 
diff --git a/converter/other/fiasco/lib/image.h b/converter/other/fiasco/lib/image.h
index a87a3c05..c3c5f0df 100644
--- a/converter/other/fiasco/lib/image.h
+++ b/converter/other/fiasco/lib/image.h
@@ -29,7 +29,7 @@ typedef struct image
  *  Image data
  */
 {
-   char      id [7];
+   char      id [8];         /* NUL-terminated "IFIASCO" */
    unsigned  reference_count;
    unsigned  width;			/* Width of the image */
    unsigned  height;			/* Height of the image */
diff --git a/converter/other/fiasco/lib/macros.h b/converter/other/fiasco/lib/macros.h
index 0bc80e7c..2f404a74 100644
--- a/converter/other/fiasco/lib/macros.h
+++ b/converter/other/fiasco/lib/macros.h
@@ -34,8 +34,6 @@
   
 *****************************************************************************/
 
-#define streq(str1, str2)	(strcmp ((str1), (str2)) == 0)
-#define strneq(str1, str2)	(strcmp ((str1), (str2)) != 0)
 #define square(x)		((x) * (x))
 #define first_band(color)	((unsigned) ((color) ? Y  : GRAY))
 #define last_band(color)        ((unsigned) ((color) ? Cr : GRAY))
diff --git a/converter/other/fiasco/output/mc.c b/converter/other/fiasco/output/mc.c
index d048bef5..170a2648 100644
--- a/converter/other/fiasco/output/mc.c
+++ b/converter/other/fiasco/output/mc.c
@@ -1,9 +1,9 @@
 /*
- *  mc.c:		Output of motion compensation	
+ *  mc.c:		Output of motion compensation
  *
  *  Written by:		Michael Unger
  *			Ullrich Hafner
- *		
+ *
  *  This file is part of FIASCO (Fractal Image And Sequence COdec)
  *  Copyright (C) 1994-2000 Ullrich Hafner
  */
@@ -30,7 +30,7 @@
 /*****************************************************************************
 
 			     local variables
-  
+
 *****************************************************************************/
 
 static unsigned p_frame_codes [4][2] =
@@ -39,7 +39,7 @@ static unsigned p_frame_codes [4][2] =
  *  NONE,  FORWARD
  */
 {
-   {1, 1}, {0, 1}, {0, 0}, {0, 0} 
+   {1, 1}, {0, 1}, {0, 0}, {0, 0}
 };
 
 static unsigned b_frame_codes [4][2] =
@@ -48,7 +48,7 @@ static unsigned b_frame_codes [4][2] =
  *  NONE,  FORWARD,  BACKWARD, INTERPOLATED
  */
 {
-   {1, 1}, {000, 3}, {001, 3}, {01, 2} 
+   {1, 1}, {000, 3}, {001, 3}, {01, 2}
 };
 
 enum vlc_e {CODE = 0, BITS = 1};
@@ -56,7 +56,7 @@ enum vlc_e {CODE = 0, BITS = 1};
 /*****************************************************************************
 
 				prototypes
-  
+
 *****************************************************************************/
 
 static void
@@ -68,7 +68,7 @@ encode_mc_coords (unsigned max_state, const wfa_t *wfa, bitfile_t *output);
 /*****************************************************************************
 
 				public code
-  
+
 *****************************************************************************/
 
 void
@@ -85,7 +85,7 @@ write_mc (frame_type_e frame_type, const wfa_t *wfa, bitfile_t *output)
 /*****************************************************************************
 
 				private code
-  
+
 *****************************************************************************/
 
 static void
@@ -108,22 +108,22 @@ encode_mc_tree (unsigned max_state, frame_type_e frame_type, const wfa_t *wfa,
    mc_type_e type;			/* type of motion compensation */
    unsigned	     (*mc_tree_codes)[2]; /* pointer to VLC table */
    unsigned  bits  = bits_processed (output); /* number of bits used */
-   
+
    if (frame_type == P_FRAME)
       mc_tree_codes = p_frame_codes;	/* binary code */
-   else 
+   else
       mc_tree_codes = b_frame_codes;	/* variable length code */
-   
+
    /*
     *  Traverse tree in breadth first order (starting at
-    *  level 'wfa->p_max_level'). Use a queue to store the childs
-    *  of each node ('last' is the next free queue element).  
+    *  level 'wfa->p_max_level'). Use a queue to store the children
+    *  of each node ('last' is the next free queue element).
     */
 
    for (last = 0, state = wfa->basis_states; state < max_state; state++)
       if (wfa->level_of_state [state] - 1 == (int) wfa->wfainfo->p_max_level)
 	 queue [last++] = state;	/* init level = 'mc_max_level' */
-   
+
    for (current = 0; current < last; current++)
       for (label = 0; label < MAXLABELS; label++)
       {
@@ -145,7 +145,7 @@ encode_mc_tree (unsigned max_state, frame_type_e frame_type, const wfa_t *wfa,
 	     wfa->level_of_state [state] - 1 >=
 	     (int) wfa->wfainfo->p_min_level)
 	    queue [last++] = wfa->tree [state][label]; /* append child */
-	 
+
       }
 
    OUTPUT_BYTE_ALIGN (output);
@@ -174,16 +174,16 @@ encode_mc_coords (unsigned max_state, const wfa_t *wfa, bitfile_t *output)
    unsigned  itotal = 0;		/* #interpolated decisions */
    unsigned  bits   = bits_processed (output); /* number of bits used */
    unsigned  sr     = wfa->wfainfo->search_range; /* search range */
-   
+
    for (level = wfa->wfainfo->p_max_level;
 	level >= wfa->wfainfo->p_min_level; level--)
       level_count [level] = 0;
-   
+
    for (state = wfa->basis_states; state < max_state; state++)
       for (label = 0; label < MAXLABELS; label++)
       {
 	 mv_t *mv = &wfa->mv_tree[state][label]; /* motion vector info */
-	 
+
 	 if (mv->type != NONE)
 	 {
 	    level_count [wfa->level_of_state [state] - 1]++;
@@ -229,14 +229,14 @@ encode_mc_coords (unsigned max_state, const wfa_t *wfa, bitfile_t *output)
       }
 
    OUTPUT_BYTE_ALIGN (output);
-   
+
    debug_message ("Motion compensation: %d forward, %d backward, "
 		  "%d interpolated", ftotal, btotal, itotal);
 
    for (level = wfa->wfainfo->p_max_level;
 	level >= wfa->wfainfo->p_min_level; level--)
       debug_message ("Level %d: %d motion vectors", level, level_count[level]);
-   
+
    {
       unsigned  total = ftotal * 2 + btotal * 2 + itotal * 4;
 
diff --git a/converter/other/fiasco/output/nd.c b/converter/other/fiasco/output/nd.c
index 65a85467..b1dd6746 100644
--- a/converter/other/fiasco/output/nd.c
+++ b/converter/other/fiasco/output/nd.c
@@ -1,8 +1,8 @@
 /*
- *  nd.c:		Output of prediction tree	
+ *  nd.c:		Output of prediction tree
  *
  *  Written by:		Ullrich Hafner
- *		
+ *
  *  This file is part of FIASCO (Fractal Image And Sequence COdec)
  *  Copyright (C) 1994-2000 Ullrich Hafner
  */
@@ -32,7 +32,7 @@
 /*****************************************************************************
 
 				prototypes
-  
+
 *****************************************************************************/
 
 static unsigned
@@ -43,7 +43,7 @@ encode_nd_coefficients (unsigned total, const wfa_t *wfa, bitfile_t *output);
 /*****************************************************************************
 
 				public code
-  
+
 *****************************************************************************/
 
 void
@@ -56,7 +56,7 @@ write_nd (const wfa_t *wfa, bitfile_t *output)
  */
 {
    unsigned total = encode_nd_tree (wfa, output);
-   
+
    if (total > 0)
       encode_nd_coefficients (total, wfa, output);
 }
@@ -64,13 +64,13 @@ write_nd (const wfa_t *wfa, bitfile_t *output)
 /*****************************************************************************
 
 				private code
-  
+
 *****************************************************************************/
 
 static unsigned
 encode_nd_tree (const wfa_t *wfa, bitfile_t *output)
 /*
- *  Write prediction tree of 'wfa' to given stream 'output'. 
+ *  Write prediction tree of 'wfa' to given stream 'output'.
  *
  *  No return value.
  */
@@ -85,7 +85,7 @@ encode_nd_tree (const wfa_t *wfa, bitfile_t *output)
    unsigned  bits = bits_processed (output);
 
    used = not_used = 0;
-   
+
    /*
     *  Initialize arithmetic coder
     */
@@ -94,18 +94,18 @@ encode_nd_tree (const wfa_t *wfa, bitfile_t *output)
    underflow = 0;
    sum0      = 1;
    sum1      = 11;
-   
+
    queue = alloc_queue (sizeof (int));
    state = wfa->root_state;
    queue_append (queue, &state);
-   
+
    /*
     *  Traverse the WFA tree in breadth first order (using a queue).
     */
    while (queue_remove (queue, &next))
    {
       unsigned label;
-      
+
       if (wfa->level_of_state [next] > wfa->wfainfo->p_max_level + 1)
       {
 	 /*
@@ -114,7 +114,7 @@ encode_nd_tree (const wfa_t *wfa, bitfile_t *output)
 	  */
 	 for (label = 0; label < MAXLABELS; label++)
 	    if (ischild (state = wfa->tree [next][label]))
-	       queue_append (queue, &state); /* continue with childs */
+	       queue_append (queue, &state); /* continue with children */
       }
       else if (wfa->level_of_state [next] > wfa->wfainfo->p_min_level)
       {
@@ -126,7 +126,7 @@ encode_nd_tree (const wfa_t *wfa, bitfile_t *output)
 	       if (isedge (wfa->into [next][label][0])) /* prediction used */
 	       {
 		  used++;
-		  
+
 		  /*
 		   *  Encode a '1' symbol
 		   */
@@ -134,12 +134,12 @@ encode_nd_tree (const wfa_t *wfa, bitfile_t *output)
 		  low   = low + (u_word_t) ((range * sum0) / sum1);
 		  RESCALE_OUTPUT_INTERVAL;
 	       }
-	       else			/* no predict., continue with childs */
+	       else			/* no predict., continue with children */
 	       {
 		  not_used++;
 		  if (wfa->level_of_state [state] > wfa->wfainfo->p_min_level)
 		     queue_append (queue, &state);
-		  
+
 		  /*
 		   *  Encode a '0' symbol
 		   */
@@ -162,7 +162,7 @@ encode_nd_tree (const wfa_t *wfa, bitfile_t *output)
 		     sum1 = sum0 + 1;
 	       }
 	    }
-	 
+
       }
    }
    free_queue (queue);
@@ -178,7 +178,7 @@ encode_nd_tree (const wfa_t *wfa, bitfile_t *output)
 		  used, not_used);
    {
       unsigned total = used + not_used;
-      
+
       debug_message ("nd-tree:      %5d bits. (%5d symbols => %5.2f bps)",
 		     bits_processed (output) - bits, total,
 		     total > 0 ? ((bits_processed (output) - bits) /
@@ -205,7 +205,7 @@ encode_nd_coefficients (unsigned total, const wfa_t *wfa, bitfile_t *output)
       unsigned *ptr;			/* pointer to current factor */
       unsigned	state, label, edge;
       word_t	domain;
-      
+
       ptr = coefficients  = Calloc (total, sizeof (unsigned));
 
       for (state = wfa->basis_states; state < wfa->states; state++)
@@ -232,7 +232,7 @@ encode_nd_coefficients (unsigned total, const wfa_t *wfa, bitfile_t *output)
 	 encode_array (output, coefficients, NULL, &c_symbols, 1,
 		       total, scaling);
       }
-      
+
       debug_message ("nd-factors:   %5d bits. (%5d symbols => %5.2f bps)",
 		     bits_processed (output) - bits, total,
 		     total ? ((bits_processed (output) - bits)
diff --git a/converter/other/fiasco/output/tree.c b/converter/other/fiasco/output/tree.c
index 2eae2df9..55080a51 100644
--- a/converter/other/fiasco/output/tree.c
+++ b/converter/other/fiasco/output/tree.c
@@ -2,7 +2,7 @@
  *  tree.c:		Output of bintree partitioning
  *
  *  Written by:		Ullrich Hafner
- *		
+ *
  *  This file is part of FIASCO (Fractal Image And Sequence COdec)
  *  Copyright (C) 1994-2000 Ullrich Hafner
  */
@@ -30,7 +30,7 @@
 /*****************************************************************************
 
 				prototypes
-  
+
 *****************************************************************************/
 
 static void
@@ -40,7 +40,7 @@ encode_tree (bitfile_t *output, const byte_t *data, unsigned n_data,
 /*****************************************************************************
 
 				public code
-  
+
 *****************************************************************************/
 
 void
@@ -64,9 +64,9 @@ write_tree (const wfa_t *wfa, bitfile_t *output)
 
    /*
     *  Traverse tree in breadth first order. Use a queue to store
-    *  the childs of each node ('last' is the next free queue element).
+    *  the children of each node ('last' is the next free queue element).
     *  The first element ('current') of this queue will get the new parent
-    *  node. 
+    *  node.
     */
    tree_string = Calloc (MAXSTATES * MAXLABELS, sizeof (byte_t));
    queue [0] = wfa->root_state;
@@ -83,7 +83,7 @@ write_tree (const wfa_t *wfa, bitfile_t *output)
    if (total != (wfa->states - wfa->basis_states) * MAXLABELS)
       error ("total [%d] != (states - basis_states) * 2 [%d]", total,
 	     (wfa->states - wfa->basis_states) * MAXLABELS);
-   
+
    {
       unsigned scale = total / 20 ;
 
@@ -91,7 +91,7 @@ write_tree (const wfa_t *wfa, bitfile_t *output)
    }
 
    Free (tree_string);
-   
+
    debug_message ("tree:         %5d bits. (%5d symbols => %5.2f bps)",
 		  bits_processed (output) - bits, total,
 		  total > 0 ? ((bits_processed (output) - bits)
@@ -101,7 +101,7 @@ write_tree (const wfa_t *wfa, bitfile_t *output)
 /*****************************************************************************
 
 				private code
-  
+
 *****************************************************************************/
 
 static void
@@ -128,7 +128,7 @@ encode_tree (bitfile_t *output, const byte_t *data, unsigned n_data,
    for (n = n_data; n; n--)
    {
       unsigned range;			/* Current interval range */
-      
+
       if (!*data++)
       {
 	 /*
diff --git a/converter/other/fiasco/params.c b/converter/other/fiasco/params.c
index 7d0b84ab..29f52afc 100644
--- a/converter/other/fiasco/params.c
+++ b/converter/other/fiasco/params.c
@@ -3,7 +3,7 @@
  *
  *  Written by:		Stefan Frank
  *			Ullrich Hafner
- *		
+ *
  *  This file is part of FIASCO (Fractal Image And Sequence COdec)
  *  Copyright (C) 1994-2000 Ullrich Hafner
  */
@@ -28,7 +28,7 @@
 
 #include <stdlib.h>
 #include <string.h>
- 
+
 #include <getopt.h>			/* system or ../lib */
 
 #include "pm_c_util.h"
@@ -47,7 +47,7 @@
 /*****************************************************************************
 
 				prototypes
-  
+
 *****************************************************************************/
 
 static void
@@ -56,7 +56,7 @@ static int
 get_parameter_index (const param_t *params, const char *search_string);
 static void
 set_parameter (param_t *parameter, const char *value);
-static void 
+static void
 usage (const param_t *params, const char *progname, const char *synopsis,
        const char *comment, const char *non_opt_string,
        bool_t show_all_options, const char *sys_file_name,
@@ -65,17 +65,17 @@ usage (const param_t *params, const char *progname, const char *synopsis,
 /*****************************************************************************
 
 				public code
-  
+
 *****************************************************************************/
 
 int
-parseargs (param_t *usr_params, 
-           int argc, char **argv, 
+parseargs (param_t *usr_params,
+           int argc, char **argv,
            const char *synopsis,
-           const char *comment, 
-           const char *non_opt_string, 
+           const char *comment,
+           const char *non_opt_string,
            const char *path,
-           const char *sys_file_name, 
+           const char *sys_file_name,
            const char *usr_file_name)
 /*
  *  Perform the command line parsing.
@@ -95,7 +95,7 @@ parseargs (param_t *usr_params,
  *
  *  Side effects:
  *	the elements of ARGV are permuted
- *      usr_params [].value is modified 
+ *      usr_params [].value is modified
  */
 {
    extern int optind;			/* index in ARGV of the 1st element
@@ -146,7 +146,7 @@ parseargs (param_t *usr_params,
     */
    {
        param_t *p;
-      
+
        for (p = usr_params; p->name != NULL; p++)
        {
            set_parameter (p, p->default_value);
@@ -155,7 +155,7 @@ parseargs (param_t *usr_params,
        }
 
       sys_params = detailed_help ? detailed_sys_params : short_sys_params;
-      
+
       for (p = sys_params; p->name != NULL; p++)
           set_parameter (p, p->default_value);
    }
@@ -210,12 +210,12 @@ parseargs (param_t *usr_params,
       int	     optchar;		/* found option character */
 
       /*
-       *  Build short option string for getopt_long (). 
+       *  Build short option string for getopt_long ().
        */
       {
 	 param_t *p;			/* counter */
 	 char	 *ptr_optstr;		/* pointer to position in string */
-	 
+
 	 ptr_optstr = optstr;
 	 for (p = params; p->name != NULL; p++)
 	    if (p->optchar != '\0')
@@ -231,13 +231,13 @@ parseargs (param_t *usr_params,
 	    }
 	 *ptr_optstr = '\0';
       }
-      
+
       /*
-       *  Build long option string for getopt_long (). 
+       *  Build long option string for getopt_long ().
        */
       {
 	 int i;
-	 
+
 	 long_options = calloc (n1 + n2 + 1, sizeof (struct option));
 	 if (!long_options)
 	    error ("Out of memory.");
@@ -264,15 +264,15 @@ parseargs (param_t *usr_params,
 	    long_options [i].val     = 0;
 	 }
       }
-      
+
       /*
-       *  Parse comand line
+       *  Parse command line
        */
       while ((optchar = getopt_long (argc, argv, optstr, long_options,
 				     &option_index)) != EOF)
       {
 	 int param_index = -1;
-	 
+
 	 switch (optchar)
 	 {
 	    case 0:
@@ -303,7 +303,7 @@ parseargs (param_t *usr_params,
 	    default:
 	       {
 		  int i;
-		  
+
 		  for (i = 0; params [i].name != NULL; i++)
 		     if (params [i].optchar == optchar)
 		     {
@@ -350,7 +350,7 @@ parseargs (param_t *usr_params,
 
       free (long_options);
    }
-   
+
    /*
     *  Read config-file if specified by option -f
     */
@@ -361,7 +361,7 @@ parseargs (param_t *usr_params,
       if ((filename = (char *) parameter_value (params, "config")) != NULL)
       {
 	 FILE *parameter_file;		/* input file */
-	 
+
 	 warning ("Options set in file `%s' will override"
 		  " command line options.", filename);
 	 parameter_file = open_file (filename, NULL, READ_ACCESS);
@@ -379,10 +379,10 @@ parseargs (param_t *usr_params,
 
    memcpy (usr_params, params, n1 * sizeof (param_t)); /* fill user struct */
    free (sys_path);
-   
+
    return optind;
 }
- 
+
 void *
 parameter_value (const param_t *params, const char *name)
 /*
@@ -399,7 +399,7 @@ parameter_value (const param_t *params, const char *name)
 
    if (params [pind].type == PSTR || params [pind].type == POSTR)
       return (void *) params [pind].value.s;
-      
+
    return (void *) &(params [pind].value);
 }
 
@@ -414,7 +414,7 @@ ask_and_set (param_t *params, const char *name, const char *msg)
  *  Side effects:
  *	'params ['name'].value' is changed
  */
-{ 
+{
    char answer [MAXSTRLEN];
    int  index = get_parameter_index (params, name);
 
@@ -423,7 +423,7 @@ ask_and_set (param_t *params, const char *name, const char *msg)
 
    if (msg)
       fprintf (stderr, "%s\n", msg);
-  
+
    switch (params [index].type)
    {
       case PFLAG:			/* Unusual, at least. */
@@ -439,7 +439,7 @@ ask_and_set (param_t *params, const char *name, const char *msg)
       default:
 	 error ("Invalid parameter type for %s", name);
    }
-} 
+}
 
 void
 write_parameters (const param_t *params, FILE *output)
@@ -483,7 +483,7 @@ write_parameters (const param_t *params, FILE *output)
 /*****************************************************************************
 
 				private code
-  
+
 *****************************************************************************/
 
 static void
@@ -498,7 +498,7 @@ set_parameter (param_t *parameter, const char *value)
  */
 {
    assert (parameter);
-   
+
    switch (parameter->type)
    {
       case PFLAG:
@@ -516,7 +516,7 @@ set_parameter (param_t *parameter, const char *value)
 	    {
 	       long int	data;
 	       char	*endptr;
-	    
+
 	       data = strtol (value, &endptr, 0);
 	       if (*endptr != '\0' || endptr == value)
 		  warning ("Invalid value `%s' converted to %d",
@@ -531,7 +531,7 @@ set_parameter (param_t *parameter, const char *value)
 	 {
 	    long int  data;
 	    char     *endptr;
-	    
+
 	    data = strtol (value, &endptr, 0);
 	    if (*endptr != '\0' || endptr == value)
 	       warning ("Invalid value `%s' converted to %d",
@@ -543,7 +543,7 @@ set_parameter (param_t *parameter, const char *value)
 	 {
 	    double	data;
 	    char	*endptr;
-	    
+
 	    data = strtod (value, &endptr);
 	    if (*endptr != '\0' || endptr == value)
 	       warning ("Invalid value `%s' converted to %f",
@@ -555,7 +555,7 @@ set_parameter (param_t *parameter, const char *value)
       case POSTR:
 	 parameter->value.s = value ? strdup (value) : NULL;
 	 break;
-      default:				
+      default:
 	 error ("Invalid parameter type for %s", parameter->name);
    }
 }
@@ -606,7 +606,7 @@ read_parameter_file (param_t *params, FILE *file)
       char *name;			/* parameter name */
       char *value;			/* parameter value */
       int   pind;			/* current argument number */
-      
+
       b = strchr (buffer, '#');
       if (b != NULL)			/* Strip comments. */
 	 *b = '\0';
@@ -619,7 +619,7 @@ read_parameter_file (param_t *params, FILE *file)
       /*
        *  Extract value of parameter
        */
-      for (value = b + 1; ISSPACE (*value); value++) 
+      for (value = b + 1; ISSPACE (*value); value++)
 	 ;				/* Delete leading spaces */
 
       for (b = value + strlen (value) - 1; b >= value && ISSPACE (*b); b--)
@@ -628,7 +628,7 @@ read_parameter_file (param_t *params, FILE *file)
       /*
        *  Extract parameter name
        */
-      for (name = buffer; ISSPACE (*name); name++) 
+      for (name = buffer; ISSPACE (*name); name++)
 	 ;				/* Delete leading spaces */
 
       for (b = name + strlen (name) - 1; b >= name && ISSPACE (*b); b--)
@@ -637,21 +637,21 @@ read_parameter_file (param_t *params, FILE *file)
       pind = get_parameter_index (params, name);
       if (pind >= 0)
 	 set_parameter (&params [pind], value);
-      
+
       n++;
    }
-}   
+}
 
 
 
-static void 
+static void
 usage (const param_t *params, const char *progname, const char *synopsis,
        const char *comment, const char *non_opt_string,
        bool_t show_all_options, const char *sys_file_name,
        const char *usr_file_name)
 /*
  *  Generates and prints command line description from param_t struct 'params'.
- *  'progname' is the name of the excecutable, 'synopsis' a short program
+ *  'progname' is the name of the executable, 'synopsis' a short program
  *  description, and 'comment' some more advice.
  *  If flag 'show_all_options' is set then print also options that are not
  *  associated with a short option character.
@@ -662,7 +662,7 @@ usage (const param_t *params, const char *progname, const char *synopsis,
 {
     int	  i;
     size_t width = 0;
-   
+
     fprintf (stderr, "Usage: %s [OPTION]...%s\n", progname,
              non_opt_string ? non_opt_string : " ");
     if (synopsis != NULL)
@@ -683,7 +683,7 @@ usage (const param_t *params, const char *progname, const char *synopsis,
             else
                 width = MAX(width, (strlen (params [i].name)) - 1);
         }
-   
+
     for (i = 0; params [i].name != NULL; i++)
         if (params [i].optchar != '\0' || show_all_options)
         {
@@ -691,7 +691,7 @@ usage (const param_t *params, const char *progname, const char *synopsis,
                 fprintf (stderr, "  -%c, --", params [i].optchar);
             else
                 fprintf (stderr, "      --");
-	 
+
             if (params [i].type == POSTR)
                 fprintf (stderr, "%s=[%s]%-*s  ", params [i].name,
                          params [i].argument_name,
@@ -707,7 +707,7 @@ usage (const param_t *params, const char *progname, const char *synopsis,
                          (unsigned)(width + 1), params [i].name);
 
             fprintf (stderr, params [i].use, params [i].argument_name);
-	 
+
             switch (params [i].type)
             {
             case PFLAG:
diff --git a/converter/other/fiasco/pnmtofiasco.c b/converter/other/fiasco/pnmtofiasco.c
index e2656c71..9f63e7a1 100644
--- a/converter/other/fiasco/pnmtofiasco.c
+++ b/converter/other/fiasco/pnmtofiasco.c
@@ -2,11 +2,11 @@
  *  cwfa.c:     FIASCO coder
  *
  *  Written by:     Ullrich Hafner
- *      
+ *
  *  This file is part of FIASCO (Fractal Image And Sequence COdec)
  *  Copyright (C) 1994-2000 Ullrich Hafner
  */
- 
+
 /*
  *  $Date: 2000/10/28 17:39:29 $
  *  $Author: hafner $
@@ -33,7 +33,7 @@
 /*****************************************************************************
 
                  local variables
-  
+
 *****************************************************************************/
 
 static param_t params [] =
@@ -107,7 +107,7 @@ static param_t params [] =
    "Set domain pool of r-lc to `%s'."},
   {"coeff", "NAME", '\0', PSTR, {0}, "adaptive",
    "Set coefficients model to `%s'."},
-  /*  DELTA APPROXIATION  */
+  /*  DELTA APPROXIMATION  */
   {"d-domain-pool", "NAME", '\0', PSTR, {0}, "rle",
    "Set domain pool of d-lc to `%s'."},
   {"d-coeff", "NAME", '\0', PSTR, {0}, "adaptive",
@@ -132,36 +132,36 @@ static param_t params [] =
    "Smooth frames by factor `%s' (0.5 - 1.0)"},
   {"reference-frame", "FILE", '\0', PSTR, {0}, NULL,
    "Use PPM/PGM image `%s' as reference frame."},
-#endif  
+#endif
   {NULL, NULL, 0, PSTR, {0}, NULL, NULL }
 };
 
 /*****************************************************************************
 
                 prototypes
-  
+
 *****************************************************************************/
 
-static void 
+static void
 checkargs (int argc, char **argv, char const ***image_template,
        char **wfa_name, float *quality, fiasco_c_options_t **options);
 
 /*****************************************************************************
 
                 public code
-  
+
 *****************************************************************************/
- 
-int 
+
+int
 main (int argc, char **argv)
 {
    char const         **image_template; /* template for input image files */
    char                *wfa_name;   /* filename of output WFA */
    float            quality;    /* approximation quality */
    fiasco_c_options_t  *options;    /* additional coder options */
-   
+
    pnm_init(&argc, argv);
-   
+
    init_error_handling (argv [0]);
 
    checkargs (argc, argv, &image_template, &wfa_name, &quality, &options);
@@ -179,10 +179,10 @@ main (int argc, char **argv)
 /*****************************************************************************
 
                 private code
-  
+
 *****************************************************************************/
 
-static void 
+static void
 checkargs (int argc, char **argv, char const ***image_template,
            char **wfa_name, float *quality, fiasco_c_options_t **options)
 /*
@@ -191,7 +191,7 @@ checkargs (int argc, char **argv, char const ***image_template,
  *  Return value:
  *  1 on success
  *  0 otherwise
- *  
+ *
  *
  *  Side effects:
  *  'image_template', 'wfa_name', 'quality' and 'options' are set.
@@ -200,7 +200,7 @@ checkargs (int argc, char **argv, char const ***image_template,
     int   optind;            /* last processed commandline param */
     char *image_name;            /* filename given by option '--input_name' */
     int   i;             /* counter */
-   
+
     optind = parseargs (params, argc, argv,
                         "Compress raw PPM/PGM image FILEs to a FIASCO file.",
                         "With no image FILE, or if FILE is -, "
@@ -220,7 +220,7 @@ checkargs (int argc, char **argv, char const ***image_template,
     /*
      *  Default options ...
      */
-    image_name = (char *) parameter_value (params, "image-name"); 
+    image_name = (char *) parameter_value (params, "image-name");
     *wfa_name  = (char *) parameter_value (params, "output-name");
     for (;;)
     {
@@ -233,7 +233,7 @@ checkargs (int argc, char **argv, char const ***image_template,
         ask_and_set (params, "quality",
                      "Please enter coding quality 'q' ('q' > 0): ");
     }
-   
+
     if (optind < argc)           /* Additional command line param */
     {
         if (image_name)
@@ -260,7 +260,7 @@ checkargs (int argc, char **argv, char const ***image_template,
      */
     {
         *options = fiasco_c_options_new ();
-      
+
         {
             char *pattern = (char *) parameter_value (params, "pattern");
 
@@ -270,7 +270,7 @@ checkargs (int argc, char **argv, char const ***image_template,
 
         {
             char *basis = (char *) parameter_value (params, "basis-name");
-     
+
             if (!fiasco_c_options_set_basisfile (*options, basis))
                 error (fiasco_get_error_message ());
         }
@@ -278,41 +278,41 @@ checkargs (int argc, char **argv, char const ***image_template,
         {
             int   n = * (int *) parameter_value (params, "chroma-dictionary");
             float q = * (float *) parameter_value (params, "chroma-qfactor");
-      
+
             if (!fiasco_c_options_set_chroma_quality (*options, q, MAX(0, n)))
                 error (fiasco_get_error_message ());
         }
-      
+
         {
             int n = *((int *) parameter_value (params, "smooth"));
-     
+
             if (!fiasco_c_options_set_smoothing (*options, MAX(0, n)))
                 error (fiasco_get_error_message ());
         }
-      
+
         {
             int n = * (int *) parameter_value (params, "progress-meter");
-            fiasco_progress_e type = (n < 0) ? 
+            fiasco_progress_e type = (n < 0) ?
                 FIASCO_PROGRESS_NONE : (fiasco_progress_e) n;
-      
+
             if (!fiasco_c_options_set_progress_meter (*options, type))
                 error (fiasco_get_error_message ());
         }
-      
+
         {
             char *t = (char *) parameter_value (params, "title");
-     
+
             if (strlen (t) > 0 && !fiasco_c_options_set_title (*options, t))
                 error (fiasco_get_error_message ());
         }
-      
+
         {
             char *c = (char *) parameter_value (params, "comment");
 
             if (strlen (c) > 0 && !fiasco_c_options_set_comment (*options, c))
                 error (fiasco_get_error_message ());
         }
-      
+
         {
             fiasco_tiling_e method = FIASCO_TILING_VARIANCE_DSC;
             int   e  = * (int *) parameter_value (params, "tiling-exponent");
@@ -332,7 +332,7 @@ checkargs (int argc, char **argv, char const ***image_template,
             if (!fiasco_c_options_set_tiling (*options, method, MAX(0, e)))
                 error (fiasco_get_error_message ());
         }
-      
+
         {
             int M/*  = * (int *) parameter_value (params, "max-level") */;
             int m/*  = * (int *) parameter_value (params, "min-level") */;
@@ -354,7 +354,7 @@ checkargs (int argc, char **argv, char const ***image_template,
                 m = 4;
                 N = 5;
             }
-     
+
             if (!fiasco_c_options_set_optimizations (*options, m, M, N,
                                                      MAX(0, D), o))
                 error (fiasco_get_error_message ());
@@ -363,7 +363,7 @@ checkargs (int argc, char **argv, char const ***image_template,
             int M = * (int *) parameter_value (params, "max-level");
             int m = * (int *) parameter_value (params, "min-level");
             int p = * (int *) parameter_value (params, "prediction");
-     
+
             if (!fiasco_c_options_set_prediction (*options,
                                                   p, MAX(0, m), MAX(0, M)))
                 error (fiasco_get_error_message ());
@@ -374,7 +374,7 @@ checkargs (int argc, char **argv, char const ***image_template,
             int   m    = * (int *)  parameter_value(params, "rpf-mantissa");
             int   dc_m = * (int *)  parameter_value(params, "dc-rpf-mantissa");
             fiasco_rpf_range_e range, dc_range;
-     
+
             if (r < 1)
                 range = FIASCO_RPF_RANGE_0_75;
             else if (r < 1.5)
@@ -383,7 +383,7 @@ checkargs (int argc, char **argv, char const ***image_template,
                 range = FIASCO_RPF_RANGE_1_50;
             else
                 range = FIASCO_RPF_RANGE_2_00;
-        
+
             if (dc_r < 1)
                 dc_range = FIASCO_RPF_RANGE_0_75;
             else if (dc_r < 1.5)
@@ -392,7 +392,7 @@ checkargs (int argc, char **argv, char const ***image_template,
                 dc_range = FIASCO_RPF_RANGE_1_50;
             else
                 dc_range = FIASCO_RPF_RANGE_2_00;
-        
+
             if (!fiasco_c_options_set_quantization (*options,
                                                     MAX(0, m), range,
                                                     MAX(0, dc_m), dc_range))
@@ -402,4 +402,7 @@ checkargs (int argc, char **argv, char const ***image_template,
         if (fiasco_get_verbosity () == FIASCO_ULTIMATE_VERBOSITY)
             write_parameters (params, stderr);
     }
-}   
+}
+
+
+
diff --git a/converter/other/fitstopnm.c b/converter/other/fitstopnm.c
index e7de4311..804d4ae9 100644
--- a/converter/other/fitstopnm.c
+++ b/converter/other/fitstopnm.c
@@ -44,6 +44,7 @@
 #include <string.h>
 #include <float.h>
 #include <assert.h>
+#include <stdbool.h>
 
 #include "pm_config.h"
 #include "pm_c_util.h"
@@ -74,12 +75,12 @@ struct CmdlineInfo {
 
 
 
-static void 
-parseCommandLine(int argc, const char ** argv, 
+static void
+parseCommandLine(int argc, const 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.  
+   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.
@@ -140,7 +141,7 @@ parseCommandLine(int argc, const char ** argv,
         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);
@@ -150,29 +151,25 @@ parseCommandLine(int argc, const char ** argv,
 
 
 
-struct FITS_Header {
-  int simple;       /* basic format or not */
-  int bitpix;
-      /* number of bits per pixel, positive for integer, negative 
-         for floating point
-      */
-  int naxis;        /* number of axes */
-  int naxis1;       /* number of points on axis 1 */
-  int naxis2;       /* number of points on axis 2 */
-  int naxis3;       /* number of points on axis 3 */
-  double datamin;   /* min # (Physical value!) */
-  double datamax;   /* max #     "       "     */
-  double bzer;      /* Physical value = Array value*bscale + bzero */
-  double bscale;
-};
-
-
 typedef enum {
     VF_CHAR, VF_SHORT, VF_LONG, VF_FLOAT, VF_DOUBLE
-} valFmt;
+} ValFmt;
+
+struct FITS_Header {
+    bool simple;      /* basic format */
+    ValFmt valFmt;    /* format of values -- bits per pixel, integer/float */
+    unsigned int naxis;  /* number of axes */
+    unsigned int naxis1;       /* number of points on axis 1 */
+    unsigned int naxis2;       /* number of points on axis 2 */
+    unsigned int naxis3;       /* number of points on axis 3 */
+    double datamin;   /* min # (Physical value!) */
+    double datamax;   /* max #     "       "     */
+    double bzer;      /* Physical value = Array value*bscale + bzero */
+    double bscale;
+};
 
-struct fitsRasterInfo {
-    valFmt valFmt;
+struct FitsRasterInfo {
+    ValFmt valFmt;
     double bzer;
     double bscale;
 };
@@ -296,7 +293,7 @@ readFitsDouble(FILE *   const ifP,
 
 
 
-static valFmt
+static ValFmt
 valFmtFromBitpix(int const bitpix) {
 /*----------------------------------------------------------------------------
    Return the format of a "value" in the FITS file, given the value
@@ -323,7 +320,7 @@ valFmtFromBitpix(int const bitpix) {
 
 static void
 readVal(FILE *   const ifP,
-        valFmt   const fmt,
+        ValFmt   const fmt,
         double * const vP) {
 
     switch (fmt) {
@@ -334,15 +331,15 @@ readVal(FILE *   const ifP,
     case VF_SHORT:
         readFitsShort(ifP, vP);
         break;
-      
+
     case VF_LONG:
         readFitsLong(ifP, vP);
         break;
-      
+
     case VF_FLOAT:
         readFitsFloat(ifP, vP);
         break;
-      
+
     case VF_DOUBLE:
         readFitsDouble(ifP, vP);
         break;
@@ -364,46 +361,129 @@ readCard(FILE * const ifP,
 
 
 
+
+static void
+processNaxisN(unsigned int   const n,
+              int            const value,
+              bool           const gotNaxis,
+              unsigned int   const naxis,
+              bool *         const gotNaxisNP,
+              unsigned int * const naxisNP) {
+
+    if (*gotNaxisNP)
+        pm_error("Invalid FITS header: two NAXIS%u keywords", n);
+    else {
+        *gotNaxisNP = true;
+
+        if (!gotNaxis)
+            pm_error("Invalid FITS header: NAXIS must precede NAXIS%u", n);
+        else if (naxis < n)
+            pm_error("Invalid FITS header: NAXIS%u for image with "
+                     "only %u axes", n, naxis);
+        else if (value < 0)
+            pm_error("Invalid NAXIS%u value %d in FITS header:  "
+                     "Must not be negative", n, value);
+        else
+            *naxisNP = value;
+    }
+}
+
+
+
 static void
 readFitsHeader(FILE *               const ifP,
                struct FITS_Header * const hP) {
 
-    int seenEnd;
-  
-    seenEnd = 0;
+
+    bool gotEmpty, gotSimple, gotNaxis, gotN1, gotN2, gotN3, gotBitpix, gotEnd;
+
+    gotEmpty  = false;  /* initial value */    
+    gotSimple = false;  /* initial value */
+    gotNaxis  = false;  /* initial value */
+    gotN1     = false;  /* initial value */
+    gotN2     = false;  /* initial value */
+    gotN3     = false;  /* initial value */
+    gotBitpix = false;  /* initial value */
+    gotEnd    = false;  /* initial value */
+
     /* Set defaults */
-    hP->simple  = 0;
     hP->bzer    = 0.0;
     hP->bscale  = 1.0;
     hP->datamin = - DBL_MAX;
     hP->datamax = DBL_MAX;
-  
-    while (!seenEnd) {
+
+    while (!gotEnd) {
         unsigned int i;
 
         for (i = 0; i < 36; ++i) {
             char buf[81];
             char c;
+            int n;
 
             readCard(ifP, buf); /* Reads into first 80 elements of buf[] */
-    
+
             buf[80] = '\0'; /* Make ASCIIZ string */
 
-            if (sscanf(buf, "SIMPLE = %c", &c) == 1) {
+            if (sscanf(buf, " %c", &c) < 1) {
+                gotEmpty = true;
+            } else if (sscanf(buf, "SIMPLE = %c", &c) == 1) {
+                if (gotSimple)
+                    pm_error("FITS header has two SIMPLE keywords");
+                gotSimple = true;
                 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;
+                    hP->simple = true;
+                else if (c == 'F' || c == 'f')
+                    hP->simple = false;
+                else
+                    pm_error("Invalid SIMPLE value '%c'.  Only 'T' and 'F' "
+                             "are recognized", c);
+            } else if (sscanf(buf, "BITPIX = %d", &n) == 1) {
+                if (gotBitpix)
+                    pm_error("FITS header has two NAXIS keywords");
+                gotBitpix = true;
+                hP->valFmt = valFmtFromBitpix(n);
+            } else if (sscanf(buf, "NAXIS = %d", &n) == 1) {
+                gotNaxis = true;
+                if (n < 0)
+                    pm_error("Invalid value %d for NAXIS in FITS header.  "
+                             "Value must not be negative", n);
+                else
+                    hP->naxis = n;
+            } else if (sscanf(buf, "NAXIS1 = %d", &n) == 1) {
+                processNaxisN(1, n, gotNaxis, hP->naxis, &gotN1, &hP->naxis1);
+            } else if (sscanf(buf, "NAXIS2 = %d", &n) == 1) {
+                processNaxisN(2, n, gotNaxis, hP->naxis, &gotN2, &hP->naxis2);
+            } else if (sscanf(buf, "NAXIS3 = %d", &n) == 1) {
+                processNaxisN(3, n, gotNaxis, hP->naxis, &gotN3, &hP->naxis3);
+            } 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) {
+                gotEnd = true;
+                if (gotEmpty == true)
+                    pm_message("Blank card(s) were encountered before "
+			       "END in header");
+            }
         }
     }
+    if (!gotSimple)
+        pm_error("FITS header missing the SIMPLE keyword");
+    if (!gotBitpix)
+        pm_error("FITS header missing the BITPIX keyword");
+    if (!gotNaxis)
+        pm_error("FITS header missing the NAXIS keyword");
+
+    if (hP->naxis > 3)
+        pm_error("FITS file has %u axes; this program can handle "
+                 "no more than 3", hP->naxis);
+
+    if (hP->naxis > 0 && !gotN1)
+        pm_error("FITS header missing NAXIS1 keyword");
+    if (hP->naxis > 1 && !gotN2)
+        pm_error("FITS header missing NAXIS1 keyword");
+    if (hP->naxis > 2 && !gotN3)
+        pm_error("FITS header missing NAXIS3 keyword");
 }
 
 
@@ -424,7 +504,7 @@ interpretPlanes(struct FITS_Header const fitsHeader,
         if (imageRequest) {
             if (imageRequest > fitsHeader.naxis3)
                 pm_error("Only %u plane%s in this file.  "
-                         "You requested image %u", 
+                         "You requested image %u",
                          fitsHeader.naxis3, fitsHeader.naxis3 > 1 ? "s" : "",
                          imageRequest);
             else {
@@ -449,7 +529,7 @@ interpretPlanes(struct FITS_Header const fitsHeader,
         }
     }
     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",
@@ -464,7 +544,7 @@ scanImageForMinMax(FILE *       const ifP,
                    unsigned int const images,
                    int          const cols,
                    int          const rows,
-                   valFmt       const valFmt,
+                   ValFmt       const valFmt,
                    double       const bscale,
                    double       const bzer,
                    unsigned int const imagenum,
@@ -479,7 +559,7 @@ scanImageForMinMax(FILE *       const ifP,
     unsigned int image;
     pm_filepos rasterPos;
     double fmaxval;
-    
+
     pm_tell2(ifP, &rasterPos, sizeof(rasterPos));
 
     pm_message("Scanning file for scaling parameters");
@@ -557,7 +637,7 @@ computeMinMax(FILE *             const ifP,
     if (datamin == -DBL_MAX || datamax == DBL_MAX) {
         double scannedDatamin, scannedDatamax;
         scanImageForMinMax(ifP, images, cols, rows,
-                           valFmtFromBitpix(h.bitpix), h.bscale, h.bzer,
+                           h.valFmt, h.bscale, h.bzer,
                            imagenum, multiplane,
                            &scannedDatamin, &scannedDatamax);
 
@@ -574,12 +654,12 @@ computeMinMax(FILE *             const ifP,
 
 static xelval
 determineMaxval(struct CmdlineInfo const cmdline,
-                valFmt             const valFmt,
+                ValFmt             const valFmt,
                 double             const datamax,
                 double             const datamin) {
 
     xelval retval;
-                
+
     if (cmdline.omaxvalSpec)
         retval = cmdline.omaxval;
     else {
@@ -615,11 +695,11 @@ convertPgmRaster(FILE *                const ifP,
                  xelval                const maxval,
                  unsigned int          const desiredImage,
                  unsigned int          const imageCount,
-                 struct fitsRasterInfo const rasterInfo,
+                 struct FitsRasterInfo const rasterInfo,
                  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,
@@ -651,7 +731,7 @@ convertPgmRaster(FILE *                const ifP,
                 }
             }
         }
-    } 
+    }
 }
 
 
@@ -661,7 +741,7 @@ convertPpmRaster(FILE *                const ifP,
                  unsigned int          const cols,
                  unsigned int          const rows,
                  xelval                const maxval,
-                 struct fitsRasterInfo const rasterInfo,
+                 struct FitsRasterInfo const rasterInfo,
                  double                const scale,
                  double                const datamin,
                  xel **                const xels) {
@@ -711,7 +791,7 @@ convertRaster(FILE *                const ifP,
               bool                  const multiplane,
               unsigned int          const desiredImage,
               unsigned int          const imageCount,
-              struct fitsRasterInfo const rasterInfo,
+              struct FitsRasterInfo const rasterInfo,
               double                const scale,
               double                const datamin) {
 
@@ -746,7 +826,7 @@ main(int argc, const char * argv[]) {
     double scale;
     double datamin, datamax;
     struct FITS_Header fitsHeader;
-    struct fitsRasterInfo rasterInfo;
+    struct FitsRasterInfo rasterInfo;
 
     unsigned int imageCount;
     unsigned int desiredImage;
@@ -757,15 +837,15 @@ main(int argc, const char * argv[]) {
         /* This is a one-image multiplane stream; 'desiredImage'
            is undefined
         */
-  
+
     pm_proginit(&argc, argv);
-  
+
     parseCommandLine(argc, argv, &cmdline);
 
     ifP = pm_openr(cmdline.inputFileName);
 
     readFitsHeader(ifP, &fitsHeader);
-  
+
     if (!fitsHeader.simple)
         pm_error("FITS file is not in simple format, can't read");
 
@@ -777,7 +857,7 @@ main(int argc, const char * argv[]) {
 
     rasterInfo.bscale = fitsHeader.bscale;
     rasterInfo.bzer   = fitsHeader.bzer;
-    rasterInfo.valFmt = valFmtFromBitpix(fitsHeader.bitpix);
+    rasterInfo.valFmt = fitsHeader.valFmt;
 
     interpretPlanes(fitsHeader, cmdline.image, cmdline.verbose,
                     &imageCount, &multiplane, &desiredImage);
diff --git a/converter/other/gemtopnm.c b/converter/other/gemtopnm.c
index d862213f..6bbfcc05 100644
--- a/converter/other/gemtopnm.c
+++ b/converter/other/gemtopnm.c
@@ -25,7 +25,7 @@
  *
  * 92/07/11 Johann Haider
  * Changed to read from stdin if file is omitted
- * Changed to handle line length not a multipe of 8
+ * Changed to handle line length not a multiple of 8
  *
  * 94/01/31 Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de)
  * Changed to remove architecture dependency and conform to
diff --git a/converter/other/giftopnm.c b/converter/other/giftopnm.c
index e2d5923d..470c85b7 100644
--- a/converter/other/giftopnm.c
+++ b/converter/other/giftopnm.c
@@ -867,7 +867,7 @@ termStack(struct Stack * const stackP) {
 
    What we call 'dataWidth', others call the "minimum code size," which is a
    misnomer, because the minimum code size in a stream must be at least one
-   more than 'dataWidth', to accomodate the clear and end codes.
+   more than 'dataWidth', to accommmodate the clear and end codes.
 -----------------------------------------------------------------------------*/
 
 static int const maxLzwCodeCt = (1<<MAX_LZW_BITS);
@@ -1722,7 +1722,7 @@ readImageData(FILE *       const ifP,
         pm_error("Invalid data width (bits for a true data item) "
                  "in image data: %u.  "
                  "Maximum allowable code size in GIF is %u, "
-                 "and a code has to be wide enough to accomodate both "
+                 "and a code has to be wide enough to accommodate both "
                  "all possible data values and two control codes",
                  lzwDataWidth, MAX_LZW_BITS);
 
diff --git a/converter/other/infotopam.c b/converter/other/infotopam.c
index f2e35827..24c4d776 100644
--- a/converter/other/infotopam.c
+++ b/converter/other/infotopam.c
@@ -99,7 +99,7 @@ typedef struct IconInfo_ {
 typedef struct IconHeader_ { /* 20 bytes */
     unsigned char pad0[4];        /* Padding (always seems to be zero) */
     unsigned char iconWidth[2];   /* Width (usually equal to Gadget width) */
-    unsigned char iconHeight[2];  
+    unsigned char iconHeight[2];
     /* Height (usually equal to Gadget height -1) */
     unsigned char bpp[2];         /* Bits per pixel */
     unsigned char pad1[10];       /* ??? */
@@ -134,7 +134,7 @@ parseCommandLine( int              argc,
     unsigned int numColorArgs,  /* Number of arguments for overriding colors */
         colorIdx,      /* Color index */
         i;             /* Argument index */
-    const char  * const colors[4] = { 
+    const char  * const colors[4] = {
         /* Pixel colors based on original Amiga colors */
         "#0055AA",    /*   Blue      0,  85, 170 */
         "#FFFFFF",    /*   White   255, 255, 255 */
@@ -147,7 +147,7 @@ parseCommandLine( int              argc,
     optStruct3    opt;
     unsigned int  option_def_index;
     unsigned int numColorsSpec, forceColorSpec, selectedSpec;
-  
+
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     /* Set command line options */
@@ -166,7 +166,7 @@ parseCommandLine( int              argc,
     infoP->depth = 0;
     infoP->icon = NULL;
     for ( colorIdx = 0; colorIdx < 4; colorIdx++ )
-        infoP->colors[colorIdx] = 
+        infoP->colors[colorIdx] =
             ppm_parsecolor( (char*) colors[colorIdx], 0xFF );
 
     /* Initialize option structure */
@@ -258,7 +258,7 @@ getDiskObject( IconInfo * const infoP ) {
 
 
 
-static void 
+static void
 getIconHeader(IconInfo * const infoP) {
 /*-------------------------------------------------------------------------
  * Get fields from icon header portion of info file
@@ -277,7 +277,7 @@ getIconHeader(IconInfo * const infoP) {
                  "Only read 0x%X of 0x%X bytes",
                  infoP->name, (unsigned)bytesRead, (unsigned)sizeof(ihead));
 
-    /* Get icon width, heigh, and bitplanes */
+    /* Get icon width, height, and bitplanes */
     infoP->width  = (ihead.iconWidth[0]  << 8) + ihead.iconWidth[1];
     infoP->height = (ihead.iconHeight[0] << 8) + ihead.iconHeight[1];
     infoP->depth  = (ihead.bpp[0]        << 8) + ihead.bpp[1];
@@ -299,7 +299,7 @@ addBitplane(unsigned char * const icon,
 -----------------------------------------------------------------------------*/
     unsigned int i;
     unsigned int j;
-    
+
     for (i = j = 0; i < bpsize; ++i, j += 8) {
         icon[j+0] = (icon[j+0] << 1) | ((buff[i] >> 0) & 0x01);
         icon[j+1] = (icon[j+1] << 1) | ((buff[i] >> 1) & 0x01);
@@ -317,7 +317,7 @@ addBitplane(unsigned char * const icon,
 static void
 readIconData(FILE *           const fileP,
              unsigned int     const width,
-             unsigned int     const height, 
+             unsigned int     const height,
              unsigned int     const depth,
              unsigned char ** const iconP) {
 /*-------------------------------------------------------------------------
@@ -330,7 +330,7 @@ readIconData(FILE *           const fileP,
     unsigned int const bpsize = height * (((width + 15) / 16) * 2);
         /* Bitplane size in bytes, with padding */
 
-  
+
     MALLOCARRAY(buff, bpsize);
     if ( buff == NULL )
         pm_error( "Cannot allocate memory to hold icon pixels" );
@@ -350,10 +350,10 @@ readIconData(FILE *           const fileP,
      * points to the next byte in buff to fill in.  When the inner
      * loop is done, bp points to the end of buff.
      *
-     * After reading in the entire bitplane, the second inner loop splits the 
-     * eight pixels in each byte of the bitplane into eight separate bytes in 
-     * the icon buffer.  The existing contents of each byte in icon are left 
-     * shifted by one to make room for the next bit. 
+     * After reading in the entire bitplane, the second inner loop splits the
+     * eight pixels in each byte of the bitplane into eight separate bytes in
+     * the icon buffer.  The existing contents of each byte in icon are left
+     * shifted by one to make room for the next bit.
      *
      * Each byte in the completed icon contains a value from 0 to
      * 2^depth (0 to 1 for depth of 1 and 0 to 3 for a depth of 3).
@@ -363,7 +363,7 @@ readIconData(FILE *           const fileP,
         /* Read bitplane into buffer */
         int toread;   /* Number of bytes left to read */
         unsigned char * buffp;    /* Buffer point for reading data */
-       
+
         toread = bpsize; buffp = &buff[0];
 
         while (toread > 0) {
@@ -378,7 +378,7 @@ readIconData(FILE *           const fileP,
                 pm_error("Premature end-of-file.  "
                          "Still have 0x%X bytes to read",
                          toread );
-            
+
             toread -= bytesRead;
             buffp  += bytesRead;
         }
@@ -542,3 +542,6 @@ main( int argc,
 
     return 0;
 }
+
+
+
diff --git a/converter/other/ipdb.c b/converter/other/ipdb.c
index 5e4dc82e..d524c7e9 100644
--- a/converter/other/ipdb.c
+++ b/converter/other/ipdb.c
@@ -23,15 +23,12 @@
 #define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
 #define _BSD_SOURCE   /* Ensure strdup() is in <string.h> */
 #include <assert.h>
-#include <time.h>
 #include <string.h>
 
 #include "mallocvar.h"
 #include "nstring.h"
-#include "ipdb.h"
-
-typedef uint32_t pilot_time_t;
 
+#include "ipdb.h"
 
 
 
@@ -49,7 +46,7 @@ imgPpb(IMAGE * const imgP) {
 
 
 unsigned int
-ipdb_img_ppb(IMAGE * const imgP) {
+ipdb_imgPpb(IMAGE * const imgP) {
 /*----------------------------------------------------------------------------
    Pixels per byte
 -----------------------------------------------------------------------------*/
@@ -59,7 +56,7 @@ ipdb_img_ppb(IMAGE * const imgP) {
 
 
 size_t
-ipdb_img_size(IMAGE * const imgP) {
+ipdb_imgSize(IMAGE * const imgP) {
 /*----------------------------------------------------------------------------
   Size (in bytes) of an image's data.
 -----------------------------------------------------------------------------*/
@@ -71,115 +68,97 @@ ipdb_img_size(IMAGE * const imgP) {
 /*
  * Return the start of row `r'.
  */
- uint8_t *
- ipdb_img_row(IMAGE *      const imgP,
-              unsigned int const row) {
-
-     return &imgP->data[(row) * imgP->width / imgPpb(imgP)];
- }
-
-
+uint8_t *
+ipdb_imgRow(IMAGE *      const imgP,
+            unsigned int const row) {
 
- #define img_row(i, r)   
-
- static pilot_time_t const unixepoch = (66*365+17)*24*3600;
-     /* The unix epoch in Mac time (the Mac epoch is 00:00 UTC 1904.01.01).
-        The 17 is the number of leap years.
-     */
-
- static const char * const errorDesc[] = {
-     /* E_BADCOLORS      */
-     "Invalid palette, only {0x00, 0x55, 0xAA, 0xFF} allowed.",
+    return &imgP->data[(row) * imgP->width / imgPpb(imgP)];
+}
 
-     /* E_NOTIMAGE       */
-     "Not an image file.",
 
-     /* E_IMAGETHERE     */
-     "Image record already present, logic error.",
 
-     /* E_IMAGENOTTHERE  */
-     "Image record required before text record, logic error.",
+static const char * const errorDesc[] = {
+    /* E_BADCOLORS      */
+    "Invalid palette, only {0x00, 0x55, 0xAA, 0xFF} allowed.",
 
-     /* E_TEXTTHERE      */
-     "Text record already present, logic error.",
+    /* E_NOTIMAGE       */
+    "Not an image file.",
 
-     /* E_NOTRECHDR      */
-     "Invalid record header encountered.",
+    /* E_IMAGETHERE     */
+    "Image record already present, logic error.",
 
-     /* E_UNKNOWNRECHDR  */
-     "Unknown record header.",
+    /* E_IMAGENOTTHERE  */
+    "Image record required before text record, logic error.",
 
-     /* E_TOOBIGG        */
-     "Image too big, maximum size approx. 640*400 gray pixels.",
+    /* E_TEXTTHERE      */
+    "Text record already present, logic error.",
 
-     /* E_TOOBIGM        */
-     "Image too big, maximum size approx. 640*800 monochrome pixels.",
- };
+    /* E_NOTRECHDR      */
+    "Invalid record header encountered.",
 
+    /* E_UNKNOWNRECHDR  */
+    "Unknown record header.",
 
+    /* E_TOOBIGG        */
+    "Image too big, maximum size approx. 640*400 gray pixels.",
 
- const char *
- ipdb_err(int const e) {
+    /* E_TOOBIGM        */
+    "Image too big, maximum size approx. 640*800 monochrome pixels.",
+};
 
-     if (e < 0)
-         return e >= E_LAST ? errorDesc[-e - 1] : "unknown error";
-     else
-         return strerror(e);
- }
 
 
+const char *
+ipdb_err(int const e) {
 
- static void
- rechdr_free(RECHDR * const recP) {
+    if (e < 0)
+        return e >= E_LAST ? errorDesc[-e - 1] : "unknown error";
+    else
+        return strerror(e);
+}
 
-     if (recP) {
-         free(recP->extra);
-         free(recP);
-     }
- }
 
 
+static void
+rechdr_free(RECHDR * const recP) {
 
- void
- ipdb_image_free(IMAGE * const imgP) {
+    if (recP) {
+        free(recP->extra);
+        free(recP);
+    }
+}
 
-     if (imgP) {
-         rechdr_free(imgP->r);
-         free(imgP->data);
-         free(imgP);
-     }
- }
 
 
+void
+ipdb_imageFree(IMAGE * const imgP) {
 
- void
- ipdb_text_free(TEXT * const textP) {
+    if (imgP) {
+        rechdr_free(imgP->r);
+        free(imgP->data);
+        free(imgP);
+    }
+}
 
-     if (textP) {
-         rechdr_free(textP->r);
-         free(textP->data);
-         free(textP);
-     }
- }
 
 
+void
+ipdb_textFree(TEXT * const textP) {
 
- void
- ipdb_pdbhead_free(PDBHEAD * const headP) {
+    if (textP) {
+        rechdr_free(textP->r);
+        if (textP->data)
+            free(textP->data);
+        free(textP);
+    }
+}
 
-     free(headP);
- }
 
 
+void
+ipdb_pdbheadFree(PDBHEAD * const headP) {
 
- void
- ipdb_clear(IPDB * const pdbP) {
-     
-     if (pdbP) {
-         ipdb_image_free(pdbP->i);
-         ipdb_text_free(pdbP->t);
-         ipdb_pdbhead_free(pdbP->p);
-    }
+    free(headP);
 }
 
 
@@ -187,14 +166,22 @@ ipdb_img_size(IMAGE * const imgP) {
 void
 ipdb_free(IPDB * const pdbP) {
 
-    ipdb_clear(pdbP);
+    if (pdbP->i)
+        ipdb_imageFree(pdbP->i);
+
+    if (pdbP->t)
+        ipdb_textFree(pdbP->t);
+
+    if (pdbP->p)
+        ipdb_pdbheadFree(pdbP->p);
+
     free(pdbP);
 }
 
 
 
 PDBHEAD *
-ipdb_pdbhead_alloc(const char * const name) {
+ipdb_pdbheadAlloc() {
 
     PDBHEAD * pdbHeadP;
 
@@ -202,20 +189,6 @@ ipdb_pdbhead_alloc(const char * const name) {
 
     if (pdbHeadP) {
         MEMSZERO(pdbHeadP);
-
-        STRSCPY(pdbHeadP->name, name == NULL ? "unnamed" : name);
-
-        /*
-         * All of the Image Viewer pdb files that I've come across have
-         * 3510939142U (1997.08.16 14:38:22 UTC) here.  I don't know where
-         * this bizarre date comes from but the real date works fine so
-         * I'm using it.
-         */
-        pdbHeadP->ctime =
-            pdbHeadP->mtime = (pilot_time_t)time(NULL) + unixepoch;
-        
-        MEMSCPY(&pdbHeadP->type, IPDB_vIMG);
-        MEMSCPY(&pdbHeadP->id,   IPDB_View);
     }
     return pdbHeadP;
 }
@@ -223,7 +196,7 @@ ipdb_pdbhead_alloc(const char * const name) {
 
 
 static RECHDR *
-rechdr_alloc(int      const type,
+rechdrCreate(int      const type,
              uint32_t const offset) {
 
     /*
@@ -234,7 +207,7 @@ rechdr_alloc(int      const type,
     RECHDR  * recHdrP;
 
     MALLOCVAR(recHdrP);
-    
+
     if (recHdrP) {
         MEMSSET(recHdrP, 0);
 
@@ -255,10 +228,10 @@ rechdr_alloc(int      const type,
 
 
 IMAGE *
-ipdb_image_alloc(const char * const name,
-            int          const type,
-            int          const w,
-            int          const h) {
+ipdb_imageCreate(const char * const name,
+                 int          const type,
+                 int          const w,
+                 int          const h) {
 
     bool failed;
     IMAGE * imgP;
@@ -277,7 +250,7 @@ ipdb_image_alloc(const char * const name,
         imgP->width    = w;
         imgP->height   = h;
 
-        imgP->r = rechdr_alloc(IMG_REC, IMGOFFSET);
+        imgP->r = rechdrCreate(IMG_REC, IMGOFFSET);
 
         if (imgP->r) {
             if (w != 0 && h != 0) {
@@ -292,10 +265,10 @@ ipdb_image_alloc(const char * const name,
                 rechdr_free(imgP->r);
         } else
             failed = true;
-        
+
         if (failed)
-            ipdb_image_free(imgP);
-    } else 
+            ipdb_imageFree(imgP);
+    } else
         failed = true;
 
     return failed ? NULL : imgP;
@@ -304,7 +277,7 @@ ipdb_image_alloc(const char * const name,
 
 
 TEXT *
-ipdb_text_alloc(const char * const content) {
+ipdb_textAlloc(void) {
 
     TEXT * textP;
     bool failed;
@@ -320,22 +293,13 @@ ipdb_text_alloc(const char * const content) {
     if (textP) {
         MEMSZERO(textP);
 
-        textP->r = rechdr_alloc(TEXT_REC, 0);
+        textP->r = rechdrCreate(TEXT_REC, 0);
 
-        if (textP->r) {
-            if (content) {
-                textP->data = strdup(content);
-
-                if (!textP->data)
-                    failed = true;
-            }
-            if (failed)
-                rechdr_free(textP->r);
-        } else
+        if (textP->r == NULL)
             failed = true;
 
         if (failed)
-            ipdb_text_free(textP);
+            free(textP);
     } else
         failed = true;
 
@@ -345,7 +309,7 @@ ipdb_text_alloc(const char * const content) {
 
 
 IPDB *
-ipdb_alloc(const char * const name) {
+ipdb_alloc(void) {
 
     IPDB * pdbP;
     bool failed;
@@ -357,12 +321,11 @@ ipdb_alloc(const char * const name) {
     if (pdbP) {
         MEMSZERO(pdbP);
 
-        if (name) {
-            pdbP->p = ipdb_pdbhead_alloc(name);
+        pdbP->p = ipdb_pdbheadAlloc();
+
+        if (!pdbP->p)
+            failed = true;
 
-            if (!pdbP->p)
-                failed = true;
-        }
         if (failed)
             ipdb_free(pdbP);
     } else
@@ -383,3 +346,6 @@ ipdb_typeName(uint8_t const type) {
     default: return "???";
     }
 }
+
+
+
diff --git a/converter/other/ipdb.h b/converter/other/ipdb.h
index 6af5fc44..59e5d266 100644
--- a/converter/other/ipdb.h
+++ b/converter/other/ipdb.h
@@ -201,43 +201,40 @@ const char *
 ipdb_err(int error);
 
 size_t
-ipdb_img_size(IMAGE * const imgP);
+ipdb_imgSize(IMAGE * const imgP);
 
 unsigned int
-ipdb_img_ppb(IMAGE * const imgP);
+ipdb_imgPpb(IMAGE * const imgP);
 
 uint8_t *
-ipdb_img_row(IMAGE *      const imgP,
+ipdb_imgRow(IMAGE *      const imgP,
              unsigned int const row);
 
 void
 ipdb_free(IPDB *);
 
 IPDB *
-ipdb_alloc(const char *);
-
-void
-ipdb_clear(IPDB * const pdbP);
+ipdb_alloc(void);
 
 PDBHEAD *
-ipdb_pdbhead_alloc(const char * const name);
+ipdb_pdbheadAlloc(void);
 
 void
-ipdb_pdbhead_free(PDBHEAD * const headP);
+ipdb_pdbheadFree(PDBHEAD * const headP);
 
 IMAGE *
-ipdb_image_alloc(const char * const name,
+ipdb_imageCreate(const char * const name,
                  int          const type,
                  int          const w,
                  int          const h);
 
 void
-ipdb_image_free(IMAGE * const imgP);
+ipdb_imageFree(IMAGE * const imgP);
 
 void
-ipdb_text_free(TEXT * const textP);
+ipdb_textFree(TEXT * const textP);
 
 TEXT *
-ipdb_text_alloc(const char * const content);
+ipdb_textAlloc(void);
 
 #endif
diff --git a/converter/other/jbig/libjbig/include/jbig_ar.h b/converter/other/jbig/libjbig/include/jbig_ar.h
index d58b1ae0..ed5f2f86 100644
--- a/converter/other/jbig/libjbig/include/jbig_ar.h
+++ b/converter/other/jbig/libjbig/include/jbig_ar.h
@@ -14,7 +14,7 @@
 
 struct jbg_arenc_state {
   unsigned char st[4096];    /* probability status for contexts, MSB = MPS */
-  unsigned long c;                /* register C: base of coding intervall, *
+  unsigned long c;                /* register C: base of coding interval,  *
                                    * layout as in Table 23                 */
   unsigned long a;       /* register A: normalized size of coding interval */
   long sc;     /* number of buffered 0xff values that might still overflow */
@@ -30,7 +30,7 @@ struct jbg_arenc_state {
 
 struct jbg_ardec_state {
   unsigned char st[4096];    /* probability status for contexts, MSB = MPS */
-  unsigned long c;                /* register C: base of coding intervall, *
+  unsigned long c;                /* register C: base of coding interval,  *
                                    * layout as in Table 25                 */
   unsigned long a;       /* register A: normalized size of coding interval */
   unsigned char *pscd_ptr;               /* pointer to next PSCD data byte */
diff --git a/converter/other/jbig/libjbig/jbig.c b/converter/other/jbig/libjbig/jbig.c
index e8141070..cf24a93b 100644
--- a/converter/other/jbig/libjbig/jbig.c
+++ b/converter/other/jbig/libjbig/jbig.c
@@ -109,7 +109,7 @@ static const char *errmsg[] = {
  * The following three functions are the only places in this code, were
  * C library memory management functions are called. The whole JBIG
  * library has been designed in order to allow multi-threaded
- * execution. No static or global variables are used, so all fuctions
+ * execution. No static or global variables are used, so all functions
  * are fully reentrant. However if you want to use this multi-thread
  * capability and your malloc, realloc and free are not reentrant,
  * then simply add the necessary semaphores or mutex primitives below.
@@ -776,7 +776,7 @@ void jbg_enc_init(struct jbg_enc_state *s, unsigned long x, unsigned long y,
   assert(x > 0 && y > 0 && planes > 0 && planes < 256);
   s->xd = x;
   s->yd = y;
-  s->yd1 = y; /* This is the hight initially announced in BIH. To provoke
+  s->yd1 = y; /* This is the height initially announced in BIH. To provoke
                  generation of NEWLEN for T.85 compatibility tests,
                  overwrite with new value s->yd1 > s->yd  */
   s->planes = planes;
@@ -1106,7 +1106,7 @@ static void encode_sde(struct jbg_enc_state *s,
 	    if (!at_determined && j >= s->mx && j < hx-2) {
 	      p = (line_h1 & 0x100) != 0; /* current pixel value */
 	      c[0] += ((line_h2 & 0x4000) != 0) == p; /* default position */
-	      assert(!(((line_h2 >> 6) ^ line_h1) & 0x100) ==
+	      assert((!(((line_h2 >> 6) ^ line_h1) & 0x100)) ==
 		     (((line_h2 & 0x4000) != 0) == p));
 	      for (t = 5; t <= s->mx && t <= j; t++) {
 		o = (j - t) - (j & ~7L);
@@ -1151,7 +1151,7 @@ static void encode_sde(struct jbg_enc_state *s,
 	    if (!at_determined && j >= s->mx && j < hx-2) {
 	      p = (line_h1 & 0x100) != 0; /* current pixel value */
 	      c[0] += ((line_h2 & 0x4000) != 0) == p; /* default position */
-	      assert(!(((line_h2 >> 6) ^ line_h1) & 0x100) ==
+	      assert((!(((line_h2 >> 6) ^ line_h1) & 0x100)) ==
 		     (((line_h2 & 0x4000) != 0) == p));
 	      for (t = 3; t <= s->mx && t <= j; t++) {
 		o = (j - t) - (j & ~7L);
@@ -3240,7 +3240,7 @@ static unsigned char *jbg_next_pscdms(unsigned char *p, size_t len)
  * depends on the fact that section 6.2.6.2 of ITU-T T.82 says that a
  * NEWLEN marker segment "could refer to a line in the immediately
  * preceding stripe due to an unexpected termination of the image or
- * the use of only such stripe". ITU-T.85 explicitely suggests the
+ * the use of only such stripe". ITU-T.85 explicitly suggests the
  * use of this for fax machines that start transmission before having
  * encountered the end of the page. None of this is necessary for
  * BIEs produced by JBIG-KIT, which normally does not use NEWLEN.
diff --git a/converter/other/jpeg2000/Makefile b/converter/other/jpeg2000/Makefile
index 6e5af8e7..9c8729ac 100644
--- a/converter/other/jpeg2000/Makefile
+++ b/converter/other/jpeg2000/Makefile
@@ -46,8 +46,8 @@ endif
 
 BINARIES = $(PORTBINARIES)
 
-OBJECTS = $(BINARIES:%=%.o)
-MERGE_OBJECTS = $(BINARIES:%=%.o2) 
+OBJECTS = $(BINARIES:%=%.o) libjasper_compat.o
+MERGE_OBJECTS = $(BINARIES:%=%.o2) libjasper_compat.o2
 ifeq ($(JASPERLIB),$(INTERNAL_JASPERLIB))
   # MERGE_OBJECTS contains relative paths, so $(INTERNAL_JASPERLIB) had better
   # be relative to the current directory.
@@ -63,7 +63,7 @@ include $(SRCDIR)/common.mk
 
 LIBOPTS = $(shell $(LIBOPT) $(JASPERLIB_USE))
 
-$(BINARIES): %: %.o $(JASPERLIB_DEP) $(LIBOPT)
+$(BINARIES): %: %.o libjasper_compat.o $(JASPERLIB_DEP) $(LIBOPT)
 $(BINARIES): LDFLAGS_TARGET = $(LIBOPTS) $(JASPERDEPLIBS)
 
 $(INTERNAL_JASPERLIB): $(BUILDDIR)/$(SUBDIR)/libjasper FORCE
diff --git a/converter/other/jpeg2000/jpeg2ktopam.c b/converter/other/jpeg2000/jpeg2ktopam.c
index b507f56e..bda0de2e 100644
--- a/converter/other/jpeg2000/jpeg2ktopam.c
+++ b/converter/other/jpeg2000/jpeg2ktopam.c
@@ -29,11 +29,9 @@
 
 #include "libjasper_compat.h"
 
-enum compmode {COMPMODE_INTEGER, COMPMODE_REAL};
 
-enum progression {PROG_LRCP, PROG_RLCP, PROG_RPCL, PROG_PCRL, PROG_CPRL};
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -44,15 +42,15 @@ struct cmdlineInfo {
 
 
 static void
-parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo * const cmdlineP) {
+parseCommandLine(int argc, const char ** argv,
+                 struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that many of the strings that this function returns in the
    *cmdlineP structure are actually in the supplied argv array.  And
    sometimes, one of these strings is actually just a suffix of an entry
    in argv!
 -----------------------------------------------------------------------------*/
-    optEntry *option_def;
+    optEntry * option_def;
     optStruct3 opt;
 
     unsigned int debuglevelSpec;
@@ -71,7 +69,7 @@ parseCommandLine(int argc, char ** argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char**)argv, opt, sizeof(opt), 0);
 
     if (!debuglevelSpec)
         cmdlineP->debuglevel = 0;
@@ -84,6 +82,7 @@ parseCommandLine(int argc, char ** argv,
         pm_error("Too many arguments.  The only argument accepted\n"
                  "is the input file specification");
 
+    free(option_def);
 }
 
 
@@ -114,9 +113,11 @@ static void
 readJ2k(const char *   const inputFilename,
         jas_image_t ** const jasperPP) {
 
+    const char * const options = "";
+
     jas_image_t * jasperP;
     jas_stream_t * instreamP;
-    const char * options;
+    const char * error;
 
     if (streq(inputFilename, "-")) {
         /* The input image is to be read from standard input. */
@@ -131,13 +132,10 @@ readJ2k(const char *   const inputFilename,
 
     validateJ2k(instreamP);
 
-    options = "";
-
-    jasperP = jas_image_decode(instreamP, jas_image_getfmt(instreamP),
-                               (char*)options);
-    if (jasperP == NULL)
-        pm_error("Unable to interpret JPEG-2000 input.  "
-                 "The Jasper library jas_image_decode() subroutine failed.");
+    pmjas_image_decode(instreamP, jas_image_getfmt(instreamP), options,
+                       &jasperP, &error);
+    if (error)
+        pm_error("Unable to interpret JPEG-2000 input.  %s", error);
 
     jas_stream_close(instreamP);
 
@@ -483,9 +481,9 @@ convertToPamPnm(struct pam *  const outpamP,
 
 
 int
-main(int argc, char **argv)
+main(int argc, const char **argv)
 {
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     struct pam outpam;
     int * jasperCmpt;  /* malloc'ed */
        /* jaspercmpt[P] is the component number for use with the
@@ -493,7 +491,7 @@ main(int argc, char **argv)
        */
     jas_image_t * jasperP;
 
-    pnm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
diff --git a/converter/other/jpeg2000/libjasper/base/jas_image.c b/converter/other/jpeg2000/libjasper/base/jas_image.c
index 5c2822be..c6f984c1 100644
--- a/converter/other/jpeg2000/libjasper/base/jas_image.c
+++ b/converter/other/jpeg2000/libjasper/base/jas_image.c
@@ -126,6 +126,8 @@
 #include <assert.h>
 #include <ctype.h>
 
+#include "netpbm/nstring.h"
+
 #include "jasper/jas_math.h"
 #include "jasper/jas_image.h"
 #include "jasper/jas_malloc.h"
@@ -379,22 +381,47 @@ static void jas_image_cmpt_destroy(jas_image_cmpt_t *cmpt)
 * Load and save operations.
 \*****************************************************************************/
 
-jas_image_t *jas_image_decode(jas_stream_t *in, int fmt, char *optstr)
-{
+void
+pmjas_image_decode(jas_stream_t * const in,
+				   int            const fmtArg,
+				   const char *   const optstr,
+				   jas_image_t ** const imagePP,
+				   const char **  const errorP) {
+/*----------------------------------------------------------------------------
+  Create an image from a stream in some specified format
+-----------------------------------------------------------------------------*/
 	jas_image_fmtinfo_t *fmtinfo;
+	int fmt;
 
 	/* If possible, try to determine the format of the input data. */
-	if (fmt < 0) {
+	if (fmtArg < 0) {
 		if ((fmt = jas_image_getfmt(in)) < 0) {
-			return 0;
+			pm_asprintf(errorP, "jas_image_getfmt failed");
+			return;
 		}
-	}
+	} else
+		fmt = fmtArg;
+
 	if (!(fmtinfo = jas_image_lookupfmtbyid(fmt))) {
-		return 0;
+		pm_asprintf(errorP, "jas_image_lookupfmtbyid of format %d failed",
+					fmt);
+		return;
+	}
+	{
+		const char * error;
+
+		(*fmtinfo->ops.decode)(in, optstr, imagePP, &error);
+		if (error) {
+			pm_asprintf(errorP, "decoder failed.  %s", error);
+			pm_strfree(error);
+		} else {
+			*errorP = NULL;
+		}
 	}
-	return (fmtinfo->ops.decode) ? (*fmtinfo->ops.decode)(in, optstr) : 0;
 }
 
+
+
 int jas_image_encode(jas_image_t *image, jas_stream_t *out, int fmt, char *optstr)
 {
 	jas_image_fmtinfo_t *fmtinfo;
@@ -648,7 +675,7 @@ int jas_image_fmtfromname(char *name)
 		return -1;
 	}
 	++ext;
-	/* Try to find a format that uses this extension. */	
+	/* Try to find a format that uses this extension. */
 	for (i = 0, fmtinfo = jas_image_fmtinfos; i < jas_image_numfmts; ++i,
 	  ++fmtinfo) {
 		/* Do we have a match? */
@@ -659,25 +686,28 @@ int jas_image_fmtfromname(char *name)
 	return -1;
 }
 
-/******************************************************************************\
+/*****************************************************************************\
 * Miscellaneous operations.
-\******************************************************************************/
+\*****************************************************************************/
 
-uint_fast32_t jas_image_rawsize(jas_image_t *image)
-{
-	uint_fast32_t rawsize;
-	uint_fast32_t cmptno;
-	jas_image_cmpt_t *cmpt;
+uint_fast32_t
+jas_image_rawsize(jas_image_t * const imageP) {
+/*----------------------------------------------------------------------------
+   The raw size of the image, i.e. the number of bytes the raster of the image
+   would take if just represented simply, with no compression.
+-----------------------------------------------------------------------------*/
+    uint_fast32_t rawsize;
+    uint_fast32_t cmptno;
 
-	rawsize = 0;
-	for (cmptno = 0; cmptno < image->numcmpts_; ++cmptno) {
-		cmpt = image->cmpts_[cmptno];
-		rawsize += (cmpt->width_ * cmpt->height_ * cmpt->prec_ +
-		  7) / 8;
-	}
-	return rawsize;
+    for (cmptno = 0, rawsize = 0; cmptno < imageP->numcmpts_; ++cmptno) {
+        jas_image_cmpt_t * const cmptP = imageP->cmpts_[cmptno];
+        rawsize += (cmptP->width_ * cmptP->height_ * cmptP->prec_ + 7) / 8;
+    }
+    return rawsize;
 }
 
+
+
 void jas_image_delcmpt(jas_image_t *image, uint_fast16_t cmptno)
 {
 	if (cmptno >= image->numcmpts_) {
diff --git a/converter/other/jpeg2000/libjasper/base/jas_stream.c b/converter/other/jpeg2000/libjasper/base/jas_stream.c
index 24f835ed..a4b3a27c 100644
--- a/converter/other/jpeg2000/libjasper/base/jas_stream.c
+++ b/converter/other/jpeg2000/libjasper/base/jas_stream.c
@@ -6,14 +6,14 @@
  */
 
 /* __START_OF_JASPER_LICENSE__
- * 
+ *
  * JasPer Software License
- * 
+ *
  * IMAGE POWER JPEG-2000 PUBLIC LICENSE
  * ************************************
- * 
+ *
  * GRANT:
- * 
+ *
  * Permission is hereby granted, free of charge, to any person (the "User")
  * obtaining a copy of this software and associated documentation, to deal
  * in the JasPer Software without restriction, including without limitation
@@ -21,22 +21,22 @@
  * and/or sell copies of the JasPer Software (in source and binary forms),
  * and to permit persons to whom the JasPer Software is furnished to do so,
  * provided further that the License Conditions below are met.
- * 
+ *
  * License Conditions
  * ******************
- * 
+ *
  * A.  Redistributions of source code must retain the above copyright notice,
  * and this list of conditions, and the following disclaimer.
- * 
+ *
  * B.  Redistributions in binary form must reproduce the above copyright
  * notice, and this list of conditions, and the following disclaimer in
  * the documentation and/or other materials provided with the distribution.
- * 
+ *
  * C.  Neither the name of Image Power, Inc. nor any other contributor
  * (including, but not limited to, the University of British Columbia and
  * Michael David Adams) may be used to endorse or promote products derived
  * from this software without specific prior written permission.
- * 
+ *
  * D.  User agrees that it shall not commence any action against Image Power,
  * Inc., the University of British Columbia, Michael David Adams, or any
  * other contributors (collectively "Licensors") for infringement of any
@@ -56,17 +56,17 @@
  * trade dress, or service mark rights); and (v) divisions, continuations,
  * renewals, reissues and extensions of the foregoing (as and to the extent
  * applicable) now existing, hereafter filed, issued or acquired.
- * 
+ *
  * E.  If User commences an infringement action against any Licensor(s) then
  * such Licensor(s) shall have the right to terminate User's license and
  * all sublicenses that have been granted hereunder by User to other parties.
- * 
+ *
  * F.  This software is for use only in hardware or software products that
  * are compliant with ISO/IEC 15444-1 (i.e., JPEG-2000 Part 1).  No license
  * or right to this Software is granted for products that do not comply
  * with ISO/IEC 15444-1.  The JPEG-2000 Part 1 standard can be purchased
  * from the ISO.
- * 
+ *
  * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.
  * NO USE OF THE JASPER SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER
  * THIS DISCLAIMER.  THE JASPER SOFTWARE IS PROVIDED BY THE LICENSORS AND
@@ -106,10 +106,11 @@
  * 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__
  */
 
+#define _DEFAULT_SOURCE /* New name for SVID & BSD source defines */
 #define _SVID_SOURCE
     /* Make sure P_tmpdir is defined in GNU libc 2.0.7 (_XOPEN_SOURCE 500
        does it in other libc's).  pm_config.h defines TMPDIR as P_tmpdir
@@ -276,7 +277,7 @@ jas_stream_t *jas_stream_memopen(char *buf, int bufsize)
 		obj->len_ = 0;
 	}
 	obj->pos_ = 0;
-	
+
 	return stream;
 }
 
@@ -409,7 +410,7 @@ jas_stream_t *jas_stream_tmpfile()
         */
         jmp_buf jmpbuf;
         int rc;
-        
+
         rc = setjmp(jmpbuf);
         if (rc == 0) {
             pm_setjmpbuf(&jmpbuf);
diff --git a/converter/other/jpeg2000/libjasper/include/jasper/jas_image.h b/converter/other/jpeg2000/libjasper/include/jasper/jas_image.h
index 6e914efd..20170986 100644
--- a/converter/other/jpeg2000/libjasper/include/jasper/jas_image.h
+++ b/converter/other/jpeg2000/libjasper/include/jasper/jas_image.h
@@ -300,7 +300,10 @@ typedef struct {
 
 typedef struct {
 
-	jas_image_t *(*decode)(jas_stream_t *in, char *opts);
+	void (*decode)(jas_stream_t * const in,
+				   const char *   const opts,
+				   jas_image_t ** const imagePP,
+				   const char **  const errorP);
 	/* Decode image data from a stream. */
 
 	int (*encode)(jas_image_t *image, jas_stream_t *out, char *opts);
@@ -442,8 +445,14 @@ void jas_image_destroy(jas_image_t *image);
   any compression. */
 uint_fast32_t jas_image_rawsize(jas_image_t *image);
 
-/* Create an image from a stream in some specified format. */
-jas_image_t *jas_image_decode(jas_stream_t *in, int fmt, char *optstr);
+#define JAS_HAVE_PMJAS_IMAGE_DECODE
+
+void
+pmjas_image_decode(jas_stream_t * const in,
+				   int            const fmt,
+				   const char *   const optstr,
+				   jas_image_t ** const imagePP,
+				   const char **  const errorP);
 
 /* Write an image to a stream in a specified format. */
 int jas_image_encode(jas_image_t *image, jas_stream_t *out, int fmt,
@@ -567,14 +576,22 @@ int bmp_validate(jas_stream_t *in);
 
 #if !defined(EXCLUDE_JP2_CAPABILITY)
 /* Format-dependent operations for JP2 capability. */
-jas_image_t *jp2_decode(jas_stream_t *in, char *optstr);
+void
+jp2_decode(jas_stream_t * const in,
+		   const char *   const optstr,
+		   jas_image_t ** const imagePP,
+		   const char **  const errorP);
 int jp2_encode(jas_image_t *image, jas_stream_t *out, char *optstr);
 int jp2_validate(jas_stream_t *in);
 #endif
 
 #if !defined(EXCLUDE_JPC_CAPABILITY)
 /* Format-dependent operations for JPEG-2000 code stream capability. */
-jas_image_t *jpc_decode(jas_stream_t *in, char *optstr);
+void
+jpc_decode(jas_stream_t * const in,
+           const char *   const optstr,
+           jas_image_t ** const imagePP,
+           const char **  const errorP);
 int jpc_encode(jas_image_t *image, jas_stream_t *out, char *optstr);
 int jpc_validate(jas_stream_t *in);
 #endif
diff --git a/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c b/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c
index 4036f0f2..e8d71b0a 100644
--- a/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c
+++ b/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c
@@ -117,6 +117,8 @@
 #include "jasper/jas_malloc.h"
 #include "jasper/jas_version.h"
 
+#include "netpbm/nstring.h"
+
 #include "jp2_cod.h"
 #include "jp2_dec.h"
 
@@ -271,8 +273,11 @@ fromiccpcs(int cs) {
 
 
 
-jas_image_t *
-jp2_decode(jas_stream_t *in, char *optstr) {
+void
+jp2_decode(jas_stream_t * const in,
+           const char *   const optstr,
+           jas_image_t ** const imagePP,
+           const char **  const errorP) {
 
     jp2_box_t *box;
     int found;
@@ -295,32 +300,34 @@ jp2_decode(jas_stream_t *in, char *optstr) {
     image = 0;
 
     if (!(dec = jp2_dec_create())) {
-        goto error;
+        pm_asprintf(errorP, "jp2_dec_create failed");
+        goto cleanup;
     }
 
     /* Get the first box.  This should be a JP box. */
     if (!(box = jp2_box_get(in))) {
-        jas_eprintf("error: cannot get box\n");
-        goto error;
+        pm_asprintf(errorP, "cannot get box");
+        goto cleanup;
     }
     if (box->type != JP2_BOX_JP) {
-        jas_eprintf("error: expecting signature box\n");
-        goto error;
+        pm_asprintf(errorP, "expecting signature box");
+        goto cleanup;
     }
     if (box->data.jp.magic != JP2_JP_MAGIC) {
-        jas_eprintf("incorrect magic number\n");
-        goto error;
+        pm_asprintf(errorP, "incorrect magic number");
+        goto cleanup;
     }
     jp2_box_destroy(box);
     box = 0;
 
     /* Get the second box.  This should be a FTYP box. */
     if (!(box = jp2_box_get(in))) {
-        goto error;
+        pm_asprintf(errorP, "cannot get second box");
+        goto cleanup;
     }
     if (box->type != JP2_BOX_FTYP) {
-        jas_eprintf("expecting file type box\n");
-        goto error;
+        pm_asprintf(errorP, "expecting file type box");
+        goto cleanup;
     }
     jp2_box_destroy(box);
     box = 0;
@@ -329,7 +336,7 @@ jp2_decode(jas_stream_t *in, char *optstr) {
     found = 0;
     while ((box = jp2_box_get(in))) {
         if (jas_getdbglevel() >= 1) {
-            fprintf(stderr, "box type %s\n", box->info->name);
+            jas_eprintf("box type '%s'\n", box->info->name);
         }
         switch (box->type) {
         case JP2_BOX_JP2C:
@@ -382,19 +389,24 @@ jp2_decode(jas_stream_t *in, char *optstr) {
     }
 
     if (!found) {
-        jas_eprintf("error: no code stream found\n");
-        goto error;
+        pm_asprintf(errorP, "no code stream found");
+        goto cleanup;
     }
 
-    if (!(dec->image = jpc_decode(in, optstr))) {
-        jas_eprintf("error: cannot decode code stream\n");
-        goto error;
+    {
+        const char * decodeError;
+        jpc_decode(in, optstr, &dec->image, &decodeError);
+        if (decodeError) {
+            pm_asprintf(errorP, "cannot decode code stream.  %s", decodeError);
+            pm_strfree(decodeError);
+            goto cleanup;
+        }
     }
 
     /* An IHDR box must be present. */
     if (!dec->ihdr) {
-        jas_eprintf("error: missing IHDR box\n");
-        goto error;
+        pm_asprintf(errorP, "missing IHDR box");
+        goto cleanup;
     }
 
     /* Does the number of components indicated in the IHDR box match
@@ -405,8 +417,8 @@ jp2_decode(jas_stream_t *in, char *optstr) {
 
     /* At least one component must be present. */
     if (!jas_image_numcmpts(dec->image)) {
-        jas_eprintf("error: no components\n");
-        goto error;
+        pm_asprintf(errorP, "no components");
+        goto cleanup;
     }
 
     /* Determine if all components have the same data type. */
@@ -428,15 +440,15 @@ jp2_decode(jas_stream_t *in, char *optstr) {
 
     /* Can we handle the compression type? */
     if (dec->ihdr->data.ihdr.comptype != JP2_IHDR_COMPTYPE) {
-        jas_eprintf("error: not capable of this compression type\n");
-        goto error;
+        pm_asprintf(errorP, "not capable of this compression type");
+        goto cleanup;
     }
 
     if (dec->bpcc) {
         /* Is the number of components indicated in the BPCC box
           consistent with the code stream data? */
         if (dec->bpcc->data.bpcc.numcmpts != jas_image_numcmpts(
-          dec->image)) {
+                dec->image)) {
             jas_eprintf("warning: number of components mismatch\n");
         }
         /* Is the component data type information indicated in the BPCC
@@ -455,8 +467,8 @@ jp2_decode(jas_stream_t *in, char *optstr) {
 
     /* A COLR box must be present. */
     if (!dec->colr) {
-        jas_eprintf("error: no COLR box\n");
-        goto error;
+        pm_asprintf(errorP, "no COLR box");
+        goto cleanup;
     }
 
     switch (dec->colr->data.colr.method) {
@@ -502,14 +514,14 @@ jp2_decode(jas_stream_t *in, char *optstr) {
             /* Is the component number reasonable? */
             if (dec->cmap->data.cmap.ents[i].cmptno >=
                 jas_image_numcmpts(dec->image)) {
-                jas_eprintf("error: invalid component number in CMAP box\n");
-                goto error;
+                pm_asprintf(errorP, "invalid component number in CMAP box");
+                goto cleanup;
             }
             /* Is the LUT index reasonable? */
             if (dec->cmap->data.cmap.ents[i].pcol >=
                 dec->pclr->data.pclr.numchans) {
-                jas_eprintf("error: invalid CMAP LUT index\n");
-                goto error;
+                pm_asprintf(errorP, "invalid CMAP LUT index");
+                goto cleanup;
             }
         }
     }
@@ -517,8 +529,8 @@ jp2_decode(jas_stream_t *in, char *optstr) {
     /* Allocate space for the channel-number to component-number LUT. */
     dec->chantocmptlut = jas_malloc(dec->numchans * sizeof(uint_fast16_t));
     if (!dec->chantocmptlut) {
-        jas_eprintf("error: no memory\n");
-        goto error;
+        pm_asprintf(errorP, "no memory");
+        goto cleanup;
     }
 
     if (!dec->cmap) {
@@ -564,8 +576,8 @@ jp2_decode(jas_stream_t *in, char *optstr) {
                 }
 #endif
             } else {
-                jas_eprintf("error: invalid MTYP in CMAP box\n");
-                goto error;
+                pm_asprintf(errorP, "invalid MTYP in CMAP box");
+                goto cleanup;
             }
         }
     }
@@ -604,8 +616,8 @@ jp2_decode(jas_stream_t *in, char *optstr) {
 
     /* Ensure that some components survived. */
     if (!jas_image_numcmpts(dec->image)) {
-        jas_eprintf("error: no components\n");
-        goto error;
+        pm_asprintf(errorP, "no components");
+        goto cleanup;
     }
 
     /* Prevent the image from being destroyed later. */
@@ -614,16 +626,17 @@ jp2_decode(jas_stream_t *in, char *optstr) {
 
     jp2_dec_destroy(dec);
 
-    return image;
+    *imagePP = image;
+    *errorP = NULL;
+    return;
 
-error:
+cleanup:
     if (box) {
         jp2_box_destroy(box);
     }
     if (dec) {
         jp2_dec_destroy(dec);
     }
-    return 0;
 }
 
 
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_dec.c b/converter/other/jpeg2000/libjasper/jpc/jpc_dec.c
index 4d4dfc50..140169ec 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_dec.c
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_dec.c
@@ -114,15 +114,13 @@
  * $Id$
  */
 
-/*****************************************************************************\
-* Includes.
-\*****************************************************************************/
-
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <assert.h>
 
 #include "pm.h"
+#include "netpbm/nstring.h"
 
 #include "jasper/jas_types.h"
 #include "jasper/jas_math.h"
@@ -164,7 +162,10 @@ typedef struct {
     /* The states in which this type of marker segment can be
       validly encountered. */
 
-    int (*action)(jpc_dec_t *dec, jpc_ms_t *ms);
+    void (*action)(jpc_dec_t *   const dec,
+                   jpc_ms_t *    const ms,
+                   bool *        const doneP,
+                   const char ** const errorP);
     /* The action to take upon encountering this type of marker segment. */
 
 } jpc_dec_mstabent_t;
@@ -223,119 +224,263 @@ static void jpc_dec_cp_destroy(jpc_dec_cp_t *cp);
 static int jpc_dec_cp_setfrompoc(jpc_dec_cp_t *cp, jpc_poc_t *poc, int reset);
 static int jpc_pi_addpchgfrompoc(jpc_pi_t *pi, jpc_poc_t *poc);
 
-static int jpc_dec_decode(jpc_dec_t *dec);
 static jpc_dec_t *jpc_dec_create(jpc_dec_importopts_t *impopts, jas_stream_t *in);
 static void jpc_dec_destroy(jpc_dec_t *dec);
 static void jpc_dequantize(jas_matrix_t *x, jpc_fix_t absstepsize);
 static void jpc_undo_roi(jas_matrix_t *x, int roishift, int bgshift, int numbps);
 static jpc_fix_t jpc_calcabsstepsize(int stepsize, int numbits);
-static int jpc_dec_tiledecode(jpc_dec_t *dec, jpc_dec_tile_t *tile);
 static int jpc_dec_tileinit(jpc_dec_t *dec, jpc_dec_tile_t *tile);
 static int jpc_dec_tilefini(jpc_dec_t *dec, jpc_dec_tile_t *tile);
-static int jpc_dec_process_soc(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_sot(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_sod(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_eoc(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_siz(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_cod(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_coc(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_rgn(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_qcd(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_qcc(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_poc(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_ppm(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_ppt(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_com(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_unk(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_crg(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_parseopts(char *optstr, jpc_dec_importopts_t *opts);
 
-/******************************************************************************\
-* Global data.
-\******************************************************************************/
 
-jpc_dec_mstabent_t jpc_dec_mstab[] = {
-    {JPC_MS_SOC, JPC_MHSOC, jpc_dec_process_soc},
-    {JPC_MS_SOT, JPC_MH | JPC_TPHSOT, jpc_dec_process_sot},
-    {JPC_MS_SOD, JPC_TPH, jpc_dec_process_sod},
-    {JPC_MS_EOC, JPC_TPHSOT, jpc_dec_process_eoc},
-    {JPC_MS_SIZ, JPC_MHSIZ, jpc_dec_process_siz},
-    {JPC_MS_COD, JPC_MH | JPC_TPH, jpc_dec_process_cod},
-    {JPC_MS_COC, JPC_MH | JPC_TPH, jpc_dec_process_coc},
-    {JPC_MS_RGN, JPC_MH | JPC_TPH, jpc_dec_process_rgn},
-    {JPC_MS_QCD, JPC_MH | JPC_TPH, jpc_dec_process_qcd},
-    {JPC_MS_QCC, JPC_MH | JPC_TPH, jpc_dec_process_qcc},
-    {JPC_MS_POC, JPC_MH | JPC_TPH, jpc_dec_process_poc},
-    {JPC_MS_TLM, JPC_MH, 0},
-    {JPC_MS_PLM, JPC_MH, 0},
-    {JPC_MS_PLT, JPC_TPH, 0},
-    {JPC_MS_PPM, JPC_MH, jpc_dec_process_ppm},
-    {JPC_MS_PPT, JPC_TPH, jpc_dec_process_ppt},
-    {JPC_MS_SOP, 0, 0},
-    {JPC_MS_CRG, JPC_MH, jpc_dec_process_crg},
-    {JPC_MS_COM, JPC_MH | JPC_TPH, jpc_dec_process_com},
-    {0, JPC_MH | JPC_TPH, jpc_dec_process_unk}
-};
 
-/*****************************************************************************\
-* The main entry point for the JPEG-2000 decoder.
-\*****************************************************************************/
+static void
+jpc_dec_tiledecode(jpc_dec_t *      const dec,
+                   jpc_dec_tile_t * const tile,
+                   const char **    const errorP) {
 
-jas_image_t *jpc_decode(jas_stream_t *in, char *optstr)
-{
-    jpc_dec_importopts_t opts;
-    jpc_dec_t *dec;
-    jas_image_t *image;
+    int i;
+    int j;
+    jpc_dec_tcomp_t *tcomp;
+    jpc_dec_rlvl_t *rlvl;
+    jpc_dec_band_t *band;
+    int compno;
+    int rlvlno;
+    int bandno;
+    int adjust;
+    int v;
+    jpc_dec_ccp_t *ccp;
+    jpc_dec_cmpt_t *cmpt;
+    const char * error;
 
-    dec = 0;
+    jpc_dec_decodecblks(dec, tile, &error);
 
-    if (jpc_dec_parseopts(optstr, &opts)) {
-        goto error;
+    if (error) {
+        pm_asprintf(errorP, "jpc_dec_decodecblks failed.  %s", error);
+        return;
     }
 
-    jpc_initluts();
+    /* Perform dequantization. */
+    for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps;
+         ++compno, ++tcomp) {
+        ccp = &tile->cp->ccps[compno];
+        for (rlvlno = 0, rlvl = tcomp->rlvls; rlvlno < tcomp->numrlvls;
+             ++rlvlno, ++rlvl) {
+            if (!rlvl->bands) {
+                continue;
+            }
+            for (bandno = 0, band = rlvl->bands;
+                 bandno < rlvl->numbands; ++bandno, ++band) {
+                if (!band->data) {
+                    continue;
+                }
+                jpc_undo_roi(band->data, band->roishift, ccp->roishift -
+                             band->roishift, band->numbps);
+                if (tile->realmode) {
+                    jas_matrix_asl(band->data, JPC_FIX_FRACBITS);
+                    jpc_dequantize(band->data, band->absstepsize);
+                }
 
-    if (!(dec = jpc_dec_create(&opts, in))) {
-        goto error;
+            }
+        }
     }
 
-    /* Do most of the work. */
-    if (jpc_dec_decode(dec)) {
-        goto error;
+    /* Apply an inverse wavelet transform if necessary. */
+    for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps;
+         ++compno, ++tcomp) {
+        ccp = &tile->cp->ccps[compno];
+        jpc_tsfb_synthesize(tcomp->tsfb,
+                            ((ccp->qmfbid ==
+                              JPC_COX_RFT) ? JPC_TSFB_RITIMODE : 0),
+                            tcomp->data);
     }
 
-    if (jas_image_numcmpts(dec->image) >= 3) {
-        jas_image_setcolorspace(dec->image, JAS_IMAGE_CS_RGB);
-        jas_image_setcmpttype(dec->image, 0,
-          JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_R));
-        jas_image_setcmpttype(dec->image, 1,
-          JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_G));
-        jas_image_setcmpttype(dec->image, 2,
-          JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_B));
-    } else {
-        jas_image_setcolorspace(dec->image, JAS_IMAGE_CS_GRAY);
-        jas_image_setcmpttype(dec->image, 0,
-          JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_GRAY_Y));
+
+    /* Apply an inverse intercomponent transform if necessary. */
+    switch (tile->cp->mctid) {
+    case JPC_MCT_RCT:
+        assert(dec->numcomps == 3);
+        jpc_irct(tile->tcomps[0].data, tile->tcomps[1].data,
+                 tile->tcomps[2].data);
+        break;
+    case JPC_MCT_ICT:
+        assert(dec->numcomps == 3);
+        jpc_iict(tile->tcomps[0].data, tile->tcomps[1].data,
+                 tile->tcomps[2].data);
+        break;
     }
 
-    /* Save the return value. */
-    image = dec->image;
+    /* Perform rounding and convert to integer values. */
+    if (tile->realmode) {
+        for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps;
+             ++compno, ++tcomp) {
+            for (i = 0; i < jas_matrix_numrows(tcomp->data); ++i) {
+                for (j = 0; j < jas_matrix_numcols(tcomp->data); ++j) {
+                    v = jas_matrix_get(tcomp->data, i, j);
+                    v = jpc_fix_round(v);
+                    jas_matrix_set(tcomp->data, i, j, jpc_fixtoint(v));
+                }
+            }
+        }
+    }
 
-    /* Stop the image from being discarded. */
-    dec->image = 0;
+    /* Perform level shift. */
+    for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno <
+             dec->numcomps; ++compno, ++tcomp, ++cmpt) {
+        adjust = cmpt->sgnd ? 0 : (1 << (cmpt->prec - 1));
+        for (i = 0; i < jas_matrix_numrows(tcomp->data); ++i) {
+            for (j = 0; j < jas_matrix_numcols(tcomp->data); ++j) {
+                *jas_matrix_getref(tcomp->data, i, j) += adjust;
+            }
+        }
+    }
 
-    /* Destroy decoder. */
-    jpc_dec_destroy(dec);
+    /* Perform clipping. */
+    for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno <
+             dec->numcomps; ++compno, ++tcomp, ++cmpt) {
+        jpc_fix_t mn;
+        jpc_fix_t mx;
+        mn = cmpt->sgnd ? (-(1 << (cmpt->prec - 1))) : (0);
+        mx = cmpt->sgnd ? ((1 << (cmpt->prec - 1)) - 1) : ((1 <<
+                                                            cmpt->prec) - 1);
+        jas_matrix_clip(tcomp->data, mn, mx);
+    }
 
-    return image;
+    /* XXX need to free tsfb struct */
 
-error:
-    if (dec) {
-        jpc_dec_destroy(dec);
+    /* Write the data for each component of the image. */
+    for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno <
+             dec->numcomps; ++compno, ++tcomp, ++cmpt) {
+        if (jas_image_writecmpt(dec->image, compno, tcomp->xstart -
+                                JPC_CEILDIV(dec->xstart, cmpt->hstep),
+                                tcomp->ystart -
+                                JPC_CEILDIV(dec->ystart, cmpt->vstep),
+                                jas_matrix_numcols(
+                                    tcomp->data),
+                                jas_matrix_numrows(tcomp->data),
+                                tcomp->data)) {
+            pm_asprintf(errorP, "write component failed");
+            return;
+        }
     }
-    return 0;
+    *errorP = NULL;
 }
 
+
+
+static void
+jpc_dec_process_sod(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
+    jpc_dec_tile_t *tile;
+    int pos;
+
+    if (!(tile = dec->curtile)) {
+        pm_asprintf(errorP, "No current tile");
+        return;
+    }
+
+    if (!tile->partno) {
+        if (!jpc_dec_cp_isvalid(tile->cp)) {
+            pm_asprintf(errorP, "CP is not valid");
+            return;
+        }
+        if (jpc_dec_cp_prepare(tile->cp)) {
+            pm_asprintf(errorP, "fpc_dec_cp_prepare failed");
+            return;
+        }
+        if (jpc_dec_tileinit(dec, tile)) {
+            pm_asprintf(errorP, "jpc_dec_tileinit failed");
+            return;
+        }
+    }
+
+    /* Are packet headers stored in the main header or tile-part header? */
+    if (dec->pkthdrstreams) {
+        /* Get the stream containing the packet header data for this
+          tile-part. */
+        if (!(tile->pkthdrstream = jpc_streamlist_remove(dec->pkthdrstreams, 0))) {
+            pm_asprintf(errorP, "jpc_streamlist_remove failed");
+            return;
+        }
+    }
+
+    if (tile->pptstab) {
+        if (!tile->pkthdrstream) {
+            if (!(tile->pkthdrstream = jas_stream_memopen(0, 0))) {
+                pm_asprintf(errorP, "jas_stream_memopen failed");
+                return;
+            }
+        }
+        pos = jas_stream_tell(tile->pkthdrstream);
+        jas_stream_seek(tile->pkthdrstream, 0, SEEK_END);
+        if (jpc_pptstabwrite(tile->pkthdrstream, tile->pptstab)) {
+            pm_asprintf(errorP, "jpc_pptstabwrite failed");
+            return;
+        }
+        jas_stream_seek(tile->pkthdrstream, pos, SEEK_SET);
+        jpc_ppxstab_destroy(tile->pptstab);
+        tile->pptstab = 0;
+    }
+
+    if (jas_getdbglevel() >= 10) {
+        jpc_dec_dump(dec, stderr);
+    }
+
+    if (jpc_dec_decodepkts(dec, (tile->pkthdrstream) ? tile->pkthdrstream :
+      dec->in, dec->in)) {
+        pm_asprintf(errorP, "jpc_dec_decodepkts failed");
+        return;
+    }
+
+    /* Gobble any unconsumed tile data. */
+    if (dec->curtileendoff > 0) {
+        uint_fast32_t curoff;
+        uint_fast32_t n;
+        curoff = jas_stream_getrwcount(dec->in);
+        if (curoff < dec->curtileendoff) {
+            n = dec->curtileendoff - curoff;
+            pm_message("warning: ignoring trailing garbage (%lu bytes)",
+                       (unsigned long) n);
+
+            while (n-- > 0) {
+                if (jas_stream_getc(dec->in) == EOF) {
+                    pm_asprintf(errorP, "read error");
+                    return;
+                }
+            }
+        } else if (curoff > dec->curtileendoff) {
+            pm_message("warning: not enough tile data (%lu bytes)",
+                       (unsigned long) curoff - dec->curtileendoff);
+        }
+    }
+
+    if (tile->numparts > 0 && tile->partno == tile->numparts - 1) {
+        const char * error;
+        jpc_dec_tiledecode(dec, tile, &error);
+        if (error) {
+            pm_asprintf(errorP, "jpc_dec_tiledecode failed.  %s", error);
+            pm_strfree(error);
+            return;
+        }
+        jpc_dec_tilefini(dec, tile);
+    }
+
+    dec->curtile = 0;
+
+    /* Increment the expected tile-part number. */
+    ++tile->partno;
+
+    /* We should expect to encounter a SOT marker segment next. */
+    dec->state = JPC_TPHSOT;
+
+    *errorP = NULL;
+}
+
+
+
 typedef enum {
     OPT_MAXLYRS,
     OPT_MAXPKTS,
@@ -349,7 +494,8 @@ jas_taginfo_t decopts[] = {
     {-1, 0}
 };
 
-static int jpc_dec_parseopts(char *optstr, jpc_dec_importopts_t *opts)
+static int
+jpc_dec_parseopts(const char *optstr, jpc_dec_importopts_t *opts)
 {
     jas_tvparser_t *tvp;
 
@@ -374,8 +520,8 @@ static int jpc_dec_parseopts(char *optstr, jpc_dec_importopts_t *opts)
             opts->maxpkts = atoi(jas_tvparser_getval(tvp));
             break;
         default:
-            fprintf(stderr, "warning: ignoring invalid option %s\n",
-              jas_tvparser_gettag(tvp));
+            pm_message("warning: ignoring invalid option %s",
+                       jas_tvparser_gettag(tvp));
             break;
         }
     }
@@ -385,79 +531,14 @@ static int jpc_dec_parseopts(char *optstr, jpc_dec_importopts_t *opts)
     return 0;
 }
 
-/******************************************************************************\
-* Code for table-driven code stream decoder.
-\******************************************************************************/
-
-static jpc_dec_mstabent_t *jpc_dec_mstab_lookup(uint_fast16_t id)
-{
-    jpc_dec_mstabent_t *mstabent;
-    for (mstabent = jpc_dec_mstab; mstabent->id != 0; ++mstabent) {
-        if (mstabent->id == id) {
-            break;
-        }
-    }
-    return mstabent;
-}
-
-static int jpc_dec_decode(jpc_dec_t *dec)
-{
-    jpc_ms_t *ms;
-    jpc_dec_mstabent_t *mstabent;
-    int ret;
-    jpc_cstate_t *cstate;
-
-    if (!(cstate = jpc_cstate_create())) {
-        return -1;
-    }
-    dec->cstate = cstate;
-
-    /* Initially, we should expect to encounter a SOC marker segment. */
-    dec->state = JPC_MHSOC;
-
-    for (;;) {
-
-        /* Get the next marker segment in the code stream. */
-        if (!(ms = jpc_getms(dec->in, cstate))) {
-            fprintf(stderr, "cannot get marker segment\n");
-            return -1;
-        }
-
-        mstabent = jpc_dec_mstab_lookup(ms->id);
-        assert(mstabent);
-
-        /* Ensure that this type of marker segment is permitted
-          at this point in the code stream. */
-        if (!(dec->state & mstabent->validstates)) {
-            fprintf(stderr, "unexpected marker segment type\n");
-            jpc_ms_destroy(ms);
-            return -1;
-        }
-
-        /* Process the marker segment. */
-        if (mstabent->action) {
-            ret = (*mstabent->action)(dec, ms);
-        } else {
-            /* No explicit action is required. */
-            ret = 0;
-        }
-
-        /* Destroy the marker segment. */
-        jpc_ms_destroy(ms);
-
-        if (ret < 0) {
-            return -1;
-        } else if (ret > 0) {
-            break;
-        }
 
-    }
 
-    return 0;
-}
+static void
+jpc_dec_process_crg(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
 
-static int jpc_dec_process_crg(jpc_dec_t *dec, jpc_ms_t *ms)
-{
     /* Ignore the information in the CRG marker segment for now.
        This information serves no useful purpose for decoding anyhow.
        Some other parts of the code need to be changed if these lines
@@ -475,19 +556,33 @@ static int jpc_dec_process_crg(jpc_dec_t *dec, jpc_ms_t *ms)
         cmpt->vsubstep = crg->comps[cmptno].voff;
     }
 #endif
-    return 0;
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_soc(jpc_dec_t *dec, jpc_ms_t *ms)
-{
+
+
+static void
+jpc_dec_process_soc(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
     /* We should expect to encounter a SIZ marker segment next. */
     dec->state = JPC_MHSIZ;
 
-    return 0;
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_sot(jpc_dec_t *dec, jpc_ms_t *ms)
-{
+
+
+static void
+jpc_dec_process_sot(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
     jpc_dec_tile_t *tile;
     jpc_sot_t *sot = &ms->parms.sot;
     jas_image_cmptparm_t *compinfos;
@@ -512,8 +607,9 @@ static int jpc_dec_process_sot(jpc_dec_t *dec, jpc_ms_t *ms)
         }
 
         if (!(dec->image = jas_image_create(dec->numcomps, compinfos,
-          JAS_IMAGE_CS_UNKNOWN))) {
-            return -1;
+                                            JAS_IMAGE_CS_UNKNOWN))) {
+            pm_asprintf(errorP, "jas_image_create failed");
+            return;
         }
         jas_free(compinfos);
 
@@ -538,18 +634,20 @@ static int jpc_dec_process_sot(jpc_dec_t *dec, jpc_ms_t *ms)
     }
 
     if (sot->tileno > dec->numtiles) {
-        fprintf(stderr, "invalid tile number in SOT marker segment\n");
-        return -1;
+        pm_asprintf(errorP, "invalid tile number in SOT marker segment");
+        return;
     }
     /* Set the current tile. */
     dec->curtile = &dec->tiles[sot->tileno];
     tile = dec->curtile;
     /* Ensure that this is the expected part number. */
     if (sot->partno != tile->partno) {
-        return -1;
+        pm_asprintf(errorP, "Unexpected part number");
+        return;
     }
     if (tile->numparts > 0 && sot->partno >= tile->numparts) {
-        return -1;
+        pm_asprintf(errorP, "part number greater than number of parts");
+        return;
     }
     if (!tile->numparts && sot->numparts > 0) {
         tile->numparts = sot->numparts;
@@ -563,7 +661,8 @@ static int jpc_dec_process_sot(jpc_dec_t *dec, jpc_ms_t *ms)
         tile->state = JPC_TILE_ACTIVE;
         assert(!tile->cp);
         if (!(tile->cp = jpc_dec_cp_copy(dec->cp))) {
-            return -1;
+            pm_asprintf(errorP, "jpc_dec_cp_copy failed");
+            return;
         }
         jpc_dec_cp_resetflags(dec->cp);
         break;
@@ -581,107 +680,11 @@ static int jpc_dec_process_sot(jpc_dec_t *dec, jpc_ms_t *ms)
       segments next. */
     dec->state = JPC_TPH;
 
-    return 0;
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_sod(jpc_dec_t *dec, jpc_ms_t *ms)
-{
-    jpc_dec_tile_t *tile;
-    int pos;
-
-    if (!(tile = dec->curtile)) {
-        return -1;
-    }
-
-    if (!tile->partno) {
-        if (!jpc_dec_cp_isvalid(tile->cp)) {
-            return -1;
-        }
-        if (jpc_dec_cp_prepare(tile->cp)) {
-            return -1;
-        }
-        if (jpc_dec_tileinit(dec, tile)) {
-            return -1;
-        }
-    }
-
-    /* Are packet headers stored in the main header or tile-part header? */
-    if (dec->pkthdrstreams) {
-        /* Get the stream containing the packet header data for this
-          tile-part. */
-        if (!(tile->pkthdrstream = jpc_streamlist_remove(dec->pkthdrstreams, 0))) {
-            return -1;
-        }
-    }
-
-    if (tile->pptstab) {
-        if (!tile->pkthdrstream) {
-            if (!(tile->pkthdrstream = jas_stream_memopen(0, 0))) {
-                return -1;
-            }
-        }
-        pos = jas_stream_tell(tile->pkthdrstream);
-        jas_stream_seek(tile->pkthdrstream, 0, SEEK_END);
-        if (jpc_pptstabwrite(tile->pkthdrstream, tile->pptstab)) {
-            return -1;
-        }
-        jas_stream_seek(tile->pkthdrstream, pos, SEEK_SET);
-        jpc_ppxstab_destroy(tile->pptstab);
-        tile->pptstab = 0;
-    }
-
-    if (jas_getdbglevel() >= 10) {
-        jpc_dec_dump(dec, stderr);
-    }
-
-    if (jpc_dec_decodepkts(dec, (tile->pkthdrstream) ? tile->pkthdrstream :
-      dec->in, dec->in)) {
-        fprintf(stderr, "jpc_dec_decodepkts failed\n");
-        return -1;
-    }
-
-    /* Gobble any unconsumed tile data. */
-    if (dec->curtileendoff > 0) {
-        uint_fast32_t curoff;
-        uint_fast32_t n;
-        curoff = jas_stream_getrwcount(dec->in);
-        if (curoff < dec->curtileendoff) {
-            n = dec->curtileendoff - curoff;
-            fprintf(stderr,
-              "warning: ignoring trailing garbage (%lu bytes)\n",
-              (unsigned long) n);
-
-            while (n-- > 0) {
-                if (jas_stream_getc(dec->in) == EOF) {
-                    fprintf(stderr, "read error\n");
-                    return -1;
-                }
-            }
-        } else if (curoff > dec->curtileendoff) {
-            fprintf(stderr,
-              "warning: not enough tile data (%lu bytes)\n",
-              (unsigned long) curoff - dec->curtileendoff);
-        }
-
-    }
-
-    if (tile->numparts > 0 && tile->partno == tile->numparts - 1) {
-        if (jpc_dec_tiledecode(dec, tile)) {
-            return -1;
-        }
-        jpc_dec_tilefini(dec, tile);
-    }
-
-    dec->curtile = 0;
-
-    /* Increment the expected tile-part number. */
-    ++tile->partno;
-
-    /* We should expect to encounter a SOT marker segment next. */
-    dec->state = JPC_TPHSOT;
 
-    return 0;
-}
 
 static int jpc_dec_tileinit(jpc_dec_t *dec, jpc_dec_tile_t *tile)
 {
@@ -1059,136 +1062,25 @@ if (!prc->cblks) {
     return 0;
 }
 
-static int jpc_dec_tiledecode(jpc_dec_t *dec, jpc_dec_tile_t *tile)
-{
-    int i;
-    int j;
-    jpc_dec_tcomp_t *tcomp;
-    jpc_dec_rlvl_t *rlvl;
-    jpc_dec_band_t *band;
-    int compno;
-    int rlvlno;
-    int bandno;
-    int adjust;
-    int v;
-    jpc_dec_ccp_t *ccp;
-    jpc_dec_cmpt_t *cmpt;
 
-    if (jpc_dec_decodecblks(dec, tile)) {
-        fprintf(stderr, "jpc_dec_decodecblks failed\n");
-        return -1;
-    }
 
-    /* Perform dequantization. */
-    for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps;
-      ++compno, ++tcomp) {
-        ccp = &tile->cp->ccps[compno];
-        for (rlvlno = 0, rlvl = tcomp->rlvls; rlvlno < tcomp->numrlvls;
-          ++rlvlno, ++rlvl) {
-            if (!rlvl->bands) {
-                continue;
-            }
-            for (bandno = 0, band = rlvl->bands;
-              bandno < rlvl->numbands; ++bandno, ++band) {
-                if (!band->data) {
-                    continue;
-                }
-                jpc_undo_roi(band->data, band->roishift, ccp->roishift -
-                  band->roishift, band->numbps);
-                if (tile->realmode) {
-                    jas_matrix_asl(band->data, JPC_FIX_FRACBITS);
-                    jpc_dequantize(band->data, band->absstepsize);
-                }
+static void
+jpc_dec_process_eoc(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
 
-            }
-        }
-    }
-
-    /* Apply an inverse wavelet transform if necessary. */
-    for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps;
-      ++compno, ++tcomp) {
-        ccp = &tile->cp->ccps[compno];
-        jpc_tsfb_synthesize(tcomp->tsfb, ((ccp->qmfbid ==
-          JPC_COX_RFT) ? JPC_TSFB_RITIMODE : 0), tcomp->data);
-    }
-
-
-    /* Apply an inverse intercomponent transform if necessary. */
-    switch (tile->cp->mctid) {
-    case JPC_MCT_RCT:
-        assert(dec->numcomps == 3);
-        jpc_irct(tile->tcomps[0].data, tile->tcomps[1].data,
-          tile->tcomps[2].data);
-        break;
-    case JPC_MCT_ICT:
-        assert(dec->numcomps == 3);
-        jpc_iict(tile->tcomps[0].data, tile->tcomps[1].data,
-          tile->tcomps[2].data);
-        break;
-    }
-
-    /* Perform rounding and convert to integer values. */
-    if (tile->realmode) {
-        for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps;
-          ++compno, ++tcomp) {
-            for (i = 0; i < jas_matrix_numrows(tcomp->data); ++i) {
-                for (j = 0; j < jas_matrix_numcols(tcomp->data); ++j) {
-                    v = jas_matrix_get(tcomp->data, i, j);
-                    v = jpc_fix_round(v);
-                    jas_matrix_set(tcomp->data, i, j, jpc_fixtoint(v));
-                }
-            }
-        }
-    }
-
-    /* Perform level shift. */
-    for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno <
-      dec->numcomps; ++compno, ++tcomp, ++cmpt) {
-        adjust = cmpt->sgnd ? 0 : (1 << (cmpt->prec - 1));
-        for (i = 0; i < jas_matrix_numrows(tcomp->data); ++i) {
-            for (j = 0; j < jas_matrix_numcols(tcomp->data); ++j) {
-                *jas_matrix_getref(tcomp->data, i, j) += adjust;
-            }
-        }
-    }
-
-    /* Perform clipping. */
-    for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno <
-      dec->numcomps; ++compno, ++tcomp, ++cmpt) {
-        jpc_fix_t mn;
-        jpc_fix_t mx;
-        mn = cmpt->sgnd ? (-(1 << (cmpt->prec - 1))) : (0);
-        mx = cmpt->sgnd ? ((1 << (cmpt->prec - 1)) - 1) : ((1 <<
-          cmpt->prec) - 1);
-        jas_matrix_clip(tcomp->data, mn, mx);
-    }
-
-    /* XXX need to free tsfb struct */
-
-    /* Write the data for each component of the image. */
-    for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno <
-      dec->numcomps; ++compno, ++tcomp, ++cmpt) {
-        if (jas_image_writecmpt(dec->image, compno, tcomp->xstart -
-          JPC_CEILDIV(dec->xstart, cmpt->hstep), tcomp->ystart -
-          JPC_CEILDIV(dec->ystart, cmpt->vstep), jas_matrix_numcols(
-          tcomp->data), jas_matrix_numrows(tcomp->data), tcomp->data)) {
-            fprintf(stderr, "write component failed\n");
-            return -4;
-        }
-    }
-
-    return 0;
-}
-
-static int jpc_dec_process_eoc(jpc_dec_t *dec, jpc_ms_t *ms)
-{
     int tileno;
     jpc_dec_tile_t *tile;
     for (tileno = 0, tile = dec->tiles; tileno < dec->numtiles; ++tileno,
       ++tile) {
         if (tile->state == JPC_TILE_ACTIVE) {
-            if (jpc_dec_tiledecode(dec, tile)) {
-                return -1;
+            const char * error;
+            jpc_dec_tiledecode(dec, tile, &error);
+            if (error) {
+                pm_asprintf(errorP, "jpc_dec_tiledecode failed.  %s", error);
+                pm_strfree(error);
+                return;
             }
         }
         jpc_dec_tilefini(dec, tile);
@@ -1197,11 +1089,17 @@ static int jpc_dec_process_eoc(jpc_dec_t *dec, jpc_ms_t *ms)
     /* We are done processing the code stream. */
     dec->state = JPC_MT;
 
-    return 1;
+    *doneP = true;
 }
 
-static int jpc_dec_process_siz(jpc_dec_t *dec, jpc_ms_t *ms)
-{
+
+
+static void
+jpc_dec_process_siz(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
     jpc_siz_t *siz = &ms->parms.siz;
     uint_fast16_t compno;
     uint_fast32_t tileno;
@@ -1221,11 +1119,13 @@ static int jpc_dec_process_siz(jpc_dec_t *dec, jpc_ms_t *ms)
     dec->tileyoff = siz->tileyoff;
     dec->numcomps = siz->numcomps;
     if (!(dec->cp = jpc_dec_cp_create(dec->numcomps))) {
-        return -1;
+        pm_asprintf(errorP, "jpc_dec_cp_create failed");
+        return;
     }
 
     if (!(dec->cmpts = jas_malloc(dec->numcomps * sizeof(jpc_dec_cmpt_t)))) {
-        return -1;
+        pm_asprintf(errorP, "jas_malloc failed");
+        return;
     }
 
     for (compno = 0, cmpt = dec->cmpts; compno < dec->numcomps; ++compno,
@@ -1248,7 +1148,8 @@ static int jpc_dec_process_siz(jpc_dec_t *dec, jpc_ms_t *ms)
     dec->numvtiles = JPC_CEILDIV(dec->yend - dec->tileyoff, dec->tileheight);
     dec->numtiles = dec->numhtiles * dec->numvtiles;
     if (!(dec->tiles = jas_malloc(dec->numtiles * sizeof(jpc_dec_tile_t)))) {
-        return -1;
+        pm_asprintf(errorP, "jas_malloc failed");
+        return;
     }
 
     for (tileno = 0, tile = dec->tiles;
@@ -1280,9 +1181,10 @@ static int jpc_dec_process_siz(jpc_dec_t *dec, jpc_ms_t *ms)
         tile->pkthdrstreampos = 0;
         tile->pptstab = 0;
         tile->cp = 0;
-        if (!(tile->tcomps = jas_malloc(dec->numcomps *
-          sizeof(jpc_dec_tcomp_t)))) {
-            return -1;
+        tile->tcomps = jas_malloc(dec->numcomps * sizeof(jpc_dec_tcomp_t));
+        if (!tile->tcomps) {
+            pm_asprintf(errorP, "jas_malloc failed");
+            return;
         }
         for (compno = 0, cmpt = dec->cmpts, tcomp = tile->tcomps;
           compno < dec->numcomps; ++compno, ++cmpt, ++tcomp) {
@@ -1302,11 +1204,18 @@ static int jpc_dec_process_siz(jpc_dec_t *dec, jpc_ms_t *ms)
       or an SOT marker segment next. */
     dec->state = JPC_MH;
 
-    return 0;
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_cod(jpc_dec_t *dec, jpc_ms_t *ms)
-{
+
+
+static void
+jpc_dec_process_cod(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
     jpc_cod_t *cod = &ms->parms.cod;
     jpc_dec_tile_t *tile;
 
@@ -1316,26 +1225,34 @@ static int jpc_dec_process_cod(jpc_dec_t *dec, jpc_ms_t *ms)
         break;
     case JPC_TPH:
         if (!(tile = dec->curtile)) {
-            return -1;
+            pm_asprintf(errorP, "No current tile");
+            return;
         }
         if (tile->partno != 0) {
-            return -1;
+            pm_asprintf(errorP, "part number is not zero");
+            return;
         }
         jpc_dec_cp_setfromcod(tile->cp, cod);
         break;
     }
-    return 0;
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_coc(jpc_dec_t *dec, jpc_ms_t *ms)
-{
+
+
+static void
+jpc_dec_process_coc(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
     jpc_coc_t *coc = &ms->parms.coc;
     jpc_dec_tile_t *tile;
 
     if (coc->compno > dec->numcomps) {
-        fprintf(stderr,
-          "invalid component number in COC marker segment\n");
-        return -1;
+        pm_asprintf(errorP, "invalid component number in COC marker segment");
+        return;
     }
     switch (dec->state) {
     case JPC_MH:
@@ -1343,26 +1260,34 @@ static int jpc_dec_process_coc(jpc_dec_t *dec, jpc_ms_t *ms)
         break;
     case JPC_TPH:
         if (!(tile = dec->curtile)) {
-            return -1;
+            pm_asprintf(errorP, "No current tile");
+            return;
         }
         if (tile->partno > 0) {
-            return -1;
+            pm_asprintf(errorP, "Part number is not zero");
+            return;
         }
         jpc_dec_cp_setfromcoc(tile->cp, coc);
         break;
     }
-    return 0;
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_rgn(jpc_dec_t *dec, jpc_ms_t *ms)
-{
+
+
+static void
+jpc_dec_process_rgn(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
     jpc_rgn_t *rgn = &ms->parms.rgn;
     jpc_dec_tile_t *tile;
 
     if (rgn->compno > dec->numcomps) {
-        fprintf(stderr,
-          "invalid component number in RGN marker segment\n");
-        return -1;
+        pm_asprintf(errorP, "invalid component number in RGN marker segment");
+        return;
     }
     switch (dec->state) {
     case JPC_MH:
@@ -1370,20 +1295,29 @@ static int jpc_dec_process_rgn(jpc_dec_t *dec, jpc_ms_t *ms)
         break;
     case JPC_TPH:
         if (!(tile = dec->curtile)) {
-            return -1;
+            pm_asprintf(errorP, "No current tile");
+            return;
         }
         if (tile->partno > 0) {
-            return -1;
+            pm_asprintf(errorP, "Part number is not zero");
+            return;
         }
         jpc_dec_cp_setfromrgn(tile->cp, rgn);
         break;
     }
 
-    return 0;
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_qcd(jpc_dec_t *dec, jpc_ms_t *ms)
-{
+
+
+static void
+jpc_dec_process_qcd(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
     jpc_qcd_t *qcd = &ms->parms.qcd;
     jpc_dec_tile_t *tile;
 
@@ -1393,26 +1327,34 @@ static int jpc_dec_process_qcd(jpc_dec_t *dec, jpc_ms_t *ms)
         break;
     case JPC_TPH:
         if (!(tile = dec->curtile)) {
-            return -1;
+            pm_asprintf(errorP, "No current tile");
+            return;
         }
         if (tile->partno > 0) {
-            return -1;
+            pm_asprintf(errorP, "Part number is not zero");
+            return;
         }
         jpc_dec_cp_setfromqcd(tile->cp, qcd);
         break;
     }
-    return 0;
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_qcc(jpc_dec_t *dec, jpc_ms_t *ms)
-{
+
+
+static void
+jpc_dec_process_qcc(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
     jpc_qcc_t *qcc = &ms->parms.qcc;
     jpc_dec_tile_t *tile;
 
     if (qcc->compno > dec->numcomps) {
-        fprintf(stderr,
-          "invalid component number in QCC marker segment\n");
-        return -1;
+        pm_asprintf(errorP, "invalid component number in QCC marker segment");
+        return;
     }
     switch (dec->state) {
     case JPC_MH:
@@ -1420,69 +1362,98 @@ static int jpc_dec_process_qcc(jpc_dec_t *dec, jpc_ms_t *ms)
         break;
     case JPC_TPH:
         if (!(tile = dec->curtile)) {
-            return -1;
+            pm_asprintf(errorP, "No current tile");
+            return;
         }
         if (tile->partno > 0) {
-            return -1;
+            pm_asprintf(errorP, "Part number is not zero");
+            return;
         }
         jpc_dec_cp_setfromqcc(tile->cp, qcc);
         break;
     }
-    return 0;
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_poc(jpc_dec_t *dec, jpc_ms_t *ms)
-{
+
+
+static void
+jpc_dec_process_poc(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
     jpc_poc_t *poc = &ms->parms.poc;
     jpc_dec_tile_t *tile;
     switch (dec->state) {
     case JPC_MH:
         if (jpc_dec_cp_setfrompoc(dec->cp, poc, 1)) {
-            return -1;
+            pm_asprintf(errorP, "jpc_dec_cp_setfrompoc failed");
+            return;
         }
         break;
     case JPC_TPH:
         if (!(tile = dec->curtile)) {
-            return -1;
+            pm_asprintf(errorP, "No current tile");
+            return;
         }
         if (!tile->partno) {
             if (jpc_dec_cp_setfrompoc(tile->cp, poc, (!tile->partno))) {
-                return -1;
+                pm_asprintf(errorP, "jpc_dec_cp_setfrompoc failed");
+                return;
             }
         } else {
             jpc_pi_addpchgfrompoc(tile->pi, poc);
         }
         break;
     }
-    return 0;
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_ppm(jpc_dec_t *dec, jpc_ms_t *ms)
-{
+
+
+static void
+jpc_dec_process_ppm(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
     jpc_ppm_t *ppm = &ms->parms.ppm;
     jpc_ppxstabent_t *ppmstabent;
 
     if (!dec->ppmstab) {
         if (!(dec->ppmstab = jpc_ppxstab_create())) {
-            return -1;
+            pm_asprintf(errorP, "jpc_ppxstab_create failed");
+            return;
         }
     }
 
     if (!(ppmstabent = jpc_ppxstabent_create())) {
-        return -1;
+        pm_asprintf(errorP, "jpc_ppxstabent_create failed");
+        return;
     }
     ppmstabent->ind = ppm->ind;
     ppmstabent->data = ppm->data;
     ppm->data = 0;
     ppmstabent->len = ppm->len;
     if (jpc_ppxstab_insert(dec->ppmstab, ppmstabent)) {
-        return -1;
+        pm_asprintf(errorP, "jpc_ppxstab_insert failed");
+        return;
     }
-    return 0;
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_ppt(jpc_dec_t *dec, jpc_ms_t *ms)
-{
+
+
+static void
+jpc_dec_process_ppt(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
     jpc_ppt_t *ppt = &ms->parms.ppt;
     jpc_dec_tile_t *tile;
     jpc_ppxstabent_t *pptstabent;
@@ -1490,34 +1461,55 @@ static int jpc_dec_process_ppt(jpc_dec_t *dec, jpc_ms_t *ms)
     tile = dec->curtile;
     if (!tile->pptstab) {
         if (!(tile->pptstab = jpc_ppxstab_create())) {
-            return -1;
+            pm_asprintf(errorP, "jpc_ppxstab_create failed");
+            return;
         }
     }
     if (!(pptstabent = jpc_ppxstabent_create())) {
-        return -1;
+        pm_asprintf(errorP, "jpc_ppxstabent_create failed");
+        return;
     }
     pptstabent->ind = ppt->ind;
     pptstabent->data = ppt->data;
     ppt->data = 0;
     pptstabent->len = ppt->len;
     if (jpc_ppxstab_insert(tile->pptstab, pptstabent)) {
-        return -1;
+        pm_asprintf(errorP, "jpc_ppxstab_insert failed.");
+        return;
     }
-    return 0;
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_com(jpc_dec_t *dec, jpc_ms_t *ms)
-{
-    return 0;
+
+
+static void
+jpc_dec_process_com(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_unk(jpc_dec_t *dec, jpc_ms_t *ms)
-{
-    fprintf(stderr, "warning: ignoring unknown marker segment\n");
+
+
+static void
+jpc_dec_process_unk(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
+    pm_message("warning: ignoring unknown marker segment");
     jpc_ms_dump(ms, stderr);
-    return 0;
+
+    *doneP = false;
+    *errorP = NULL;
 }
 
+
+
 /******************************************************************************\
 *
 \******************************************************************************/
@@ -2370,3 +2362,168 @@ void jpc_ppxstabent_destroy(jpc_ppxstabent_t *ent)
     }
     jas_free(ent);
 }
+
+
+
+jpc_dec_mstabent_t jpc_dec_mstab[] = {
+    {JPC_MS_SOC, JPC_MHSOC, jpc_dec_process_soc},
+    {JPC_MS_SOT, JPC_MH | JPC_TPHSOT, jpc_dec_process_sot},
+    {JPC_MS_SOD, JPC_TPH, jpc_dec_process_sod},
+    {JPC_MS_EOC, JPC_TPHSOT, jpc_dec_process_eoc},
+    {JPC_MS_SIZ, JPC_MHSIZ, jpc_dec_process_siz},
+    {JPC_MS_COD, JPC_MH | JPC_TPH, jpc_dec_process_cod},
+    {JPC_MS_COC, JPC_MH | JPC_TPH, jpc_dec_process_coc},
+    {JPC_MS_RGN, JPC_MH | JPC_TPH, jpc_dec_process_rgn},
+    {JPC_MS_QCD, JPC_MH | JPC_TPH, jpc_dec_process_qcd},
+    {JPC_MS_QCC, JPC_MH | JPC_TPH, jpc_dec_process_qcc},
+    {JPC_MS_POC, JPC_MH | JPC_TPH, jpc_dec_process_poc},
+    {JPC_MS_TLM, JPC_MH, 0},
+    {JPC_MS_PLM, JPC_MH, 0},
+    {JPC_MS_PLT, JPC_TPH, 0},
+    {JPC_MS_PPM, JPC_MH, jpc_dec_process_ppm},
+    {JPC_MS_PPT, JPC_TPH, jpc_dec_process_ppt},
+    {JPC_MS_SOP, 0, 0},
+    {JPC_MS_CRG, JPC_MH, jpc_dec_process_crg},
+    {JPC_MS_COM, JPC_MH | JPC_TPH, jpc_dec_process_com},
+    {0, JPC_MH | JPC_TPH, jpc_dec_process_unk}
+};
+
+
+
+static jpc_dec_mstabent_t *jpc_dec_mstab_lookup(uint_fast16_t id)
+{
+    jpc_dec_mstabent_t *mstabent;
+    for (mstabent = jpc_dec_mstab; mstabent->id != 0; ++mstabent) {
+        if (mstabent->id == id) {
+            break;
+        }
+    }
+    return mstabent;
+}
+
+
+
+static void
+jpc_dec_decode(jpc_dec_t *   const dec,
+               const char ** const errorP) {
+
+    jpc_ms_t *ms;
+    jpc_dec_mstabent_t *mstabent;
+    bool done;
+    jpc_cstate_t *cstate;
+
+    if (!(cstate = jpc_cstate_create())) {
+        pm_asprintf(errorP, "jpc_cstate_create failed");
+        return;
+    }
+    dec->cstate = cstate;
+
+    /* Initially, we should expect to encounter a SOC marker segment. */
+    dec->state = JPC_MHSOC;
+
+    *errorP = NULL;   /* initial value */
+
+    for (;;) {
+
+        /* Get the next marker segment in the code stream. */
+        if (!(ms = jpc_getms(dec->in, cstate))) {
+            pm_asprintf(errorP, "cannot get marker segment");
+            return;
+        }
+
+        mstabent = jpc_dec_mstab_lookup(ms->id);
+        assert(mstabent);
+
+        /* Ensure that this type of marker segment is permitted
+          at this point in the code stream. */
+        if (!(dec->state & mstabent->validstates)) {
+            pm_asprintf(errorP, "unexpected marker segment type");
+            jpc_ms_destroy(ms);
+            return;
+        }
+
+        /* Process the marker segment. */
+        if (mstabent->action) {
+            (*mstabent->action)(dec, ms, &done, errorP);
+        } else {
+            /* No explicit action is required. */
+            *errorP = NULL;
+            done = false;
+        }
+
+        /* Destroy the marker segment. */
+        jpc_ms_destroy(ms);
+
+        if (*errorP) {
+            return;
+        } else if (done) {
+            break;
+        }
+    }
+}
+
+
+
+/*****************************************************************************\
+* The main entry point for the JPEG-2000 decoder.
+\*****************************************************************************/
+
+void
+jpc_decode(jas_stream_t * const in,
+           const char *   const optstr,
+           jas_image_t ** const imagePP,
+           const char **  const errorP) {
+
+    jpc_dec_importopts_t opts;
+    jpc_dec_t *dec;
+    jas_image_t *image;
+    const char * error;
+
+    if (jpc_dec_parseopts(optstr, &opts)) {
+        pm_asprintf(errorP, "jpc_dec_parseopts failed");
+        return;
+    }
+
+    jpc_initluts();
+
+    dec = jpc_dec_create(&opts, in);
+
+    if (!dec) {
+        pm_asprintf(errorP, "jpc_dec_create failed");
+    } else {
+        /* Do most of the work. */
+        jpc_dec_decode(dec, &error);
+        if (error) {
+            pm_asprintf(errorP, "jpc_dec_decode failed.  %s", error);
+            pm_strfree(error);
+        } else {
+            if (jas_image_numcmpts(dec->image) >= 3) {
+                jas_image_setcolorspace(dec->image, JAS_IMAGE_CS_RGB);
+                jas_image_setcmpttype(dec->image, 0,
+                                      JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_R));
+                jas_image_setcmpttype(dec->image, 1,
+                                      JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_G));
+                jas_image_setcmpttype(dec->image, 2,
+                                      JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_B));
+            } else {
+                jas_image_setcolorspace(dec->image, JAS_IMAGE_CS_GRAY);
+                jas_image_setcmpttype(dec->image, 0,
+                                      JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_GRAY_Y));
+            }
+
+            /* Save the return value. */
+            image = dec->image;
+
+            /* Stop the image from being discarded. */
+            dec->image = 0;
+
+            *imagePP = image;
+
+            *errorP = NULL;
+        }
+        jpc_dec_destroy(dec);
+    }
+}
+
+
+
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_dec.h b/converter/other/jpeg2000/libjasper/jpc/jpc_dec.h
index 02c5553d..fe0e9616 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_dec.h
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_dec.h
@@ -236,7 +236,7 @@ typedef struct {
 
 } jpc_dec_ccp_t;
 
-/* Coding paramters. */
+/* Coding parameters. */
 
 typedef struct {
 
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_enc.c b/converter/other/jpeg2000/libjasper/jpc/jpc_enc.c
index 9db41ca2..0c77a94e 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_enc.c
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_enc.c
@@ -69,7 +69,6 @@ static void prc_destroy(jpc_enc_prc_t *prcs);
 static jpc_enc_cblk_t *cblk_create(jpc_enc_cblk_t *cblk, jpc_enc_cp_t *cp,
   jpc_enc_prc_t *prc);
 static void cblk_destroy(jpc_enc_cblk_t *cblks);
-int ratestrtosize(const char *s, uint_fast32_t rawsize, uint_fast32_t *size);
 static void pass_destroy(jpc_enc_pass_t *pass);
 void jpc_enc_dump(jpc_enc_t *enc);
 
@@ -78,17 +77,8 @@ void jpc_enc_dump(jpc_enc_t *enc);
 \*****************************************************************************/
 
 void quantize(jas_matrix_t *data, jpc_fix_t stepsize);
-static int jpc_enc_encodemainhdr(jpc_enc_t *enc);
-static int jpc_enc_encodemainbody(jpc_enc_t *enc);
-int jpc_enc_encodetiledata(jpc_enc_t *enc);
 jpc_enc_t *jpc_enc_create(jpc_enc_cp_t *cp, jas_stream_t *out, jas_image_t *image);
 void jpc_enc_destroy(jpc_enc_t *enc);
-static int jpc_enc_encodemainhdr(jpc_enc_t *enc);
-static int jpc_enc_encodemainbody(jpc_enc_t *enc);
-int jpc_enc_encodetiledata(jpc_enc_t *enc);
-int setins(int numvalues, jpc_flt_t *values, jpc_flt_t value);
-static jpc_enc_cp_t *cp_create(char *optstr, jas_image_t *image);
-void jpc_enc_cp_destroy(jpc_enc_cp_t *cp);
 
 
 
@@ -143,7 +133,6 @@ typedef enum {
     OPT_NUMGBITS,
     OPT_RATE,
     OPT_ILYRRATES,
-    OPT_JP2OVERHEAD
 } optid_t;
 
 jas_taginfo_t encopts[] = {
@@ -173,7 +162,6 @@ jas_taginfo_t encopts[] = {
     {OPT_NUMGBITS, "numgbits"},
     {OPT_RATE, "rate"},
     {OPT_ILYRRATES, "ilyrrates"},
-    {OPT_JP2OVERHEAD, "_jp2overhead"},
     {-1, 0}
 };
 
@@ -230,72 +218,46 @@ trace(const char * const fmt, ...) {
 
 
 
-int
-jpc_encode(jas_image_t *image, jas_stream_t *out, char *optstr) {
-
-    jpc_enc_t *enc;
-    jpc_enc_cp_t *cp;
-
-    enc = 0;
-    cp = 0;
-
-    jpc_initluts();
-
-    if (!(cp = cp_create(optstr, image))) {
-        fprintf(stderr, "invalid JP encoder options\n");
-        goto error;
-    }
-
-    if (!(enc = jpc_enc_create(cp, out, image))) {
-        goto error;
-    }
-    cp = 0;
+/*****************************************************************************\
+* Option parsing code.
+\*****************************************************************************/
 
-    /* Encode the main header. */
-    if (jpc_enc_encodemainhdr(enc)) {
-        goto error;
-    }
+static void
+ratestrtosize(const char *    const s,
+              uint_fast32_t   const rawsize,
+              uint_fast32_t * const sizeP) {
 
-    /* Encode the main body.  This constitutes most of the encoding work. */
-    if (jpc_enc_encodemainbody(enc)) {
-        goto error;
-    }
+    if (strchr(s, 'B')) {
+        *sizeP = atoi(s);
+    } else {
+        jpc_flt_t const f = atof(s);
 
-    /* Write EOC marker segment. */
-    if (!(enc->mrk = jpc_ms_create(JPC_MS_EOC))) {
-        goto error;
-    }
-    if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
-        fprintf(stderr, "cannot write EOI marker\n");
-        goto error;
+        if (f < 0) {
+            *sizeP = 0;
+        } else if (f > 1.0) {
+            *sizeP = rawsize + 1;
+        } else {
+            *sizeP = f * rawsize;
+        }
     }
-    jpc_ms_destroy(enc->mrk);
-    enc->mrk = 0;
+}
 
-    if (jas_stream_flush(enc->out)) {
-        goto error;
-    }
 
-    jpc_enc_destroy(enc);
 
-    return 0;
+static void
+cp_destroy(jpc_enc_cp_t *cp) {
 
-error:
-    if (cp) {
-        jpc_enc_cp_destroy(cp);
-    }
-    if (enc) {
-        jpc_enc_destroy(enc);
+    if (cp->ccps) {
+        if (cp->tcp.ilyrrates) {
+            jas_free(cp->tcp.ilyrrates);
+        }
+        jas_free(cp->ccps);
     }
-    return -1;
+    jas_free(cp);
 }
 
 
 
-/*****************************************************************************\
-* Option parsing code.
-\*****************************************************************************/
-
 static jpc_enc_cp_t *
 cp_create(char *optstr, jas_image_t *image) {
 
@@ -314,7 +276,6 @@ cp_create(char *optstr, jas_image_t *image) {
     uint_fast16_t prcwidthexpn;
     uint_fast16_t prcheightexpn;
     bool enablemct;
-    uint_fast32_t jp2overhead;
     uint_fast16_t lyrno;
     uint_fast32_t hsteplcm;
     uint_fast32_t vsteplcm;
@@ -332,7 +293,6 @@ cp_create(char *optstr, jas_image_t *image) {
     prcwidthexpn = 15;
     prcheightexpn = 15;
     enablemct = true;
-    jp2overhead = 0;
 
     cp->ccps = 0;
     cp->debug = 0;
@@ -380,6 +340,10 @@ cp_create(char *optstr, jas_image_t *image) {
 
     cp->rawsize = jas_image_rawsize(image);
     cp->totalsize = UINT_FAST32_MAX;
+        /* Set default value, the special value that means size is unlimited
+           (so lossless coding is called for).  To be overridden if user
+           specified
+        */
 
     tcp = &cp->tcp;
     tcp->csty = 0;
@@ -492,12 +456,8 @@ cp_create(char *optstr, jas_image_t *image) {
             cp->tccp.numgbits = atoi(jas_tvparser_getval(tvp));
             break;
         case OPT_RATE:
-            if (ratestrtosize(jas_tvparser_getval(tvp), cp->rawsize,
-              &cp->totalsize)) {
-                fprintf(stderr,
-                  "ignoring bad rate specifier %s\n",
-                  jas_tvparser_getval(tvp));
-            }
+            ratestrtosize(jas_tvparser_getval(tvp), cp->rawsize,
+                          &cp->totalsize);
             break;
         case OPT_ILYRRATES:
             if (jpc_atoaf(jas_tvparser_getval(tvp), &numilyrrates,
@@ -505,13 +465,10 @@ cp_create(char *optstr, jas_image_t *image) {
                 fprintf(stderr,
                         "warning: invalid intermediate layer rates specifier "
                         "ignored (%s)\n",
-                  jas_tvparser_getval(tvp));
+                        jas_tvparser_getval(tvp));
             }
             break;
 
-        case OPT_JP2OVERHEAD:
-            jp2overhead = atoi(jas_tvparser_getval(tvp));
-            break;
         default:
             fprintf(stderr, "warning: ignoring invalid option %s\n",
              jas_tvparser_gettag(tvp));
@@ -522,11 +479,6 @@ cp_create(char *optstr, jas_image_t *image) {
     jas_tvparser_destroy(tvp);
     tvp = 0;
 
-    if (cp->totalsize != UINT_FAST32_MAX) {
-        cp->totalsize = (cp->totalsize > jp2overhead) ?
-          (cp->totalsize - jp2overhead) : 0;
-    }
-
     if (cp->imgareatlx == UINT_FAST32_MAX) {
         cp->imgareatlx = 0;
     } else {
@@ -697,20 +649,28 @@ cp_create(char *optstr, jas_image_t *image) {
         /* The intermediate layers rates must increase monotonically. */
         for (lyrno = 0; lyrno + 2 < tcp->numlyrs; ++lyrno) {
             if (tcp->ilyrrates[lyrno] >= tcp->ilyrrates[lyrno + 1]) {
-                fprintf(stderr,
-                        "intermediate layer rates must increase "
-                        "monotonically\n");
+                pm_message("Compression rate for Layer %u (%f) "
+                           "is not greater than that for Layer %u (%f).  "
+                           "Rates must increase at every layer",
+                           (unsigned)(lyrno+1),
+                           jpc_fixtodbl(tcp->ilyrrates[lyrno + 1]),
+                           (unsigned)lyrno,
+                           jpc_fixtodbl(tcp->ilyrrates[lyrno]));
                 goto error;
             }
         }
         /* The intermediate layer rates must be less than the overall rate. */
         if (cp->totalsize != UINT_FAST32_MAX) {
             for (lyrno = 0; lyrno < tcp->numlyrs - 1; ++lyrno) {
-                if (jpc_fixtodbl(tcp->ilyrrates[lyrno]) >
-                    ((double) cp->totalsize) / cp->rawsize) {
-                    fprintf(stderr,
-                            "warning: intermediate layer rates must be "
-                            "less than overall rate\n");
+                double const thisLyrRate = jpc_fixtodbl(tcp->ilyrrates[lyrno]);
+                double const completeRate =
+                    ((double) cp->totalsize) / cp->rawsize;
+                if (thisLyrRate > completeRate) {
+                    pm_message(
+                        "Compression rate for Layer %u is %f, "
+                        "which is greater than the rate for the complete "
+                        "image (%f)",
+                        (unsigned)lyrno, thisLyrRate, completeRate);
                     goto error;
                 }
             }
@@ -732,118 +692,17 @@ error:
         jas_tvparser_destroy(tvp);
     }
     if (cp) {
-        jpc_enc_cp_destroy(cp);
-    }
-    return 0;
-}
-
-
-
-void
-jpc_enc_cp_destroy(jpc_enc_cp_t *cp) {
-
-    if (cp->ccps) {
-        if (cp->tcp.ilyrrates) {
-            jas_free(cp->tcp.ilyrrates);
-        }
-        jas_free(cp->ccps);
-    }
-    jas_free(cp);
-}
-
-
-
-int
-ratestrtosize(const char *s, uint_fast32_t rawsize, uint_fast32_t *size) {
-
-    char *cp;
-    jpc_flt_t f;
-
-    /* Note: This function must not modify output size on failure. */
-    if ((cp = strchr(s, 'B'))) {
-        *size = atoi(s);
-    } else {
-        f = atof(s);
-        if (f < 0) {
-            *size = 0;
-        } else if (f > 1.0) {
-            *size = rawsize + 1;
-        } else {
-            *size = f * rawsize;
-        }
-    }
-    return 0;
-}
-
-/*****************************************************************************\
-* Encoder constructor and destructor.
-\*****************************************************************************/
-
-jpc_enc_t *
-jpc_enc_create(jpc_enc_cp_t *cp, jas_stream_t *out, jas_image_t *image) {
-
-    jpc_enc_t *enc;
-
-    enc = 0;
-
-    if (!(enc = jas_malloc(sizeof(jpc_enc_t)))) {
-        goto error;
-    }
-
-    enc->image = image;
-    enc->out = out;
-    enc->cp = cp;
-    enc->cstate = 0;
-    enc->tmpstream = 0;
-    enc->mrk = 0;
-    enc->curtile = 0;
-
-    if (!(enc->cstate = jpc_cstate_create())) {
-        goto error;
-    }
-    enc->len = 0;
-    enc->mainbodysize = 0;
-
-    return enc;
-
-error:
-
-    if (enc) {
-        jpc_enc_destroy(enc);
+        cp_destroy(cp);
     }
     return 0;
 }
 
 
 
-void
-jpc_enc_destroy(jpc_enc_t *enc) {
-
-    /* The image object (i.e., enc->image) and output stream object
-       (i.e., enc->out) are created outside of the encoder.
-       Therefore, they must not be destroyed here.
-    */
-
-    if (enc->curtile) {
-        jpc_enc_tile_destroy(enc->curtile);
-    }
-    if (enc->cp) {
-        jpc_enc_cp_destroy(enc->cp);
-    }
-    if (enc->cstate) {
-        jpc_cstate_destroy(enc->cstate);
-    }
-    if (enc->tmpstream) {
-        jas_stream_close(enc->tmpstream);
-    }
-
-    jas_free(enc);
-}
-
-
-
 static int
-jpc_enc_encodemainhdr(jpc_enc_t *enc) {
+encodemainhdr(jpc_enc_t *enc) {
+
+    uint_fast32_t const maintlrlen = 2;
 
     jpc_siz_t *siz;
     jpc_cod_t *cod;
@@ -961,7 +820,7 @@ jpc_enc_encodemainhdr(jpc_enc_t *enc) {
                   (analgain + 1)), bandinfo->synenergywt);
             } else {
                 absstepsize = jpc_inttofix(1);
-            }   
+            }
             cp->ccps[cmptno].stepsizes[bandno] =
               jpc_abstorelstepsize(absstepsize,
               cp->ccps[cmptno].prec + analgain);
@@ -1038,61 +897,32 @@ jpc_enc_encodemainhdr(jpc_enc_t *enc) {
         enc->mrk = 0;
     }
 
-#define MAINTLRLEN  2
     mainhdrlen = jas_stream_getrwcount(enc->out) - startoff;
     enc->len += mainhdrlen;
     if (enc->cp->totalsize != UINT_FAST32_MAX) {
-        uint_fast32_t overhead;
-        overhead = mainhdrlen + MAINTLRLEN;
-        enc->mainbodysize = (enc->cp->totalsize >= overhead) ?
-          (enc->cp->totalsize - overhead) : 0;
-    } else {
-        enc->mainbodysize = UINT_FAST32_MAX;
-    }
-
-    return 0;
-}
-
-
-
-int
-jpc_enc_encodetiledata(jpc_enc_t *enc) {
-
-    assert(enc->tmpstream);
-    if (jpc_enc_encpkts(enc, enc->tmpstream)) {
-        return -1;
-    }
-    return 0;
-}
-
-
-
-void
-quantize(jas_matrix_t *data, jpc_fix_t stepsize) {
+        uint_fast32_t const overhead = mainhdrlen + maintlrlen;
 
-    int i;
-    int j;
-    jpc_fix_t t;
-
-    if (stepsize == jpc_inttofix(1)) {
-        return;
-    }
-
-    for (i = 0; i < jas_matrix_numrows(data); ++i) {
-        for (j = 0; j < jas_matrix_numcols(data); ++j) {
-            t = jas_matrix_get(data, i, j);
+        if (overhead > enc->cp->totalsize) {
+            pm_message("Requested limit on image size of %u bytes "
+                       "is not possible because it is less than "
+                       "the image metadata size (%u bytes)",
+                       (unsigned)enc->cp->totalsize, (unsigned)overhead);
+            return -1;
+        }
+        enc->mainbodysize = enc->cp->totalsize - overhead;
+        /* This has never actually worked.  'totalsize' is supposed to be
+           the total all-in, so if you request total size 200, you should
+           get an output file 200 bytes or smaller; but we see 209 bytes.
+           Furthermore, at 194 bytes, we get a warning that an empty layer
+           is generated, which probably is actually an error.
 
-{
-    if (t < 0) {
-        t = jpc_fix_neg(jpc_fix_div(jpc_fix_neg(t), stepsize));
+           We should fix this some day.
+        */
     } else {
-        t = jpc_fix_div(t, stepsize);
+        enc->mainbodysize = UINT_FAST32_MAX;
     }
-}
 
-            jas_matrix_set(data, i, j, t);
-        }
-    }
+    return 0;
 }
 
 
@@ -1166,12 +996,12 @@ calcrdslopes(jpc_enc_cblk_t *cblk) {
 
 static void
 traceLayerSizes(const uint_fast32_t * const lyrSizes,
-                unsigned int          const layerCt) {
+                uint_fast32_t         const layerCt) {
 
     if (jas_getdbglevel() > 0) {
-        unsigned int i;
+        uint_fast32_t i;
         for (i = 0; i < layerCt; ++i) {
-            fprintf(stderr, "Layer %u size = ", i);
+            fprintf(stderr, "Layer %u size = ", (unsigned)i);
 
             if (lyrSizes[i] == UINT_FAST32_MAX)
                 fprintf(stderr, "Unlimited");
@@ -1189,48 +1019,28 @@ computeLayerSizes(jpc_enc_t *      const encP,
                   jpc_enc_tile_t * const tileP,
                   jpc_enc_cp_t *   const cpP,
                   double           const rho,
-                  long             const tilehdrlen,
-                  const char **    const errorP) {
+                  long             const tilehdrlen) {
 
     /* Note that in allowed sizes, UINT_FAST32_MAX is a special value meaning
        "unlimited".
     */
 
-    unsigned int const lastLyrno = tileP->numlyrs - 1;
+    uint_fast32_t const lastLyrno = tileP->numlyrs - 1;
 
-    unsigned int lyrno;
+    uint_fast32_t lyrno;
 
     assert(tileP->numlyrs > 0);
 
     for (lyrno = 0; lyrno < lastLyrno; ++lyrno) {
-        tileP->lyrsizes[lyrno] = tileP->rawsize * jpc_fixtodbl(
-            cpP->tcp.ilyrrates[lyrno]);
+        tileP->lyrsizes[lyrno] =
+            MAX(tileP->rawsize *
+                jpc_fixtodbl(cpP->tcp.ilyrrates[lyrno]),
+                tilehdrlen + 1) - tilehdrlen;
     }
 
     tileP->lyrsizes[lastLyrno] =
-        (cpP->totalsize != UINT_FAST32_MAX) ?
-        (rho * encP->mainbodysize) : UINT_FAST32_MAX;
-
-
-    /* Subtract 'tilehdrlen' from every layer. */
-
-    for (lyrno = 0; lyrno < tileP->numlyrs; ++lyrno) {
-        if (tileP->lyrsizes[lyrno] != UINT_FAST32_MAX) {
-            if (tilehdrlen <= tileP->lyrsizes[lyrno]) {
-                tileP->lyrsizes[lyrno] -= tilehdrlen;
-            } else {
-                tileP->lyrsizes[lyrno] = 0;
-            }
-        }
-    }
-
-    if (tileP->lyrsizes[lastLyrno] < 1)
-        pm_asprintf(errorP, "Cannot make image that small (%u bytes).  "
-                    "Even with pixels compressed as far as possible, metadata "
-                    "would exceed the limit",
-                    (unsigned)cpP->totalsize);
-    else
-        *errorP = NULL;
+        (cpP->totalsize == UINT_FAST32_MAX) ?
+        UINT_FAST32_MAX : (rho * encP->mainbodysize);
 
     traceLayerSizes(tileP->lyrsizes, tileP->numlyrs);
 }
@@ -1313,8 +1123,8 @@ trace_layeringinfo(jpc_enc_t * const encP) {
 
 static void
 validateCumlensIncreases(const uint_fast32_t * const cumlens,
-                         unsigned int          const numlyrs) {
-    unsigned int lyrno;
+                         uint_fast32_t          const numlyrs) {
+    uint_fast32_t lyrno;
 
     for (lyrno = 1; lyrno < numlyrs - 1; ++lyrno) {
         if (cumlens[lyrno - 1] > cumlens[lyrno]) {
@@ -1404,7 +1214,7 @@ findMinMaxRDSlopeValues(jpc_enc_tile_t * const tileP,
 static void
 performTier2CodingOneLayer(jpc_enc_t *      const encP,
                            jpc_enc_tile_t * const tileP,
-                           unsigned int     const lyrno,
+                           uint_fast32_t     const lyrno,
                            jas_stream_t *   const outP,
                            const char **    const errorP) {
 /*----------------------------------------------------------------------------
@@ -1444,9 +1254,9 @@ performTier2CodingOneLayer(jpc_enc_t *      const encP,
 static void
 assignHighSlopePassesToLayer(jpc_enc_t *      const encP,
                              jpc_enc_tile_t * const tileP,
-                             unsigned int     const lyrno,
-                             bool             const haveThresh,
-                             jpc_flt_t        const thresh) {
+                             uint_fast32_t     const lyrno,
+                             bool              const haveThresh,
+                             jpc_flt_t         const thresh) {
 /*----------------------------------------------------------------------------
   Assign all passes with R-D slopes greater than or equal to 'thresh' to layer
   'lyrno' and the rest to no layer.
@@ -1505,8 +1315,7 @@ assignHighSlopePassesToLayer(jpc_enc_t *      const encP,
                                         for (; passP != endpassesP; ++passP) {
                                             passP->lyrno = -1;
                                         }
-                                    
-                                    }   
+                                    }
                                 }
                             }
                         }
@@ -1522,7 +1331,7 @@ assignHighSlopePassesToLayer(jpc_enc_t *      const encP,
 static void
 doLayer(jpc_enc_t *      const encP,
         jpc_enc_tile_t * const tileP,
-        unsigned int     const lyrno,
+        uint_fast32_t    const lyrno,
         uint_fast32_t    const allowedSize,
         jpc_flt_t        const mnrdslope,
         jpc_flt_t        const mxrdslope,
@@ -1550,7 +1359,7 @@ doLayer(jpc_enc_t *      const encP,
         long pos;
         jpc_flt_t lo;
         jpc_flt_t hi;
-        unsigned int numiters;
+        uint_fast32_t numiters;
 
         lo = mnrdslope;  /* initial value */
         hi = mxrdslope;  /* initial value */
@@ -1559,52 +1368,46 @@ doLayer(jpc_enc_t *      const encP,
         goodThresh = 0;     /* initial value */
 
         do {
-            if (allowedSize == UINT_FAST32_MAX) {
-                /* There's no rate constraint (This can be true of the last
-                   layer, e.g. for lossless coding). */
-                goodThresh = -1;
-                haveGoodThresh = true;
-            } else {
-                jpc_flt_t const thresh = (lo + hi) / 2;
-
-                int rc;
-                long oldpos;
-
-                /* Save the tier 2 coding state. */
-                jpc_save_t2state(encP);
-                oldpos = jas_stream_tell(outP);
-                assert(oldpos >= 0);
-
-                assignHighSlopePassesToLayer(encP, tileP, lyrno, true, thresh);
-
-                performTier2CodingOneLayer(encP, tileP, lyrno, outP, errorP);
-
-                if (!*errorP) {
-                    pos = jas_stream_tell(outP);
-
-                    /* Check the rate constraint. */
-                    assert(pos >= 0);
-                    if (pos > allowedSize) {
-                        /* The rate is too high. */
-                        lo = thresh;
-                    } else if (pos <= allowedSize) {
-                        /* The rate is low enough, so try higher. */
-                        hi = thresh;
-                        if (!haveGoodThresh || thresh < goodThresh) {
-                            goodThresh = thresh;
-                            haveGoodThresh = true;
-                        }
+            jpc_flt_t const thresh = (lo + hi) / 2;
+
+            int rc;
+            long oldpos;
+
+            /* Save the tier 2 coding state. */
+            jpc_save_t2state(encP);
+            oldpos = jas_stream_tell(outP);
+            assert(oldpos >= 0);
+
+            assignHighSlopePassesToLayer(encP, tileP, lyrno, true, thresh);
+
+            performTier2CodingOneLayer(encP, tileP, lyrno, outP, errorP);
+
+            if (!*errorP) {
+                pos = jas_stream_tell(outP);
+
+                /* Check the rate constraint. */
+                assert(pos >= 0);
+                if (pos > allowedSize) {
+                    /* The rate is too high. */
+                    lo = thresh;
+                } else if (pos <= allowedSize) {
+                    /* The rate is low enough, so try higher. */
+                    hi = thresh;
+                    if (!haveGoodThresh || thresh < goodThresh) {
+                        goodThresh = thresh;
+                        haveGoodThresh = true;
                     }
                 }
-                /* Restore the tier 2 coding state. */
-                jpc_restore_t2state(encP);
-                rc = jas_stream_seek(outP, oldpos, SEEK_SET);
-                if (rc < 0)
-                    abort();
-
-                trace("iter %u: allowedlen=%08ld actuallen=%08ld thresh=%f",
-                      numiters, allowedSize, pos, thresh);
             }
+            /* Restore the tier 2 coding state. */
+            jpc_restore_t2state(encP);
+            rc = jas_stream_seek(outP, oldpos, SEEK_SET);
+            if (rc < 0)
+                abort();
+
+            trace("iter %u: allowedlen=%08ld actuallen=%08ld thresh=%f",
+                  numiters, allowedSize, pos, thresh);
+
             ++numiters;
         } while (lo < hi - 1e-3 && numiters < 32 && !*errorP);
     }
@@ -1625,10 +1428,10 @@ doLayer(jpc_enc_t *      const encP,
 
 
 static void
-performTier2Coding(jpc_enc_t *     const encP,
-                   unsigned int    const numlyrs,
-                   uint_fast32_t * const cumlens,
-                   const char **   const errorP) {
+performTier2Coding(jpc_enc_t *      const encP,
+                   uint_fast32_t    const numlyrs,
+                   uint_fast32_t *  const cumlens,
+                   const char **    const errorP) {
 /*----------------------------------------------------------------------------
    Encode in 'numlyrs' layers, such that at each layer L, the size is
    cumlens[L].
@@ -1636,7 +1439,7 @@ performTier2Coding(jpc_enc_t *     const encP,
     jpc_enc_tile_t * const tileP = encP->curtile;
 
     jas_stream_t * outP;
-    unsigned int lyrno;
+    uint_fast32_t lyrno;
     jpc_flt_t mnrdslope;
     jpc_flt_t mxrdslope;
 
@@ -1669,6 +1472,562 @@ performTier2Coding(jpc_enc_t *     const encP,
 
 
 
+
+
+static void
+encodeTileBody(jpc_enc_t *   const encoderP,
+               long          const tilehdrlen,
+               const char ** const errorP) {
+/*----------------------------------------------------------------------------
+   Encode the body of encoder *encoderP's current tile, writing the encoded
+   result to the encoder's output stream.
+
+   Assume the tile header is already in that stream, and its length is
+   'tilehdrlen'.
+-----------------------------------------------------------------------------*/
+    jpc_enc_tile_t * const tileP = encoderP->curtile;
+    jpc_enc_cp_t *   const cp    = encoderP->cp;
+
+    int rc;
+
+    rc = jpc_enc_enccblks(encoderP);
+    if (rc != 0)
+        pm_asprintf(errorP, "jpc_enc_enccblks() failed");
+    else {
+        double const rho =
+            (double) (tileP->brx - tileP->tlx) * (tileP->bry - tileP->tly) /
+            ((cp->refgrdwidth - cp->imgareatlx) * (cp->refgrdheight -
+                                                   cp->imgareatly));
+        const char * error;
+
+        tileP->rawsize = cp->rawsize * rho;
+
+        computeLayerSizes(encoderP, tileP, cp, rho, tilehdrlen);
+
+        performTier2Coding(encoderP, tileP->numlyrs, tileP->lyrsizes, &error);
+
+        if (error) {
+            pm_asprintf(errorP, "Tier 2 coding failed.  %s", error);
+            pm_strfree(error);
+        } else {
+            int rc;
+
+            rc = jpc_enc_encpkts(encoderP, encoderP->tmpstream);
+            if (rc != 0)
+                pm_asprintf(errorP, "jpc_enc_encpkts() failed\n");
+            else
+                *errorP = NULL;
+        }
+    }
+}
+
+
+
+static void
+quantizeBand(jpc_enc_band_t * const bandP,
+             jpc_enc_tile_t * const tileP,
+             jpc_enc_cp_t *   const cp,
+             int              const prec,
+             int              const tccp_numgbits,
+             int *            const numgbitsP) {
+
+    if (bandP->data) {
+        int actualnumbps;
+        uint_fast32_t y;
+        jpc_fix_t mxmag;
+
+        for (y = 0, actualnumbps = 0, mxmag = 0;
+             y < jas_matrix_numrows(bandP->data);
+             ++y) {
+            uint_fast32_t x;
+
+            for (x = 0; x < jas_matrix_numcols(bandP->data); ++x)
+                mxmag = MAX(mxmag, abs(jas_matrix_get(bandP->data, y, x)));
+        }
+        if (tileP->intmode)
+            actualnumbps = jpc_firstone(mxmag) + 1;
+        else
+            actualnumbps = jpc_firstone(mxmag) + 1 - JPC_FIX_FRACBITS;
+
+        *numgbitsP = actualnumbps - (prec - 1 + bandP->analgain);
+
+        if (!tileP->intmode) {
+            bandP->absstepsize =
+                jpc_fix_div(
+                    jpc_inttofix(1 << (bandP->analgain + 1)),
+                    bandP->synweight);
+        } else {
+            bandP->absstepsize = jpc_inttofix(1);
+        }
+        bandP->stepsize = jpc_abstorelstepsize(
+            bandP->absstepsize, prec + bandP->analgain);
+        /* I couldn't figure out what the calculation with tccp_numgbits and
+           stepsize does (or even what a step size is), but there is an
+           assertion elsewhere than the number here is at least at large as
+           the 'numbps' value for every code block, which means
+           'actualnumbps'.  In practice, we saw that not be true, so we added
+           the code to make 'actualnumbps' the floor here in hopes that would
+           fix the problem.  But with the change, the image that caused the
+           assertion failure produces incorrect output.  22.11.07
+        */
+        bandP->numbps =
+            MAX(actualnumbps,
+                tccp_numgbits + JPC_QCX_GETEXPN(bandP->stepsize) - 1);
+
+        if (!tileP->intmode && bandP->data)
+            quantize(bandP->data, bandP->absstepsize);
+    } else
+        *numgbitsP = 0;
+}
+
+
+
+static int
+encodemainbody(jpc_enc_t *enc) {
+
+    int tileno;
+    int i;
+    jpc_sot_t *sot;
+    int rlvlno;
+    jpc_qcc_t *qcc;
+    jpc_cod_t *cod;
+    int adjust;
+    int j;
+    int absbandno;
+    long tilehdrlen;
+    long tilelen;
+    jpc_enc_tile_t *tile;
+    jpc_enc_cp_t *cp;
+    int samestepsizes;
+    jpc_enc_ccp_t *ccps;
+    jpc_enc_tccp_t *tccp;
+    int mingbits; /* Minimum number of guard bits needed */
+    const char * error;
+
+    cp = enc->cp;
+
+    for (tileno = 0; tileno < cp->numtiles; ++tileno) {
+        uint_fast16_t cmptno;
+
+        enc->curtile = jpc_enc_tile_create(enc->cp, enc->image, tileno);
+        if (!enc->curtile)
+            abort();
+
+        tile = enc->curtile;
+
+        if (jas_getdbglevel() >= 10) {
+            jpc_enc_dump(enc);
+        }
+
+        for (cmptno = 0; cmptno < tile->numtcmpts; ++cmptno) {
+
+            jpc_enc_tcmpt_t * const comp = &tile->tcmpts[cmptno];
+
+            if (!cp->ccps[cmptno].sgnd) {
+                adjust = 1 << (cp->ccps[cmptno].prec - 1);
+                for (i = 0; i < jas_matrix_numrows(comp->data); ++i) {
+                    for (j = 0; j < jas_matrix_numcols(comp->data); ++j) {
+                        *jas_matrix_getref(comp->data, i, j) -= adjust;
+                    }
+                }
+            }
+        }
+
+        if (!tile->intmode) {
+            uint_fast16_t cmptno;
+            for (cmptno = 0; cmptno < tile->numtcmpts; ++cmptno) {
+                jpc_enc_tcmpt_t * const comp = &tile->tcmpts[cmptno];
+                jas_matrix_asl(comp->data, JPC_FIX_FRACBITS);
+            }
+        }
+
+        switch (tile->mctid) {
+        case JPC_MCT_RCT:
+            assert(jas_image_numcmpts(enc->image) == 3);
+            jpc_rct(tile->tcmpts[0].data, tile->tcmpts[1].data,
+                    tile->tcmpts[2].data);
+            break;
+        case JPC_MCT_ICT:
+            assert(jas_image_numcmpts(enc->image) == 3);
+            jpc_ict(tile->tcmpts[0].data, tile->tcmpts[1].data,
+                    tile->tcmpts[2].data);
+            break;
+        default:
+            break;
+        }
+
+        for (i = 0; i < jas_image_numcmpts(enc->image); ++i) {
+            jpc_enc_tcmpt_t * const comp = &tile->tcmpts[i];
+            jpc_tsfb_analyze(comp->tsfb,
+                             ((comp->qmfbid == JPC_COX_RFT) ?
+                              JPC_TSFB_RITIMODE : 0), comp->data);
+
+        }
+
+        for (cmptno = 0; cmptno < tile->numtcmpts; ++cmptno) {
+
+            jpc_enc_tcmpt_t * const comp = &tile->tcmpts[cmptno];
+
+            mingbits = 0;
+            absbandno = 0;
+            /* All bands must have a corresponding quantizer step size,
+               even if they contain no samples and are never coded. */
+            /* Some bands may not be hit by the loop below, so we must
+               initialize all of the step sizes to a sane value. */
+            memset(comp->stepsizes, 0, sizeof(comp->stepsizes));
+            for (rlvlno = 0; rlvlno < comp->numrlvls; ++rlvlno) {
+                jpc_enc_rlvl_t * const lvl = &comp->rlvls[rlvlno];
+
+                unsigned int bandno;
+
+                if (!lvl->bands) {
+                    absbandno += rlvlno ? 3 : 1;
+                    continue;
+                }
+                for (bandno = 0; bandno < lvl->numbands; ++bandno) {
+                    jpc_enc_band_t * const band = &lvl->bands[bandno];
+
+                    int numgbits;
+
+                    quantizeBand(band, tile, cp,
+                                 cp->ccps[cmptno].prec,
+                                 cp->tccp.numgbits,
+                                 &numgbits);
+
+                    mingbits = MAX(mingbits, numgbits);
+
+                    comp->stepsizes[absbandno] = band->stepsize;
+
+                    ++absbandno;
+                }
+            }
+
+            assert(JPC_FIX_FRACBITS >= JPC_NUMEXTRABITS);
+            if (!tile->intmode) {
+                jas_matrix_divpow2(comp->data,
+                                   JPC_FIX_FRACBITS - JPC_NUMEXTRABITS);
+            } else {
+                jas_matrix_asl(comp->data, JPC_NUMEXTRABITS);
+            }
+        }
+
+        if (mingbits > cp->tccp.numgbits) {
+            fprintf(stderr, "error: too few guard bits (need at least %d)\n",
+                    mingbits);
+            return -1;
+        }
+
+        enc->tmpstream = jas_stream_memopen(0, 0);
+        if (!enc->tmpstream) {
+            fprintf(stderr, "cannot open tmp file\n");
+            return -1;
+        }
+
+        /* Write the tile header. */
+        enc->mrk = jpc_ms_create(JPC_MS_SOT);
+        if (!enc->mrk)
+            return -1;
+        sot = &enc->mrk->parms.sot;
+        sot->len = 0;
+        sot->tileno = tileno;
+        sot->partno = 0;
+        sot->numparts = 1;
+        if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) {
+            fprintf(stderr, "cannot write SOT marker\n");
+            return -1;
+        }
+        jpc_ms_destroy(enc->mrk);
+        enc->mrk = 0;
+
+/************************************************************************/
+/************************************************************************/
+/************************************************************************/
+
+        tccp = &cp->tccp;
+        for (cmptno = 0; cmptno < cp->numcmpts; ++cmptno) {
+            jpc_enc_tcmpt_t * const comp = &tile->tcmpts[cmptno];
+            jpc_enc_tcmpt_t * const comp0 = &tile->tcmpts[0];
+
+            if (comp->numrlvls != tccp->maxrlvls) {
+                if (!(enc->mrk = jpc_ms_create(JPC_MS_COD))) {
+                    return -1;
+                }
+                /* XXX = this is not really correct. we are using comp #0's
+                   precint sizes and other characteristics */
+                cod = &enc->mrk->parms.cod;
+                cod->compparms.csty = 0;
+                cod->compparms.numdlvls = comp0->numrlvls - 1;
+                cod->prg = tile->prg;
+                cod->numlyrs = tile->numlyrs;
+                cod->compparms.cblkwidthval =
+                    JPC_COX_CBLKSIZEEXPN(comp0->cblkwidthexpn);
+                cod->compparms.cblkheightval =
+                    JPC_COX_CBLKSIZEEXPN(comp0->cblkheightexpn);
+                cod->compparms.cblksty = comp0->cblksty;
+                cod->compparms.qmfbid = comp0->qmfbid;
+                cod->mctrans = (tile->mctid != JPC_MCT_NONE);
+                for (i = 0; i < comp0->numrlvls; ++i) {
+                    cod->compparms.rlvls[i].parwidthval =
+                        comp0->rlvls[i].prcwidthexpn;
+                    cod->compparms.rlvls[i].parheightval =
+                        comp0->rlvls[i].prcheightexpn;
+                }
+                if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) {
+                    return -1;
+                }
+                jpc_ms_destroy(enc->mrk);
+                enc->mrk = 0;
+            }
+        }
+
+        for (cmptno = 0; cmptno < cp->numcmpts; ++cmptno) {
+            jpc_enc_tcmpt_t * const comp = &tile->tcmpts[cmptno];
+
+            ccps = &cp->ccps[cmptno];
+            if (ccps->numstepsizes == comp->numstepsizes) {
+                unsigned int bandno;
+                samestepsizes = 1;
+                for (bandno = 0; bandno < ccps->numstepsizes; ++bandno) {
+                    if (ccps->stepsizes[bandno] != comp->stepsizes[bandno]) {
+                        samestepsizes = 0;
+                        break;
+                    }
+                }
+            } else {
+                samestepsizes = 0;
+            }
+            if (!samestepsizes) {
+                if (!(enc->mrk = jpc_ms_create(JPC_MS_QCC))) {
+                    return -1;
+                }
+                qcc = &enc->mrk->parms.qcc;
+                qcc->compno = cmptno;
+                qcc->compparms.numguard = cp->tccp.numgbits;
+                qcc->compparms.qntsty = (comp->qmfbid == JPC_COX_INS) ?
+                    JPC_QCX_SEQNT : JPC_QCX_NOQNT;
+                qcc->compparms.numstepsizes = comp->numstepsizes;
+                qcc->compparms.stepsizes = comp->stepsizes;
+                if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) {
+                    return -1;
+                }
+                qcc->compparms.stepsizes = 0;
+                jpc_ms_destroy(enc->mrk);
+                enc->mrk = 0;
+            }
+        }
+
+        /* Write a SOD marker to indicate the end of the tile header. */
+        if (!(enc->mrk = jpc_ms_create(JPC_MS_SOD))) {
+            return -1;
+        }
+        if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) {
+            fprintf(stderr, "cannot write SOD marker\n");
+            return -1;
+        }
+        jpc_ms_destroy(enc->mrk);
+        enc->mrk = 0;
+        tilehdrlen = jas_stream_getrwcount(enc->tmpstream);
+
+/************************************************************************/
+/************************************************************************/
+/************************************************************************/
+
+        encodeTileBody(enc, tilehdrlen, &error);
+            /* Encodes current tile; writes to output file */
+
+        if (error) {
+            fprintf(stderr, "Failed to encode body of tile %u.  %s\n",
+                    tileno, error);
+            pm_strfree(error);
+            return -1;
+        }
+        tilelen = jas_stream_tell(enc->tmpstream);
+
+        if (jas_stream_seek(enc->tmpstream, 6, SEEK_SET) < 0) {
+            return -1;
+        }
+        jpc_putuint32(enc->tmpstream, tilelen);
+
+        if (jas_stream_seek(enc->tmpstream, 0, SEEK_SET) < 0) {
+            return -1;
+        }
+        if (jpc_putdata(enc->out, enc->tmpstream, -1)) {
+            return -1;
+        }
+        enc->len += tilelen;
+
+        jas_stream_close(enc->tmpstream);
+        enc->tmpstream = 0;
+
+        jpc_enc_tile_destroy(enc->curtile);
+        enc->curtile = 0;
+
+    }
+
+    return 0;
+}
+
+
+
+int
+jpc_encode(jas_image_t *image, jas_stream_t *out, char *optstr) {
+
+    jpc_enc_t *enc;
+    jpc_enc_cp_t *cp;
+
+    enc = 0;
+    cp = 0;
+
+    jpc_initluts();
+
+    if (!(cp = cp_create(optstr, image))) {
+        fprintf(stderr, "invalid JP encoder options\n");
+        goto error;
+    }
+
+    if (!(enc = jpc_enc_create(cp, out, image))) {
+        goto error;
+    }
+    cp = 0;
+
+    /* Encode the main header. */
+    if (encodemainhdr(enc)) {
+        goto error;
+    }
+
+    /* Encode the main body.  This constitutes most of the encoding work. */
+    if (encodemainbody(enc)) {
+        goto error;
+    }
+
+    /* Write EOC marker segment. */
+    if (!(enc->mrk = jpc_ms_create(JPC_MS_EOC))) {
+        goto error;
+    }
+    if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
+        fprintf(stderr, "cannot write EOI marker\n");
+        goto error;
+    }
+    jpc_ms_destroy(enc->mrk);
+    enc->mrk = 0;
+
+    if (jas_stream_flush(enc->out)) {
+        goto error;
+    }
+
+    jpc_enc_destroy(enc);
+
+    return 0;
+
+error:
+    if (cp) {
+        cp_destroy(cp);
+    }
+    if (enc) {
+        jpc_enc_destroy(enc);
+    }
+    return -1;
+}
+
+
+
+/*****************************************************************************\
+* Encoder constructor and destructor.
+\*****************************************************************************/
+
+jpc_enc_t *
+jpc_enc_create(jpc_enc_cp_t *cp, jas_stream_t *out, jas_image_t *image) {
+
+    jpc_enc_t *enc;
+
+    enc = 0;
+
+    if (!(enc = jas_malloc(sizeof(jpc_enc_t)))) {
+        goto error;
+    }
+
+    enc->image = image;
+    enc->out = out;
+    enc->cp = cp;
+    enc->cstate = 0;
+    enc->tmpstream = 0;
+    enc->mrk = 0;
+    enc->curtile = 0;
+
+    if (!(enc->cstate = jpc_cstate_create())) {
+        goto error;
+    }
+    enc->len = 0;
+    enc->mainbodysize = 0;
+
+    return enc;
+
+error:
+
+    if (enc) {
+        jpc_enc_destroy(enc);
+    }
+    return 0;
+}
+
+
+
+void
+jpc_enc_destroy(jpc_enc_t *enc) {
+
+    /* The image object (i.e., enc->image) and output stream object
+       (i.e., enc->out) are created outside of the encoder.
+       Therefore, they must not be destroyed here.
+    */
+
+    if (enc->curtile) {
+        jpc_enc_tile_destroy(enc->curtile);
+    }
+    if (enc->cp) {
+        cp_destroy(enc->cp);
+    }
+    if (enc->cstate) {
+        jpc_cstate_destroy(enc->cstate);
+    }
+    if (enc->tmpstream) {
+        jas_stream_close(enc->tmpstream);
+    }
+
+    jas_free(enc);
+}
+
+
+
+void
+quantize(jas_matrix_t *data, jpc_fix_t stepsize) {
+
+    int i;
+    int j;
+    jpc_fix_t t;
+
+    if (stepsize == jpc_inttofix(1)) {
+        return;
+    }
+
+    for (i = 0; i < jas_matrix_numrows(data); ++i) {
+        for (j = 0; j < jas_matrix_numcols(data); ++j) {
+            t = jas_matrix_get(data, i, j);
+
+{
+    if (t < 0) {
+        t = jpc_fix_neg(jpc_fix_div(jpc_fix_neg(t), stepsize));
+    } else {
+        t = jpc_fix_div(t, stepsize);
+    }
+}
+
+            jas_matrix_set(data, i, j, t);
+        }
+    }
+}
+
+
+
 /*****************************************************************************\
 * Tile constructors and destructors.
 \*****************************************************************************/
@@ -2227,7 +2586,7 @@ prc_create(jpc_enc_prc_t *prc, jpc_enc_cp_t *cp, jpc_enc_band_t *band) {
         }
 
         prc->cblks = jas_malloc(prc->numcblks * sizeof(jpc_enc_cblk_t));
-        
+
         if (!prc->cblks)
             goto error;
         for (cblkno = 0, cblk = prc->cblks;
@@ -2445,9 +2804,9 @@ jpc_enc_dump(jpc_enc_t *enc) {
                      prcno < rlvl->numprcs;
                      ++prcno, ++prc) {
                     fprintf(stderr, "        prc %5d %5d %5d %5d (%5d %5d)\n",
-                            (int)prc->tlx, (int)prc->tly, 
+                            (int)prc->tlx, (int)prc->tly,
                             (int)prc->brx, (int)prc->bry,
-                            (int)(prc->brx - prc->tlx), 
+                            (int)(prc->brx - prc->tlx),
                             (int)(prc->bry - prc->tly));
                     if (!prc->cblks) {
                         continue;
@@ -2468,352 +2827,6 @@ jpc_enc_dump(jpc_enc_t *enc) {
 
 
 
-static int
-jpc_enc_encodemainbody(jpc_enc_t *enc) {
-
-    int tileno;
-    int i;
-    jpc_sot_t *sot;
-    jpc_enc_tcmpt_t *comp;
-    jpc_enc_tcmpt_t *endcomps;
-    jpc_enc_band_t *band;
-    jpc_enc_band_t *endbands;
-    jpc_enc_rlvl_t *lvl;
-    int rlvlno;
-    jpc_qcc_t *qcc;
-    jpc_cod_t *cod;
-    int adjust;
-    int j;
-    int absbandno;
-    long tilehdrlen;
-    long tilelen;
-    jpc_enc_tile_t *tile;
-    jpc_enc_cp_t *cp;
-    double rho;
-    uint_fast16_t cmptno;
-    int samestepsizes;
-    jpc_enc_ccp_t *ccps;
-    jpc_enc_tccp_t *tccp;
-    int bandno;
-    uint_fast32_t x;
-    uint_fast32_t y;
-    int mingbits;
-    int actualnumbps;
-    jpc_fix_t mxmag;
-    jpc_fix_t mag;
-    int numgbits;
-    const char * error;
-
-    cp = enc->cp;
-
-    for (tileno = 0; tileno < cp->numtiles; ++tileno) {
-        enc->curtile = jpc_enc_tile_create(enc->cp, enc->image, tileno);
-        if (!enc->curtile)
-            abort();
-
-        tile = enc->curtile;
-
-        if (jas_getdbglevel() >= 10) {
-            jpc_enc_dump(enc);
-        }
-
-        endcomps = &tile->tcmpts[tile->numtcmpts];
-        for (cmptno = 0, comp = tile->tcmpts;
-             cmptno < tile->numtcmpts;
-             ++cmptno, ++comp) {
-            if (!cp->ccps[cmptno].sgnd) {
-                adjust = 1 << (cp->ccps[cmptno].prec - 1);
-                for (i = 0; i < jas_matrix_numrows(comp->data); ++i) {
-                    for (j = 0; j < jas_matrix_numcols(comp->data); ++j) {
-                        *jas_matrix_getref(comp->data, i, j) -= adjust;
-                    }
-                }
-            }
-        }
-
-        if (!tile->intmode) {
-            endcomps = &tile->tcmpts[tile->numtcmpts];
-            for (comp = tile->tcmpts; comp != endcomps; ++comp) {
-                jas_matrix_asl(comp->data, JPC_FIX_FRACBITS);
-            }
-        }
-
-        switch (tile->mctid) {
-        case JPC_MCT_RCT:
-            assert(jas_image_numcmpts(enc->image) == 3);
-            jpc_rct(tile->tcmpts[0].data, tile->tcmpts[1].data,
-                    tile->tcmpts[2].data);
-            break;
-        case JPC_MCT_ICT:
-            assert(jas_image_numcmpts(enc->image) == 3);
-            jpc_ict(tile->tcmpts[0].data, tile->tcmpts[1].data,
-                    tile->tcmpts[2].data);
-            break;
-        default:
-            break;
-        }
-
-        for (i = 0; i < jas_image_numcmpts(enc->image); ++i) {
-            comp = &tile->tcmpts[i];
-            jpc_tsfb_analyze(comp->tsfb,
-                             ((comp->qmfbid == JPC_COX_RFT) ?
-                              JPC_TSFB_RITIMODE : 0), comp->data);
-
-        }
-
-        endcomps = &tile->tcmpts[tile->numtcmpts];
-        for (cmptno = 0, comp = tile->tcmpts;
-             comp != endcomps;
-             ++cmptno, ++comp) {
-            mingbits = 0;
-            absbandno = 0;
-            /* All bands must have a corresponding quantizer step size,
-               even if they contain no samples and are never coded. */
-            /* Some bands may not be hit by the loop below, so we must
-               initialize all of the step sizes to a sane value. */
-            memset(comp->stepsizes, 0, sizeof(comp->stepsizes));
-            for (rlvlno = 0, lvl = comp->rlvls;
-                 rlvlno < comp->numrlvls;
-                 ++rlvlno, ++lvl) {
-                if (!lvl->bands) {
-                    absbandno += rlvlno ? 3 : 1;
-                    continue;
-                }
-                endbands = &lvl->bands[lvl->numbands];
-                for (band = lvl->bands; band != endbands; ++band) {
-                    if (!band->data) {
-                        ++absbandno;
-                        continue;
-                    }
-                    actualnumbps = 0;
-                    mxmag = 0;
-                    for (y = 0; y < jas_matrix_numrows(band->data); ++y) {
-                        for (x = 0; x < jas_matrix_numcols(band->data); ++x) {
-                            mag = abs(jas_matrix_get(band->data, y, x));
-                            if (mag > mxmag) {
-                                mxmag = mag;
-                            }
-                        }
-                    }
-                    if (tile->intmode) {
-                        actualnumbps =
-                            jpc_firstone(mxmag) + 1;
-                    } else {
-                        actualnumbps =
-                            jpc_firstone(mxmag) + 1 - JPC_FIX_FRACBITS;
-                    }
-                    numgbits = actualnumbps - (cp->ccps[cmptno].prec - 1 +
-                                               band->analgain);
-                    if (numgbits > mingbits) {
-                        mingbits = numgbits;
-                    }
-                    if (!tile->intmode) {
-                        band->absstepsize =
-                            jpc_fix_div(
-                                jpc_inttofix(1 << (band->analgain + 1)),
-                                band->synweight);
-                    } else {
-                        band->absstepsize = jpc_inttofix(1);
-                    }
-                    band->stepsize = jpc_abstorelstepsize(
-                        band->absstepsize, cp->ccps[cmptno].prec +
-                        band->analgain);
-                    band->numbps = cp->tccp.numgbits +
-                        JPC_QCX_GETEXPN(band->stepsize) - 1;
-
-                    if ((!tile->intmode) && band->data) {
-                        quantize(band->data, band->absstepsize);
-                    }
-
-                    comp->stepsizes[absbandno] = band->stepsize;
-                    ++absbandno;
-                }
-            }
-
-            assert(JPC_FIX_FRACBITS >= JPC_NUMEXTRABITS);
-            if (!tile->intmode) {
-                jas_matrix_divpow2(comp->data,
-                                   JPC_FIX_FRACBITS - JPC_NUMEXTRABITS);
-            } else {
-                jas_matrix_asl(comp->data, JPC_NUMEXTRABITS);
-            }
-        }
-
-        if (mingbits > cp->tccp.numgbits) {
-            fprintf(stderr, "error: too few guard bits (need at least %d)\n",
-                    mingbits);
-            return -1;
-        }
-
-        enc->tmpstream = jas_stream_memopen(0, 0);
-        if (!enc->tmpstream) {
-            fprintf(stderr, "cannot open tmp file\n");
-            return -1;
-        }
-
-        /* Write the tile header. */
-        enc->mrk = jpc_ms_create(JPC_MS_SOT);
-        if (!enc->mrk)
-            return -1;
-        sot = &enc->mrk->parms.sot;
-        sot->len = 0;
-        sot->tileno = tileno;
-        sot->partno = 0;
-        sot->numparts = 1;
-        if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) {
-            fprintf(stderr, "cannot write SOT marker\n");
-            return -1;
-        }
-        jpc_ms_destroy(enc->mrk);
-        enc->mrk = 0;
-
-/************************************************************************/
-/************************************************************************/
-/************************************************************************/
-
-        tccp = &cp->tccp;
-        for (cmptno = 0; cmptno < cp->numcmpts; ++cmptno) {
-            comp = &tile->tcmpts[cmptno];
-            if (comp->numrlvls != tccp->maxrlvls) {
-                if (!(enc->mrk = jpc_ms_create(JPC_MS_COD))) {
-                    return -1;
-                }
-                /* XXX = this is not really correct. we are using comp #0's
-                   precint sizes and other characteristics */
-                comp = &tile->tcmpts[0];
-                cod = &enc->mrk->parms.cod;
-                cod->compparms.csty = 0;
-                cod->compparms.numdlvls = comp->numrlvls - 1;
-                cod->prg = tile->prg;
-                cod->numlyrs = tile->numlyrs;
-                cod->compparms.cblkwidthval =
-                    JPC_COX_CBLKSIZEEXPN(comp->cblkwidthexpn);
-                cod->compparms.cblkheightval =
-                    JPC_COX_CBLKSIZEEXPN(comp->cblkheightexpn);
-                cod->compparms.cblksty = comp->cblksty;
-                cod->compparms.qmfbid = comp->qmfbid;
-                cod->mctrans = (tile->mctid != JPC_MCT_NONE);
-                for (i = 0; i < comp->numrlvls; ++i) {
-                    cod->compparms.rlvls[i].parwidthval =
-                        comp->rlvls[i].prcwidthexpn;
-                    cod->compparms.rlvls[i].parheightval =
-                        comp->rlvls[i].prcheightexpn;
-                }
-                if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) {
-                    return -1;
-                }
-                jpc_ms_destroy(enc->mrk);
-                enc->mrk = 0;
-            }
-        }
-
-        for (cmptno = 0, comp = tile->tcmpts;
-             cmptno < cp->numcmpts;
-             ++cmptno, ++comp) {
-            ccps = &cp->ccps[cmptno];
-            if (ccps->numstepsizes == comp->numstepsizes) {
-                samestepsizes = 1;
-                for (bandno = 0; bandno < ccps->numstepsizes; ++bandno) {
-                    if (ccps->stepsizes[bandno] != comp->stepsizes[bandno]) {
-                        samestepsizes = 0;
-                        break;
-                    }
-                }
-            } else {
-                samestepsizes = 0;
-            }
-            if (!samestepsizes) {
-                if (!(enc->mrk = jpc_ms_create(JPC_MS_QCC))) {
-                    return -1;
-                }
-                qcc = &enc->mrk->parms.qcc;
-                qcc->compno = cmptno;
-                qcc->compparms.numguard = cp->tccp.numgbits;
-                qcc->compparms.qntsty = (comp->qmfbid == JPC_COX_INS) ?
-                    JPC_QCX_SEQNT : JPC_QCX_NOQNT;
-                qcc->compparms.numstepsizes = comp->numstepsizes;
-                qcc->compparms.stepsizes = comp->stepsizes;
-                if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) {
-                    return -1;
-                }
-                qcc->compparms.stepsizes = 0;
-                jpc_ms_destroy(enc->mrk);
-                enc->mrk = 0;
-            }
-        }
-
-        /* Write a SOD marker to indicate the end of the tile header. */
-        if (!(enc->mrk = jpc_ms_create(JPC_MS_SOD))) {
-            return -1;
-        }
-        if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) {
-            fprintf(stderr, "cannot write SOD marker\n");
-            return -1;
-        }
-        jpc_ms_destroy(enc->mrk);
-        enc->mrk = 0;
-        tilehdrlen = jas_stream_getrwcount(enc->tmpstream);
-
-/************************************************************************/
-/************************************************************************/
-/************************************************************************/
-
-        if (jpc_enc_enccblks(enc)) {
-            abort();
-            return -1;
-        }
-
-        cp = enc->cp;
-        rho = (double) (tile->brx - tile->tlx) * (tile->bry - tile->tly) /
-            ((cp->refgrdwidth - cp->imgareatlx) * (cp->refgrdheight -
-                                                   cp->imgareatly));
-        tile->rawsize = cp->rawsize * rho;
-
-        computeLayerSizes(enc, tile, cp, rho, tilehdrlen, &error);
-        
-        if (!error) {
-            int rc;
-            performTier2Coding(enc, tile->numlyrs, tile->lyrsizes, &error);
-
-            rc =  jpc_enc_encodetiledata(enc);
-            if (rc != 0)
-                pm_asprintf(&error, "jpc_enc_encodetiledata() failed\n");
-        }
-
-        if (error) {
-            fprintf(stderr, "%s\n", error);
-            pm_strfree(error);
-            return -1;
-        }
-
-        tilelen = jas_stream_tell(enc->tmpstream);
-
-        if (jas_stream_seek(enc->tmpstream, 6, SEEK_SET) < 0) {
-            return -1;
-        }
-        jpc_putuint32(enc->tmpstream, tilelen);
-
-        if (jas_stream_seek(enc->tmpstream, 0, SEEK_SET) < 0) {
-            return -1;
-        }
-        if (jpc_putdata(enc->out, enc->tmpstream, -1)) {
-            return -1;
-        }
-        enc->len += tilelen;
-
-        jas_stream_close(enc->tmpstream);
-        enc->tmpstream = 0;
-
-        jpc_enc_tile_destroy(enc->curtile);
-        enc->curtile = 0;
-
-    }
-
-    return 0;
-}
-
-
-
 /*
  * Copyright (c) 1999-2000 Image Power, Inc. and the University of
  *   British Columbia.
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_enc.h b/converter/other/jpeg2000/libjasper/jpc/jpc_enc.h
index cfd754c9..86a8e59c 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_enc.h
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_enc.h
@@ -145,7 +145,7 @@
 * Coding parameters types.
 \******************************************************************************/
 
-/* Per-component coding paramters. */
+/* Per-component coding parameters. */
 
 typedef struct {
 
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_math.c b/converter/other/jpeg2000/libjasper/jpc/jpc_math.c
index 01e3611e..a884ed4d 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_math.c
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_math.c
@@ -50,6 +50,8 @@ jpc_firstone(int_fast32_t const arg) {
 /*---------------------------------------------------------------------------- 
   Calculate the bit position of the first leading one in a nonnegative
   integer.
+
+  LSB is bit position 0.  Iff there are no ones, return -1.
 -----------------------------------------------------------------------------*/
 	int n;
     int x;
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.c b/converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.c
index 3f6122e3..54472481 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.c
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.c
@@ -6,14 +6,14 @@
  */
 
 /* __START_OF_JASPER_LICENSE__
- * 
+ *
  * JasPer Software License
- * 
+ *
  * IMAGE POWER JPEG-2000 PUBLIC LICENSE
  * ************************************
- * 
+ *
  * GRANT:
- * 
+ *
  * Permission is hereby granted, free of charge, to any person (the "User")
  * obtaining a copy of this software and associated documentation, to deal
  * in the JasPer Software without restriction, including without limitation
@@ -21,22 +21,22 @@
  * and/or sell copies of the JasPer Software (in source and binary forms),
  * and to permit persons to whom the JasPer Software is furnished to do so,
  * provided further that the License Conditions below are met.
- * 
+ *
  * License Conditions
  * ******************
- * 
+ *
  * A.  Redistributions of source code must retain the above copyright notice,
  * and this list of conditions, and the following disclaimer.
- * 
+ *
  * B.  Redistributions in binary form must reproduce the above copyright
  * notice, and this list of conditions, and the following disclaimer in
  * the documentation and/or other materials provided with the distribution.
- * 
+ *
  * C.  Neither the name of Image Power, Inc. nor any other contributor
  * (including, but not limited to, the University of British Columbia and
  * Michael David Adams) may be used to endorse or promote products derived
  * from this software without specific prior written permission.
- * 
+ *
  * D.  User agrees that it shall not commence any action against Image Power,
  * Inc., the University of British Columbia, Michael David Adams, or any
  * other contributors (collectively "Licensors") for infringement of any
@@ -56,17 +56,17 @@
  * trade dress, or service mark rights); and (v) divisions, continuations,
  * renewals, reissues and extensions of the foregoing (as and to the extent
  * applicable) now existing, hereafter filed, issued or acquired.
- * 
+ *
  * E.  If User commences an infringement action against any Licensor(s) then
  * such Licensor(s) shall have the right to terminate User's license and
  * all sublicenses that have been granted hereunder by User to other parties.
- * 
+ *
  * F.  This software is for use only in hardware or software products that
  * are compliant with ISO/IEC 15444-1 (i.e., JPEG-2000 Part 1).  No license
  * or right to this Software is granted for products that do not comply
  * with ISO/IEC 15444-1.  The JPEG-2000 Part 1 standard can be purchased
  * from the ISO.
- * 
+ *
  * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.
  * NO USE OF THE JASPER SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER
  * THIS DISCLAIMER.  THE JASPER SOFTWARE IS PROVIDED BY THE LICENSORS AND
@@ -106,7 +106,7 @@
  * TECHNOLOGY OR PRODUCTS FOR HIGH RISK ACTIVITIES AND WILL ENSURE THAT ITS
  * CUSTOMERS AND END-USERS OF ITS PRODUCTS ARE PROVIDED WITH A COPY OF THE
  * NOTICE SPECIFIED IN THIS SECTION.
- * 
+ *
  * __END_OF_JASPER_LICENSE__
  */
 
@@ -223,7 +223,7 @@
 }
 
 /******************************************************************************\
-* Local function protoypes.
+* Local function prototypes.
 \******************************************************************************/
 
 static void jpc_mqenc_setbits(jpc_mqenc_t *mqenc);
@@ -439,3 +439,6 @@ int jpc_mqenc_dump(jpc_mqenc_t *mqenc, FILE *out)
             (unsigned)(*mqenc->curctx)->qeval);
     return 0;
 }
+
+
+
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.c b/converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.c
index 01a54ea8..b6c5e14f 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.c
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.c
@@ -124,6 +124,8 @@
 #include <stdlib.h>
 #include <assert.h>
 
+#include "netpbm/nstring.h"
+
 #include "jasper/jas_fix.h"
 #include "jasper/jas_stream.h"
 #include "jasper/jas_math.h"
@@ -138,817 +140,871 @@
 *
 \******************************************************************************/
 
-static int jpc_dec_decodecblk(jpc_dec_t *dec, jpc_dec_tile_t *tile, jpc_dec_tcomp_t *tcomp, jpc_dec_band_t *band,
-  jpc_dec_cblk_t *cblk, int dopartial, int maxlyrs);
-static int dec_sigpass(jpc_dec_t *dec, jpc_mqdec_t *mqdec, int bitpos, int orient,
-  int vcausalflag, jas_matrix_t *flags, jas_matrix_t *data);
-static int dec_rawsigpass(jpc_dec_t *dec, jpc_bitstream_t *in, int bitpos,
-  int vcausalflag, jas_matrix_t *flags, jas_matrix_t *data);
-static int dec_refpass(jpc_dec_t *dec, jpc_mqdec_t *mqdec, int bitpos, int vcausalflag,
-  jas_matrix_t *flags, jas_matrix_t *data);
-static int dec_rawrefpass(jpc_dec_t *dec, jpc_bitstream_t *in, int bitpos,
-  int vcausalflag, jas_matrix_t *flags, jas_matrix_t *data);
-static int dec_clnpass(jpc_dec_t *dec, jpc_mqdec_t *mqdec, int bitpos, int orient,
-  int vcausalflag, int segsymflag, jas_matrix_t *flags, jas_matrix_t *data);
-
 #if defined(DEBUG)
 static long t1dec_cnt = 0;
 #endif
 
 #if !defined(DEBUG)
-#define	JPC_T1D_GETBIT(mqdec, v, passtypename, symtypename) \
-	((v) = jpc_mqdec_getbit(mqdec))
+#define JPC_T1D_GETBIT(mqdec, v, passtypename, symtypename) \
+    ((v) = jpc_mqdec_getbit(mqdec))
 #else
-#define	JPC_T1D_GETBIT(mqdec, v, passtypename, symtypename) \
+#define JPC_T1D_GETBIT(mqdec, v, passtypename, symtypename) \
 { \
-	(v) = jpc_mqdec_getbit(mqdec); \
-	if (jas_getdbglevel() >= 100) { \
-		fprintf(stderr, "index = %ld; passtype = %s; symtype = %s; sym = %d\n", t1dec_cnt, passtypename, symtypename, v); \
-		++t1dec_cnt; \
-	} \
+    (v) = jpc_mqdec_getbit(mqdec); \
+    if (jas_getdbglevel() >= 100) { \
+        fprintf(stderr, "index = %ld; passtype = %s; symtype = %s; sym = %d\n", t1dec_cnt, passtypename, symtypename, v); \
+        ++t1dec_cnt; \
+    } \
 }
 #endif
-#define	JPC_T1D_GETBITNOSKEW(mqdec, v, passtypename, symtypename) \
-	JPC_T1D_GETBIT(mqdec, v, passtypename, symtypename)
+#define JPC_T1D_GETBITNOSKEW(mqdec, v, passtypename, symtypename) \
+    JPC_T1D_GETBIT(mqdec, v, passtypename, symtypename)
 
 #if !defined(DEBUG)
-#define	JPC_T1D_RAWGETBIT(bitstream, v, passtypename, symtypename) \
-	((v) = jpc_bitstream_getbit(bitstream))
+#define JPC_T1D_RAWGETBIT(bitstream, v, passtypename, symtypename) \
+    ((v) = jpc_bitstream_getbit(bitstream))
 #else
-#define	JPC_T1D_RAWGETBIT(bitstream, v, passtypename, symtypename) \
+#define JPC_T1D_RAWGETBIT(bitstream, v, passtypename, symtypename) \
 { \
-	(v) = jpc_bitstream_getbit(bitstream); \
-	if (jas_getdbglevel() >= 100) { \
-		fprintf(stderr, "index = %ld; passtype = %s; symtype = %s; sym = %d\n", t1dec_cnt, passtypename, symtypename, v); \
-		++t1dec_cnt; \
-	} \
+    (v) = jpc_bitstream_getbit(bitstream); \
+    if (jas_getdbglevel() >= 100) { \
+        fprintf(stderr, "index = %ld; passtype = %s; symtype = %s; sym = %d\n", t1dec_cnt, passtypename, symtypename, v); \
+        ++t1dec_cnt; \
+    } \
 }
 #endif
 
-/******************************************************************************\
-* Code.
-\******************************************************************************/
 
-int jpc_dec_decodecblks(jpc_dec_t *dec, jpc_dec_tile_t *tile)
-{
-	jpc_dec_tcomp_t *tcomp;
-	int compcnt;
-	jpc_dec_rlvl_t *rlvl;
-	int rlvlcnt;
-	jpc_dec_band_t *band;
-	int bandcnt;
-	jpc_dec_prc_t *prc;
-	int prccnt;
-	jpc_dec_cblk_t *cblk;
-	int cblkcnt;
-
-	for (compcnt = dec->numcomps, tcomp = tile->tcomps; compcnt > 0;
-	  --compcnt, ++tcomp) {
-		for (rlvlcnt = tcomp->numrlvls, rlvl = tcomp->rlvls;
-		  rlvlcnt > 0; --rlvlcnt, ++rlvl) {
-			if (!rlvl->bands) {
-				continue;
-			}
-			for (bandcnt = rlvl->numbands, band = rlvl->bands;
-			  bandcnt > 0; --bandcnt, ++band) {
-				if (!band->data) {
-					continue;
-				}
-				for (prccnt = rlvl->numprcs, prc = band->prcs;
-				  prccnt > 0; --prccnt, ++prc) {
-					if (!prc->cblks) {
-						continue;
-					}
-					for (cblkcnt = prc->numcblks,
-					  cblk = prc->cblks; cblkcnt > 0;
-					  --cblkcnt, ++cblk) {
-						if (jpc_dec_decodecblk(dec, tile, tcomp,
-						  band, cblk, 1, JPC_MAXLYRS)) {
-							return -1;
-						}
-					}
-				}
-
-			}
-		}
-	}
-
-	return 0;
-}
-
-static int jpc_dec_decodecblk(jpc_dec_t *dec, jpc_dec_tile_t *tile, jpc_dec_tcomp_t *tcomp, jpc_dec_band_t *band,
-  jpc_dec_cblk_t *cblk, int dopartial, int maxlyrs)
-{
-	jpc_dec_seg_t *seg;
-	int i;
-	int bpno;
-	int passtype;
-	int ret;
-	int compno;
-	int filldata;
-	int fillmask;
-	jpc_dec_ccp_t *ccp;
-
-	compno = tcomp - tile->tcomps;
-
-	if (!cblk->flags) {
-		/* Note: matrix is assumed to be zeroed */
-		if (!(cblk->flags = jas_matrix_create(jas_matrix_numrows(cblk->data) +
-		  2, jas_matrix_numcols(cblk->data) + 2))) {
-			return -1;
-		}
-	}
-
-	seg = cblk->segs.head;
-	while (seg && (seg != cblk->curseg || dopartial) && (maxlyrs < 0 ||
-	  seg->lyrno < maxlyrs)) {
-		assert(seg->numpasses >= seg->maxpasses || dopartial);
-		assert(seg->stream);
-		jas_stream_rewind(seg->stream);
-		jas_stream_setrwcount(seg->stream, 0);
-		if (seg->type == JPC_SEG_MQ) {
-			if (!cblk->mqdec) {
-				if (!(cblk->mqdec = jpc_mqdec_create(JPC_NUMCTXS, 0))) {
-					return -1;
-				}
-				jpc_mqdec_setctxs(cblk->mqdec, JPC_NUMCTXS, jpc_mqctxs);
-			}
-			jpc_mqdec_setinput(cblk->mqdec, seg->stream);
-			jpc_mqdec_init(cblk->mqdec);
-		} else {
-			assert(seg->type == JPC_SEG_RAW);
-			if (!cblk->nulldec) {
-				if (!(cblk->nulldec = jpc_bitstream_sopen(seg->stream, "r"))) {
-					assert(0);
-				}
-			}
-		}
-
-
-		for (i = 0; i < seg->numpasses; ++i) {
-			if (cblk->numimsbs > band->numbps) {
-				ccp = &tile->cp->ccps[compno];
-				if (ccp->roishift <= 0) {
-					fprintf(stderr, "warning: corrupt code stream\n");
-				} else {
-					if (cblk->numimsbs < ccp->roishift - band->numbps) {
-						fprintf(stderr, "warning: corrupt code stream\n");
-					}
-				}
-			}
-			bpno = band->roishift + band->numbps - 1 - (cblk->numimsbs +
-			  (seg->passno + i - cblk->firstpassno + 2) / 3);
-if (bpno < 0) {
-	goto premature_exit;
-}
-#if 1
-			passtype = (seg->passno + i + 2) % 3;
-#else
-			passtype = JPC_PASSTYPE(seg->passno + i + 2);
-#endif
-			assert(bpno >= 0 && bpno < 31);
-			switch (passtype) {
-			case JPC_SIGPASS:
-				ret = (seg->type == JPC_SEG_MQ) ? dec_sigpass(dec,
-				  cblk->mqdec, bpno, band->orient,
-				  (tile->cp->ccps[compno].cblkctx & JPC_COX_VSC) != 0,
-				  cblk->flags, cblk->data) :
-				  dec_rawsigpass(dec, cblk->nulldec, bpno,
-				  (tile->cp->ccps[compno].cblkctx & JPC_COX_VSC) != 0,
-				  cblk->flags, cblk->data);
-				break;
-			case JPC_REFPASS:
-				ret = (seg->type == JPC_SEG_MQ) ?
-				  dec_refpass(dec, cblk->mqdec, bpno,
-				  (tile->cp->ccps[compno].cblkctx & JPC_COX_VSC) != 0,
-				  cblk->flags, cblk->data) :
-				  dec_rawrefpass(dec, cblk->nulldec, bpno,
-				  (tile->cp->ccps[compno].cblkctx & JPC_COX_VSC) != 0,
-				  cblk->flags, cblk->data);
-				break;
-			case JPC_CLNPASS:
-				assert(seg->type == JPC_SEG_MQ);
-				ret = dec_clnpass(dec, cblk->mqdec, bpno,
-				  band->orient, (tile->cp->ccps[compno].cblkctx &
-				  JPC_COX_VSC) != 0, (tile->cp->ccps[compno].cblkctx &
-				  JPC_COX_SEGSYM) != 0, cblk->flags,
-				  cblk->data);
-				break;
-			default:
-				ret = -1;
-				break;
-			}
-			/* Do we need to reset after each coding pass? */
-			if (tile->cp->ccps[compno].cblkctx & JPC_COX_RESET) {
-				jpc_mqdec_setctxs(cblk->mqdec, JPC_NUMCTXS, jpc_mqctxs);
-			}
-
-			if (ret) {
-				fprintf(stderr, "coding pass failed passtype=%d segtype=%d\n", passtype, seg->type);
-				return -1;
-			}
-
-		}
-
-		if (seg->type == JPC_SEG_MQ) {
-/* Note: dont destroy mq decoder because context info will be lost */
-		} else {
-			assert(seg->type == JPC_SEG_RAW);
-			if (tile->cp->ccps[compno].cblkctx & JPC_COX_PTERM) {
-				fillmask = 0x7f;
-				filldata = 0x2a;
-			} else {
-				fillmask = 0;
-				filldata = 0;
-			}
-			if ((ret = jpc_bitstream_inalign(cblk->nulldec, fillmask,
-			  filldata)) < 0) {
-				return -1;
-			} else if (ret > 0) {
-				fprintf(stderr, "warning: bad termination pattern detected\n");
-			}
-			jpc_bitstream_close(cblk->nulldec);
-			cblk->nulldec = 0;
-		}
-
-		cblk->curseg = seg->next;
-		jpc_seglist_remove(&cblk->segs, seg);
-		jpc_seg_destroy(seg);
-		seg = cblk->curseg;
-	}
-
-	assert(dopartial ? (!cblk->curseg) : 1);
-
-premature_exit:
-	return 0;
-}
 
 /******************************************************************************\
 * Code for significance pass.
 \******************************************************************************/
 
-#define	jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf, orient, mqdec, vcausalflag) \
+#define jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf, orient, mqdec, vcausalflag) \
 { \
-	int f; \
-	int v; \
-	f = *(fp); \
-	if ((f & JPC_OTHSIGMSK) && !(f & (JPC_SIG | JPC_VISIT))) { \
-		jpc_mqdec_setcurctx((mqdec), JPC_GETZCCTXNO(f, (orient))); \
-		JPC_T1D_GETBIT((mqdec), v, "SIG", "ZC"); \
-		if (v) { \
-			jpc_mqdec_setcurctx((mqdec), JPC_GETSCCTXNO(f)); \
-			JPC_T1D_GETBIT((mqdec), v, "SIG", "SC"); \
-			v ^= JPC_GETSPB(f); \
-			JPC_UPDATEFLAGS4((fp), (frowstep), v, (vcausalflag)); \
-			*(fp) |= JPC_SIG; \
-			*(dp) = (v) ? (-(oneplushalf)) : (oneplushalf); \
-		} \
-		*(fp) |= JPC_VISIT; \
-	} \
+    int f; \
+    int v; \
+    f = *(fp); \
+    if ((f & JPC_OTHSIGMSK) && !(f & (JPC_SIG | JPC_VISIT))) { \
+        jpc_mqdec_setcurctx((mqdec), JPC_GETZCCTXNO(f, (orient))); \
+        JPC_T1D_GETBIT((mqdec), v, "SIG", "ZC"); \
+        if (v) { \
+            jpc_mqdec_setcurctx((mqdec), JPC_GETSCCTXNO(f)); \
+            JPC_T1D_GETBIT((mqdec), v, "SIG", "SC"); \
+            v ^= JPC_GETSPB(f); \
+            JPC_UPDATEFLAGS4((fp), (frowstep), v, (vcausalflag)); \
+            *(fp) |= JPC_SIG; \
+            *(dp) = (v) ? (-(oneplushalf)) : (oneplushalf); \
+        } \
+        *(fp) |= JPC_VISIT; \
+    } \
 }
 
-static int dec_sigpass(jpc_dec_t *dec, register jpc_mqdec_t *mqdec, int bitpos, int orient,
-  int vcausalflag, jas_matrix_t *flags, jas_matrix_t *data)
-{
-	int i;
-	int j;
-	int one;
-	int half;
-	int oneplushalf;
-	int vscanlen;
-	int width;
-	int height;
-	jpc_fix_t *fp;
-	int frowstep;
-	int fstripestep;
-	jpc_fix_t *fstripestart;
-	jpc_fix_t *fvscanstart;
-	jpc_fix_t *dp;
-	int drowstep;
-	int dstripestep;
-	jpc_fix_t *dstripestart;
-	jpc_fix_t *dvscanstart;
-	int k;
-
-	width = jas_matrix_numcols(data);
-	height = jas_matrix_numrows(data);
-	frowstep = jas_matrix_rowstep(flags);
-	drowstep = jas_matrix_rowstep(data);
-	fstripestep = frowstep << 2;
-	dstripestep = drowstep << 2;
-
-	one = 1 << bitpos;
-	half = one >> 1;
-	oneplushalf = one | half;
-
-	fstripestart = jas_matrix_getref(flags, 1, 1);
-	dstripestart = jas_matrix_getref(data, 0, 0);
-	for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
-	  dstripestart += dstripestep) {
-		fvscanstart = fstripestart;
-		dvscanstart = dstripestart;
-		vscanlen = JAS_MIN(i, 4);
-		for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
-			fp = fvscanstart;
-			dp = dvscanstart;
-			k = vscanlen;
-
-			/* Process first sample in vertical scan. */
-			jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf,
-			  orient, mqdec, vcausalflag);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process second sample in vertical scan. */
-			jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf,
-			  orient, mqdec, 0);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process third sample in vertical scan. */
-			jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf,
-			  orient, mqdec, 0);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process fourth sample in vertical scan. */
-			jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf,
-			  orient, mqdec, 0);
-		}
-	}
-	return 0;
+#define jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf, in, vcausalflag) \
+{ \
+    jpc_fix_t f = *(fp); \
+    jpc_fix_t v; \
+    if ((f & JPC_OTHSIGMSK) && !(f & (JPC_SIG | JPC_VISIT))) { \
+        JPC_T1D_RAWGETBIT(in, v, "SIG", "ZC"); \
+        if (v < 0) { \
+            return -1; \
+        } \
+        if (v) { \
+            JPC_T1D_RAWGETBIT(in, v, "SIG", "SC"); \
+            if (v < 0) { \
+                return -1; \
+            } \
+            JPC_UPDATEFLAGS4((fp), (frowstep), v, (vcausalflag)); \
+            *(fp) |= JPC_SIG; \
+            *(dp) = v ? (-oneplushalf) : (oneplushalf); \
+        } \
+        *(fp) |= JPC_VISIT; \
+    } \
 }
 
-#define	jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf, in, vcausalflag) \
-{ \
-	jpc_fix_t f = *(fp); \
-	jpc_fix_t v; \
-	if ((f & JPC_OTHSIGMSK) && !(f & (JPC_SIG | JPC_VISIT))) { \
-		JPC_T1D_RAWGETBIT(in, v, "SIG", "ZC"); \
-		if (v < 0) { \
-			return -1; \
-		} \
-		if (v) { \
-			JPC_T1D_RAWGETBIT(in, v, "SIG", "SC"); \
-			if (v < 0) { \
-				return -1; \
-			} \
-			JPC_UPDATEFLAGS4((fp), (frowstep), v, (vcausalflag)); \
-			*(fp) |= JPC_SIG; \
-			*(dp) = v ? (-oneplushalf) : (oneplushalf); \
-		} \
-		*(fp) |= JPC_VISIT; \
-	} \
+
+
+static int
+dec_sigpass(jpc_dec_t *dec, register jpc_mqdec_t *mqdec, int bitpos,
+            int orient,
+            int vcausalflag, jas_matrix_t *flags, jas_matrix_t *data)
+{
+    int i;
+    int j;
+    int one;
+    int half;
+    int oneplushalf;
+    int vscanlen;
+    int width;
+    int height;
+    jpc_fix_t *fp;
+    int frowstep;
+    int fstripestep;
+    jpc_fix_t *fstripestart;
+    jpc_fix_t *fvscanstart;
+    jpc_fix_t *dp;
+    int drowstep;
+    int dstripestep;
+    jpc_fix_t *dstripestart;
+    jpc_fix_t *dvscanstart;
+    int k;
+
+    width = jas_matrix_numcols(data);
+    height = jas_matrix_numrows(data);
+    frowstep = jas_matrix_rowstep(flags);
+    drowstep = jas_matrix_rowstep(data);
+    fstripestep = frowstep << 2;
+    dstripestep = drowstep << 2;
+
+    one = 1 << bitpos;
+    half = one >> 1;
+    oneplushalf = one | half;
+
+    fstripestart = jas_matrix_getref(flags, 1, 1);
+    dstripestart = jas_matrix_getref(data, 0, 0);
+    for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
+      dstripestart += dstripestep) {
+        fvscanstart = fstripestart;
+        dvscanstart = dstripestart;
+        vscanlen = JAS_MIN(i, 4);
+        for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
+            fp = fvscanstart;
+            dp = dvscanstart;
+            k = vscanlen;
+
+            /* Process first sample in vertical scan. */
+            jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf,
+              orient, mqdec, vcausalflag);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process second sample in vertical scan. */
+            jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf,
+              orient, mqdec, 0);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process third sample in vertical scan. */
+            jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf,
+              orient, mqdec, 0);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process fourth sample in vertical scan. */
+            jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf,
+              orient, mqdec, 0);
+        }
+    }
+    return 0;
 }
 
-static int dec_rawsigpass(jpc_dec_t *dec, jpc_bitstream_t *in, int bitpos, int vcausalflag,
-  jas_matrix_t *flags, jas_matrix_t *data)
+
+
+static int
+dec_rawsigpass(jpc_dec_t *dec, jpc_bitstream_t *in, int bitpos,
+               int vcausalflag,
+               jas_matrix_t *flags, jas_matrix_t *data)
 {
-	int i;
-	int j;
-	int k;
-	int one;
-	int half;
-	int oneplushalf;
-	int vscanlen;
-	int width;
-	int height;
-	jpc_fix_t *fp;
-	int frowstep;
-	int fstripestep;
-	jpc_fix_t *fstripestart;
-	jpc_fix_t *fvscanstart;
-	jpc_fix_t *dp;
-	int drowstep;
-	int dstripestep;
-	jpc_fix_t *dstripestart;
-	jpc_fix_t *dvscanstart;
-
-	width = jas_matrix_numcols(data);
-	height = jas_matrix_numrows(data);
-	frowstep = jas_matrix_rowstep(flags);
-	drowstep = jas_matrix_rowstep(data);
-	fstripestep = frowstep << 2;
-	dstripestep = drowstep << 2;
-
-	one = 1 << bitpos;
-	half = one >> 1;
-	oneplushalf = one | half;
-
-	fstripestart = jas_matrix_getref(flags, 1, 1);
-	dstripestart = jas_matrix_getref(data, 0, 0);
-	for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
-	  dstripestart += dstripestep) {
-		fvscanstart = fstripestart;
-		dvscanstart = dstripestart;
-		vscanlen = JAS_MIN(i, 4);
-		for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
-			fp = fvscanstart;
-			dp = dvscanstart;
-			k = vscanlen;
-
-			/* Process first sample in vertical scan. */
-			jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf,
-			  in, vcausalflag);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process second sample in vertical scan. */
-			jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf,
-			  in, 0);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process third sample in vertical scan. */
-			jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf,
-			  in, 0);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process fourth sample in vertical scan. */
-			jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf,
-			  in, 0);
-
-		}
-	}
-	return 0;
+    int i;
+    int j;
+    int k;
+    int one;
+    int half;
+    int oneplushalf;
+    int vscanlen;
+    int width;
+    int height;
+    jpc_fix_t *fp;
+    int frowstep;
+    int fstripestep;
+    jpc_fix_t *fstripestart;
+    jpc_fix_t *fvscanstart;
+    jpc_fix_t *dp;
+    int drowstep;
+    int dstripestep;
+    jpc_fix_t *dstripestart;
+    jpc_fix_t *dvscanstart;
+
+    width = jas_matrix_numcols(data);
+    height = jas_matrix_numrows(data);
+    frowstep = jas_matrix_rowstep(flags);
+    drowstep = jas_matrix_rowstep(data);
+    fstripestep = frowstep << 2;
+    dstripestep = drowstep << 2;
+
+    one = 1 << bitpos;
+    half = one >> 1;
+    oneplushalf = one | half;
+
+    fstripestart = jas_matrix_getref(flags, 1, 1);
+    dstripestart = jas_matrix_getref(data, 0, 0);
+    for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
+      dstripestart += dstripestep) {
+        fvscanstart = fstripestart;
+        dvscanstart = dstripestart;
+        vscanlen = JAS_MIN(i, 4);
+        for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
+            fp = fvscanstart;
+            dp = dvscanstart;
+            k = vscanlen;
+
+            /* Process first sample in vertical scan. */
+            jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf,
+              in, vcausalflag);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process second sample in vertical scan. */
+            jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf,
+              in, 0);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process third sample in vertical scan. */
+            jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf,
+              in, 0);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process fourth sample in vertical scan. */
+            jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf,
+              in, 0);
+
+        }
+    }
+    return 0;
 }
 
+
+
 /******************************************************************************\
 * Code for refinement pass.
 \******************************************************************************/
 
-#define	jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec, vcausalflag) \
+#define jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec, vcausalflag) \
 { \
-	int v; \
-	int t; \
-	if (((*(fp)) & (JPC_SIG | JPC_VISIT)) == JPC_SIG) { \
-		jpc_mqdec_setcurctx((mqdec), JPC_GETMAGCTXNO(*(fp))); \
-		JPC_T1D_GETBITNOSKEW((mqdec), v, "REF", "MR"); \
-		t = (v ? (poshalf) : (neghalf)); \
-		*(dp) += (*(dp) < 0) ? (-t) : t; \
-		*(fp) |= JPC_REFINE; \
-	} \
+    int v; \
+    int t; \
+    if (((*(fp)) & (JPC_SIG | JPC_VISIT)) == JPC_SIG) { \
+        jpc_mqdec_setcurctx((mqdec), JPC_GETMAGCTXNO(*(fp))); \
+        JPC_T1D_GETBITNOSKEW((mqdec), v, "REF", "MR"); \
+        t = (v ? (poshalf) : (neghalf)); \
+        *(dp) += (*(dp) < 0) ? (-t) : t; \
+        *(fp) |= JPC_REFINE; \
+    } \
 }
 
-static int dec_refpass(jpc_dec_t *dec, register jpc_mqdec_t *mqdec, int bitpos,
-  int vcausalflag, jas_matrix_t *flags, jas_matrix_t *data)
+
+
+static int
+dec_refpass(jpc_dec_t *dec, register jpc_mqdec_t *mqdec, int bitpos,
+            int vcausalflag, jas_matrix_t *flags, jas_matrix_t *data)
 {
-	int i;
-	int j;
-	int vscanlen;
-	int width;
-	int height;
-	int one;
-	int poshalf;
-	int neghalf;
-	jpc_fix_t *fp;
-	int frowstep;
-	int fstripestep;
-	jpc_fix_t *fstripestart;
-	jpc_fix_t *fvscanstart;
-	jpc_fix_t *dp;
-	int drowstep;
-	int dstripestep;
-	jpc_fix_t *dstripestart;
-	jpc_fix_t *dvscanstart;
-	int k;
-
-	width = jas_matrix_numcols(data);
-	height = jas_matrix_numrows(data);
-	frowstep = jas_matrix_rowstep(flags);
-	drowstep = jas_matrix_rowstep(data);
-	fstripestep = frowstep << 2;
-	dstripestep = drowstep << 2;
-
-	one = 1 << bitpos;
-	poshalf = one >> 1;
-	neghalf = (bitpos > 0) ? (-poshalf) : (-1);
-
-	fstripestart = jas_matrix_getref(flags, 1, 1);
-	dstripestart = jas_matrix_getref(data, 0, 0);
-	for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
-	  dstripestart += dstripestep) {
-		fvscanstart = fstripestart;
-		dvscanstart = dstripestart;
-		vscanlen = JAS_MIN(i, 4);
-		for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
-			fp = fvscanstart;
-			dp = dvscanstart;
-			k = vscanlen;
-
-			/* Process first sample in vertical scan. */
-			jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec,
-			  vcausalflag);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process second sample in vertical scan. */
-			jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec, 0);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process third sample in vertical scan. */
-			jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec, 0);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process fourth sample in vertical scan. */
-			jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec, 0);
-		}
-	}
-
-	return 0;
+    int i;
+    int j;
+    int vscanlen;
+    int width;
+    int height;
+    int one;
+    int poshalf;
+    int neghalf;
+    jpc_fix_t *fp;
+    int frowstep;
+    int fstripestep;
+    jpc_fix_t *fstripestart;
+    jpc_fix_t *fvscanstart;
+    jpc_fix_t *dp;
+    int drowstep;
+    int dstripestep;
+    jpc_fix_t *dstripestart;
+    jpc_fix_t *dvscanstart;
+    int k;
+
+    width = jas_matrix_numcols(data);
+    height = jas_matrix_numrows(data);
+    frowstep = jas_matrix_rowstep(flags);
+    drowstep = jas_matrix_rowstep(data);
+    fstripestep = frowstep << 2;
+    dstripestep = drowstep << 2;
+
+    one = 1 << bitpos;
+    poshalf = one >> 1;
+    neghalf = (bitpos > 0) ? (-poshalf) : (-1);
+
+    fstripestart = jas_matrix_getref(flags, 1, 1);
+    dstripestart = jas_matrix_getref(data, 0, 0);
+    for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
+      dstripestart += dstripestep) {
+        fvscanstart = fstripestart;
+        dvscanstart = dstripestart;
+        vscanlen = JAS_MIN(i, 4);
+        for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
+            fp = fvscanstart;
+            dp = dvscanstart;
+            k = vscanlen;
+
+            /* Process first sample in vertical scan. */
+            jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec,
+              vcausalflag);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process second sample in vertical scan. */
+            jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec, 0);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process third sample in vertical scan. */
+            jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec, 0);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process fourth sample in vertical scan. */
+            jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec, 0);
+        }
+    }
+
+    return 0;
 }
 
-#define	jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in, vcausalflag) \
+#define jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in, vcausalflag) \
 { \
-	jpc_fix_t v; \
-	jpc_fix_t t; \
-	if (((*(fp)) & (JPC_SIG | JPC_VISIT)) == JPC_SIG) { \
-		JPC_T1D_RAWGETBIT(in, v, "REF", "MAGREF"); \
-		if (v < 0) { \
-			return -1; \
-		} \
-		t = (v ? poshalf : neghalf); \
-		*(dp) += (*(dp) < 0) ? (-t) : t; \
-		*(fp) |= JPC_REFINE; \
-	} \
+    jpc_fix_t v; \
+    jpc_fix_t t; \
+    if (((*(fp)) & (JPC_SIG | JPC_VISIT)) == JPC_SIG) { \
+        JPC_T1D_RAWGETBIT(in, v, "REF", "MAGREF"); \
+        if (v < 0) { \
+            return -1; \
+        } \
+        t = (v ? poshalf : neghalf); \
+        *(dp) += (*(dp) < 0) ? (-t) : t; \
+        *(fp) |= JPC_REFINE; \
+    } \
 }
 
-static int dec_rawrefpass(jpc_dec_t *dec, jpc_bitstream_t *in, int bitpos, int vcausalflag,
-  jas_matrix_t *flags, jas_matrix_t *data)
+
+
+static int
+dec_rawrefpass(jpc_dec_t *dec, jpc_bitstream_t *in, int bitpos,
+               int vcausalflag,
+               jas_matrix_t *flags, jas_matrix_t *data)
 {
-	int i;
-	int j;
-	int k;
-	int vscanlen;
-	int width;
-	int height;
-	int one;
-	int poshalf;
-	int neghalf;
-	jpc_fix_t *fp;
-	int frowstep;
-	int fstripestep;
-	jpc_fix_t *fstripestart;
-	jpc_fix_t *fvscanstart;
-	jpc_fix_t *dp;
-	int drowstep;
-	int dstripestep;
-	jpc_fix_t *dstripestart;
-	jpc_fix_t *dvscanstart;
-
-	width = jas_matrix_numcols(data);
-	height = jas_matrix_numrows(data);
-	frowstep = jas_matrix_rowstep(flags);
-	drowstep = jas_matrix_rowstep(data);
-	fstripestep = frowstep << 2;
-	dstripestep = drowstep << 2;
-
-	one = 1 << bitpos;
-	poshalf = one >> 1;
-	neghalf = (bitpos > 0) ? (-poshalf) : (-1);
-
-	fstripestart = jas_matrix_getref(flags, 1, 1);
-	dstripestart = jas_matrix_getref(data, 0, 0);
-	for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
-	  dstripestart += dstripestep) {
-		fvscanstart = fstripestart;
-		dvscanstart = dstripestart;
-		vscanlen = JAS_MIN(i, 4);
-		for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
-			fp = fvscanstart;
-			dp = dvscanstart;
-			k = vscanlen;
-
-			/* Process first sample in vertical scan. */
-			jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in,
-			  vcausalflag);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process second sample in vertical scan. */
-			jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in, 0);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process third sample in vertical scan. */
-			jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in, 0);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process fourth sample in vertical scan. */
-			jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in, 0);
-		}
-	}
-	return 0;
+    int i;
+    int j;
+    int k;
+    int vscanlen;
+    int width;
+    int height;
+    int one;
+    int poshalf;
+    int neghalf;
+    jpc_fix_t *fp;
+    int frowstep;
+    int fstripestep;
+    jpc_fix_t *fstripestart;
+    jpc_fix_t *fvscanstart;
+    jpc_fix_t *dp;
+    int drowstep;
+    int dstripestep;
+    jpc_fix_t *dstripestart;
+    jpc_fix_t *dvscanstart;
+
+    width = jas_matrix_numcols(data);
+    height = jas_matrix_numrows(data);
+    frowstep = jas_matrix_rowstep(flags);
+    drowstep = jas_matrix_rowstep(data);
+    fstripestep = frowstep << 2;
+    dstripestep = drowstep << 2;
+
+    one = 1 << bitpos;
+    poshalf = one >> 1;
+    neghalf = (bitpos > 0) ? (-poshalf) : (-1);
+
+    fstripestart = jas_matrix_getref(flags, 1, 1);
+    dstripestart = jas_matrix_getref(data, 0, 0);
+    for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
+      dstripestart += dstripestep) {
+        fvscanstart = fstripestart;
+        dvscanstart = dstripestart;
+        vscanlen = JAS_MIN(i, 4);
+        for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
+            fp = fvscanstart;
+            dp = dvscanstart;
+            k = vscanlen;
+
+            /* Process first sample in vertical scan. */
+            jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in,
+              vcausalflag);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process second sample in vertical scan. */
+            jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in, 0);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process third sample in vertical scan. */
+            jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in, 0);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process fourth sample in vertical scan. */
+            jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in, 0);
+        }
+    }
+    return 0;
 }
 
+
+
 /******************************************************************************\
 * Code for cleanup pass.
 \******************************************************************************/
 
-#define	jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient, mqdec, flabel, plabel, vcausalflag) \
+#define jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient, mqdec, flabel, plabel, vcausalflag) \
 { \
-	int v; \
+    int v; \
 flabel \
-	if (!((f) & (JPC_SIG | JPC_VISIT))) { \
-		jpc_mqdec_setcurctx((mqdec), JPC_GETZCCTXNO((f), (orient))); \
-		JPC_T1D_GETBIT((mqdec), v, "CLN", "ZC"); \
-		if (v) { \
+    if (!((f) & (JPC_SIG | JPC_VISIT))) { \
+        jpc_mqdec_setcurctx((mqdec), JPC_GETZCCTXNO((f), (orient))); \
+        JPC_T1D_GETBIT((mqdec), v, "CLN", "ZC"); \
+        if (v) { \
 plabel \
-			/* Coefficient is significant. */ \
-			jpc_mqdec_setcurctx((mqdec), JPC_GETSCCTXNO(f)); \
-			JPC_T1D_GETBIT((mqdec), v, "CLN", "SC"); \
-			v ^= JPC_GETSPB(f); \
-			*(dp) = (v) ? (-(oneplushalf)) : (oneplushalf); \
-			JPC_UPDATEFLAGS4((fp), (frowstep), v, (vcausalflag)); \
-			*(fp) |= JPC_SIG; \
-		} \
-	} \
-	/* XXX - Is this correct?  Can aggregation cause some VISIT bits not to be reset?  Check. */ \
-	*(fp) &= ~JPC_VISIT; \
+            /* Coefficient is significant. */ \
+            jpc_mqdec_setcurctx((mqdec), JPC_GETSCCTXNO(f)); \
+            JPC_T1D_GETBIT((mqdec), v, "CLN", "SC"); \
+            v ^= JPC_GETSPB(f); \
+            *(dp) = (v) ? (-(oneplushalf)) : (oneplushalf); \
+            JPC_UPDATEFLAGS4((fp), (frowstep), v, (vcausalflag)); \
+            *(fp) |= JPC_SIG; \
+        } \
+    } \
+    /* XXX - Is this correct?  Can aggregation cause some VISIT bits not to be reset?  Check. */ \
+    *(fp) &= ~JPC_VISIT; \
 }
 
-static int dec_clnpass(jpc_dec_t *dec, register jpc_mqdec_t *mqdec, int bitpos, int orient,
-  int vcausalflag, int segsymflag, jas_matrix_t *flags, jas_matrix_t *data)
+static int
+dec_clnpass(jpc_dec_t *dec, register jpc_mqdec_t *mqdec, int bitpos,
+            int orient, int vcausalflag, int segsymflag, jas_matrix_t *flags,
+            jas_matrix_t *data)
 {
-	int i;
-	int j;
-	int k;
-	int vscanlen;
-	int v;
-	int half;
-	int runlen;
-	int f;
-	int width;
-	int height;
-	int one;
-	int oneplushalf;
-
-	jpc_fix_t *fp;
-	int frowstep;
-	int fstripestep;
-	jpc_fix_t *fstripestart;
-	jpc_fix_t *fvscanstart;
-
-	jpc_fix_t *dp;
-	int drowstep;
-	int dstripestep;
-	jpc_fix_t *dstripestart;
-	jpc_fix_t *dvscanstart;
-
-	one = 1 << bitpos;
-	half = one >> 1;
-	oneplushalf = one | half;
-
-	width = jas_matrix_numcols(data);
-	height = jas_matrix_numrows(data);
-
-	frowstep = jas_matrix_rowstep(flags);
-	drowstep = jas_matrix_rowstep(data);
-	fstripestep = frowstep << 2;
-	dstripestep = drowstep << 2;
-
-	fstripestart = jas_matrix_getref(flags, 1, 1);
-	dstripestart = jas_matrix_getref(data, 0, 0);
-	for (i = 0; i < height; i += 4, fstripestart += fstripestep,
-	  dstripestart += dstripestep) {
-		fvscanstart = fstripestart;
-		dvscanstart = dstripestart;
-		vscanlen = JAS_MIN(4, height - i);
-		for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
-			fp = fvscanstart;
-			if (vscanlen >= 4 && (!((*fp) & (JPC_SIG | JPC_VISIT |
-			  JPC_OTHSIGMSK))) && (fp += frowstep, !((*fp) & (JPC_SIG |
-			  JPC_VISIT | JPC_OTHSIGMSK))) && (fp += frowstep, !((*fp) &
-			  (JPC_SIG | JPC_VISIT | JPC_OTHSIGMSK))) && (fp += frowstep,
-			  !((*fp) & (JPC_SIG | JPC_VISIT | JPC_OTHSIGMSK)))) {
-
-				jpc_mqdec_setcurctx(mqdec, JPC_AGGCTXNO);
-				JPC_T1D_GETBIT(mqdec, v, "CLN", "AGG");
-				if (!v) {
-					continue;
-				}
-				jpc_mqdec_setcurctx(mqdec, JPC_UCTXNO);
-				JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "RL");
-				runlen = v;
-				JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "RL");
-				runlen = (runlen << 1) | v;
-				f = *(fp = fvscanstart + frowstep * runlen);
-				dp = dvscanstart + drowstep * runlen;
-				k = vscanlen - runlen;
-				switch (runlen) {
-				case 0:
-					goto clnpass_partial0;
-					break;
-				case 1:
-					goto clnpass_partial1;
-					break;
-				case 2:
-					goto clnpass_partial2;
-					break;
-				case 3:
-					goto clnpass_partial3;
-					break;
-				}
-			} else {
-				f = *(fp = fvscanstart);
-				dp = dvscanstart;
-				k = vscanlen;
-				goto clnpass_full0;
-			}
-
-			/* Process first sample in vertical scan. */
-			jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient,
-			  mqdec, clnpass_full0:, clnpass_partial0:,
-			  vcausalflag);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process second sample in vertical scan. */
-			f = *fp;
-			jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient,
-				mqdec, ;, clnpass_partial1:, 0);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process third sample in vertical scan. */
-			f = *fp;
-			jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient,
-				mqdec, ;, clnpass_partial2:, 0);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process fourth sample in vertical scan. */
-			f = *fp;
-			jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient,
-				mqdec, ;, clnpass_partial3:, 0);
-		}
-	}
-
-	if (segsymflag) {
-		int segsymval;
-		segsymval = 0;
-		jpc_mqdec_setcurctx(mqdec, JPC_UCTXNO);
-		JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "SEGSYM");
-		segsymval = (segsymval << 1) | (v & 1);
-		JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "SEGSYM");
-		segsymval = (segsymval << 1) | (v & 1);
-		JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "SEGSYM");
-		segsymval = (segsymval << 1) | (v & 1);
-		JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "SEGSYM");
-		segsymval = (segsymval << 1) | (v & 1);
-		if (segsymval != 0xa) {
-			fprintf(stderr, "warning: bad segmentation symbol\n");
-		}
-	}
-
-	return 0;
+    int i;
+    int j;
+    int k;
+    int vscanlen;
+    int v;
+    int half;
+    int runlen;
+    int f;
+    int width;
+    int height;
+    int one;
+    int oneplushalf;
+
+    jpc_fix_t *fp;
+    int frowstep;
+    int fstripestep;
+    jpc_fix_t *fstripestart;
+    jpc_fix_t *fvscanstart;
+
+    jpc_fix_t *dp;
+    int drowstep;
+    int dstripestep;
+    jpc_fix_t *dstripestart;
+    jpc_fix_t *dvscanstart;
+
+    one = 1 << bitpos;
+    half = one >> 1;
+    oneplushalf = one | half;
+
+    width = jas_matrix_numcols(data);
+    height = jas_matrix_numrows(data);
+
+    frowstep = jas_matrix_rowstep(flags);
+    drowstep = jas_matrix_rowstep(data);
+    fstripestep = frowstep << 2;
+    dstripestep = drowstep << 2;
+
+    fstripestart = jas_matrix_getref(flags, 1, 1);
+    dstripestart = jas_matrix_getref(data, 0, 0);
+    for (i = 0; i < height; i += 4, fstripestart += fstripestep,
+      dstripestart += dstripestep) {
+        fvscanstart = fstripestart;
+        dvscanstart = dstripestart;
+        vscanlen = JAS_MIN(4, height - i);
+        for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
+            fp = fvscanstart;
+            if (vscanlen >= 4 && (!((*fp) & (JPC_SIG | JPC_VISIT |
+              JPC_OTHSIGMSK))) && (fp += frowstep, !((*fp) & (JPC_SIG |
+              JPC_VISIT | JPC_OTHSIGMSK))) && (fp += frowstep, !((*fp) &
+              (JPC_SIG | JPC_VISIT | JPC_OTHSIGMSK))) && (fp += frowstep,
+              !((*fp) & (JPC_SIG | JPC_VISIT | JPC_OTHSIGMSK)))) {
+
+                jpc_mqdec_setcurctx(mqdec, JPC_AGGCTXNO);
+                JPC_T1D_GETBIT(mqdec, v, "CLN", "AGG");
+                if (!v) {
+                    continue;
+                }
+                jpc_mqdec_setcurctx(mqdec, JPC_UCTXNO);
+                JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "RL");
+                runlen = v;
+                JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "RL");
+                runlen = (runlen << 1) | v;
+                f = *(fp = fvscanstart + frowstep * runlen);
+                dp = dvscanstart + drowstep * runlen;
+                k = vscanlen - runlen;
+                switch (runlen) {
+                case 0:
+                    goto clnpass_partial0;
+                    break;
+                case 1:
+                    goto clnpass_partial1;
+                    break;
+                case 2:
+                    goto clnpass_partial2;
+                    break;
+                case 3:
+                    goto clnpass_partial3;
+                    break;
+                }
+            } else {
+                f = *(fp = fvscanstart);
+                dp = dvscanstart;
+                k = vscanlen;
+                goto clnpass_full0;
+            }
+
+            /* Process first sample in vertical scan. */
+            jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient,
+              mqdec, clnpass_full0:, clnpass_partial0:,
+              vcausalflag);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process second sample in vertical scan. */
+            f = *fp;
+            jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient,
+                mqdec, ;, clnpass_partial1:, 0);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process third sample in vertical scan. */
+            f = *fp;
+            jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient,
+                mqdec, ;, clnpass_partial2:, 0);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process fourth sample in vertical scan. */
+            f = *fp;
+            jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient,
+                mqdec, ;, clnpass_partial3:, 0);
+        }
+    }
+
+    if (segsymflag) {
+        int segsymval;
+        segsymval = 0;
+        jpc_mqdec_setcurctx(mqdec, JPC_UCTXNO);
+        JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "SEGSYM");
+        segsymval = (segsymval << 1) | (v & 1);
+        JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "SEGSYM");
+        segsymval = (segsymval << 1) | (v & 1);
+        JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "SEGSYM");
+        segsymval = (segsymval << 1) | (v & 1);
+        JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "SEGSYM");
+        segsymval = (segsymval << 1) | (v & 1);
+        if (segsymval != 0xa) {
+            fprintf(stderr, "warning: bad segmentation symbol\n");
+        }
+    }
+
+    return 0;
+}
+
+
+
+static void
+jpc_dec_decodecblk(jpc_dec_t *       const dec,
+                   jpc_dec_tile_t *  const tile,
+                   jpc_dec_tcomp_t * const tcomp,
+                   jpc_dec_band_t *  const band,
+                   jpc_dec_cblk_t *  const cblk,
+                   int               const dopartial,
+                   int               const maxlyrs,
+                   const char **     const errorP) {
+
+    jpc_dec_seg_t *seg;
+    int i;
+    int bpno;
+    int passtype;
+    int ret;
+    int compno;
+    int filldata;
+    int fillmask;
+    jpc_dec_ccp_t *ccp;
+
+    compno = tcomp - tile->tcomps;
+
+    if (!cblk->flags) {
+        /* Note: matrix is assumed to be zeroed */
+        unsigned int const nrow = jas_matrix_numrows(cblk->data) + 2;
+        unsigned int const ncol = jas_matrix_numcols(cblk->data) + 2;
+        cblk->flags = jas_matrix_create(nrow, ncol);
+        if (!cblk->flags) {
+            pm_asprintf(errorP, "Out of memory allocating a flags matrix of "
+                        "%u rows by %u columns", nrow, ncol);
+            return;
+        }
+    }
+
+    seg = cblk->segs.head;
+    while (seg && (seg != cblk->curseg || dopartial) && (maxlyrs < 0 ||
+      seg->lyrno < maxlyrs)) {
+        assert(seg->numpasses >= seg->maxpasses || dopartial);
+        assert(seg->stream);
+        jas_stream_rewind(seg->stream);
+        jas_stream_setrwcount(seg->stream, 0);
+        if (seg->type == JPC_SEG_MQ) {
+            if (!cblk->mqdec) {
+                if (!(cblk->mqdec = jpc_mqdec_create(JPC_NUMCTXS, 0))) {
+                    pm_asprintf(errorP, "jpc_mqdec_create failed");
+                    return;
+                }
+                jpc_mqdec_setctxs(cblk->mqdec, JPC_NUMCTXS, jpc_mqctxs);
+            }
+            jpc_mqdec_setinput(cblk->mqdec, seg->stream);
+            jpc_mqdec_init(cblk->mqdec);
+        } else {
+            assert(seg->type == JPC_SEG_RAW);
+            if (!cblk->nulldec) {
+                if (!(cblk->nulldec = jpc_bitstream_sopen(seg->stream, "r"))) {
+                    assert(0);
+                }
+            }
+        }
+
+
+        for (i = 0; i < seg->numpasses; ++i) {
+            if (cblk->numimsbs > band->numbps) {
+                ccp = &tile->cp->ccps[compno];
+                if (ccp->roishift <= 0) {
+                    fprintf(stderr, "warning: corrupt code stream\n");
+                } else {
+                    if (cblk->numimsbs < ccp->roishift - band->numbps) {
+                        fprintf(stderr, "warning: corrupt code stream\n");
+                    }
+                }
+            }
+            bpno = band->roishift + band->numbps - 1 - (cblk->numimsbs +
+              (seg->passno + i - cblk->firstpassno + 2) / 3);
+            if (bpno < 0) {
+                goto exit;
+            }
+#if 1
+            passtype = (seg->passno + i + 2) % 3;
+#else
+            passtype = JPC_PASSTYPE(seg->passno + i + 2);
+#endif
+            assert(bpno >= 0 && bpno < 31);
+            switch (passtype) {
+            case JPC_SIGPASS:
+                ret = (seg->type == JPC_SEG_MQ) ? dec_sigpass(dec,
+                  cblk->mqdec, bpno, band->orient,
+                  (tile->cp->ccps[compno].cblkctx & JPC_COX_VSC) != 0,
+                  cblk->flags, cblk->data) :
+                  dec_rawsigpass(dec, cblk->nulldec, bpno,
+                  (tile->cp->ccps[compno].cblkctx & JPC_COX_VSC) != 0,
+                  cblk->flags, cblk->data);
+                break;
+            case JPC_REFPASS:
+                ret = (seg->type == JPC_SEG_MQ) ?
+                  dec_refpass(dec, cblk->mqdec, bpno,
+                  (tile->cp->ccps[compno].cblkctx & JPC_COX_VSC) != 0,
+                  cblk->flags, cblk->data) :
+                  dec_rawrefpass(dec, cblk->nulldec, bpno,
+                  (tile->cp->ccps[compno].cblkctx & JPC_COX_VSC) != 0,
+                  cblk->flags, cblk->data);
+                break;
+            case JPC_CLNPASS:
+                assert(seg->type == JPC_SEG_MQ);
+                ret = dec_clnpass(dec, cblk->mqdec, bpno,
+                  band->orient, (tile->cp->ccps[compno].cblkctx &
+                  JPC_COX_VSC) != 0, (tile->cp->ccps[compno].cblkctx &
+                  JPC_COX_SEGSYM) != 0, cblk->flags,
+                  cblk->data);
+                break;
+            default:
+                ret = -1;
+                break;
+            }
+            /* Do we need to reset after each coding pass? */
+            if (tile->cp->ccps[compno].cblkctx & JPC_COX_RESET) {
+                jpc_mqdec_setctxs(cblk->mqdec, JPC_NUMCTXS, jpc_mqctxs);
+            }
+
+            if (ret) {
+                pm_asprintf(errorP,
+                            "coding pass failed passtype=%d segtype=%d",
+                            passtype, seg->type);
+                return;
+            }
+
+        }
+
+        if (seg->type == JPC_SEG_MQ) {
+            /* Note: dont destroy mq decoder because context info will be
+               lost
+            */
+        } else {
+            assert(seg->type == JPC_SEG_RAW);
+            if (tile->cp->ccps[compno].cblkctx & JPC_COX_PTERM) {
+                fillmask = 0x7f;
+                filldata = 0x2a;
+            } else {
+                fillmask = 0;
+                filldata = 0;
+            }
+            if ((ret = jpc_bitstream_inalign(cblk->nulldec, fillmask,
+              filldata)) < 0) {
+                pm_asprintf(errorP, "jpc_bitstream_inalign failed");
+                return;
+            } else if (ret > 0) {
+                pm_message("warning: bad termination pattern detected");
+            }
+            jpc_bitstream_close(cblk->nulldec);
+            cblk->nulldec = 0;
+        }
+
+        cblk->curseg = seg->next;
+        jpc_seglist_remove(&cblk->segs, seg);
+        jpc_seg_destroy(seg);
+        seg = cblk->curseg;
+    }
+
+    assert(dopartial ? (!cblk->curseg) : 1);
+
+exit:
+    *errorP = NULL;
 }
+
+
+
+void
+jpc_dec_decodecblks(jpc_dec_t *      const decP,
+                    jpc_dec_tile_t * const tileP,
+                    const char **    const errorP) {
+/*----------------------------------------------------------------------------
+  Decode all of the code blocks for a particular tile
+-----------------------------------------------------------------------------*/
+    unsigned int compcnt;
+    jpc_dec_tcomp_t * tcompP;
+
+    for (compcnt = 0, tcompP = tileP->tcomps;
+         compcnt < decP->numcomps;
+         ++compcnt, ++tcompP) {
+
+        unsigned int rlvlcnt;
+        jpc_dec_rlvl_t * rlvlP;
+
+        for (rlvlcnt = 0, rlvlP = tcompP->rlvls;
+             rlvlcnt < tcompP->numrlvls;
+             ++rlvlcnt, ++rlvlP) {
+
+            if (rlvlP->bands) {
+                unsigned int bandcnt;
+                jpc_dec_band_t * bandP;
+
+                for (bandcnt = 0, bandP = rlvlP->bands;
+                     bandcnt < rlvlP->numbands;
+                     ++bandcnt, ++bandP) {
+
+                    if (bandP->data) {
+                        unsigned int prccnt;
+                        jpc_dec_prc_t * prcP;
+
+                        for (prccnt = 0, prcP = bandP->prcs;
+                             prccnt < rlvlP->numprcs;
+                             ++prccnt, ++prcP) {
+
+                            if (prcP->cblks) {
+                                unsigned int cblkcnt;
+                                jpc_dec_cblk_t * cblkP;
+
+                                for (cblkcnt = 0, cblkP = prcP->cblks;
+                                     cblkcnt < prcP->numcblks;
+                                     ++cblkcnt, ++cblkP) {
+
+                                    const char * error;
+
+                                    jpc_dec_decodecblk(decP, tileP, tcompP,
+                                                       bandP, cblkP, 1,
+                                                       JPC_MAXLYRS, &error);
+                                    if (error) {
+                                        pm_asprintf(errorP,
+                                                    "jpc_dec_decodecblk "
+                                                    "failed on component %u, "
+                                                    "resolution level %u, "
+                                                    "band %u, prc %u, "
+                                                    "code block %u.  %s",
+                                                    compcnt, rlvlcnt, bandcnt,
+                                                    prccnt, cblkcnt, error);
+                                        pm_strfree(error);
+                                        return;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    *errorP = NULL;
+}
+
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.h b/converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.h
index e28a1f57..f8b3b342 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.h
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.h
@@ -119,19 +119,13 @@
 #ifndef JPC_T1DEC_H
 #define JPC_T1DEC_H
 
-/******************************************************************************\
-* Includes.
-\******************************************************************************/
-
 #include "jpc_dec.h"
 #include "jpc_mqdec.h"
 #include "jpc_t1cod.h"
 
-/******************************************************************************\
-* Functions.
-\******************************************************************************/
-
-/* Decode all of the code blocks for a particular tile. */
-int jpc_dec_decodecblks(jpc_dec_t *dec, jpc_dec_tile_t *tile);
+void
+jpc_dec_decodecblks(jpc_dec_t *      const decP,
+                    jpc_dec_tile_t * const tileP,
+                    const char **    const errorP);
 
 #endif
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_t1enc.c b/converter/other/jpeg2000/libjasper/jpc/jpc_t1enc.c
index e1af0f61..34b9738c 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_t1enc.c
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_t1enc.c
@@ -124,6 +124,8 @@
 #include <stdlib.h>
 #include <assert.h>
 
+#include "netpbm/nstring.h"
+
 #include "jasper/jas_fix.h"
 #include "jasper/jas_malloc.h"
 #include "jasper/jas_math.h"
@@ -149,74 +151,111 @@ static int jpc_encrawsigpass(jpc_bitstream_t *out, int bitpos, int,
 static int jpc_encrawrefpass(jpc_bitstream_t *out, int bitpos, int,
   jas_matrix_t *flags, jas_matrix_t *data, int term, long *nmsedec);
 
-/******************************************************************************\
+/*****************************************************************************\
 * Code for encoding code blocks.
-\******************************************************************************/
+\*****************************************************************************/
 
-/* Encode all of the code blocks associated with the current tile. */
-int jpc_enc_enccblks(jpc_enc_t *enc)
-{
-    jpc_enc_tcmpt_t *tcmpt;
-    jpc_enc_tcmpt_t *endcomps;
-    jpc_enc_rlvl_t *lvl;
-    jpc_enc_rlvl_t *endlvls;
-    jpc_enc_band_t *band;
-    jpc_enc_band_t *endbands;
-    jpc_enc_cblk_t *cblk;
-    jpc_enc_cblk_t *endcblks;
-    int i;
-    int j;
-    int mx;
-    int bmx;
-    int v;
-    jpc_enc_tile_t *tile;
-    uint_fast32_t prcno;
-    jpc_enc_prc_t *prc;
+static void
+encodeBlocksOfPrecinct(jpc_enc_prc_t *   const prcP,
+                       jpc_enc_band_t *  const bandP,
+                       jpc_enc_tcmpt_t * const tcmptP,
+                       jpc_enc_t *       const encoderP,
+                       const char **     const errorP) {
 
-    tile = enc->curtile;
+    if (prcP->cblks) {
+        int bmx;
+        uint_fast32_t cblkno;
 
-    endcomps = &tile->tcmpts[tile->numtcmpts];
-    for (tcmpt = tile->tcmpts; tcmpt != endcomps; ++tcmpt) {
-        endlvls = &tcmpt->rlvls[tcmpt->numrlvls];
-        for (lvl = tcmpt->rlvls; lvl != endlvls; ++lvl) {
-            if (!lvl->bands) {
-                continue;
-            }
-            endbands = &lvl->bands[lvl->numbands];
-            for (band = lvl->bands; band != endbands; ++band) {
-                if (!band->data) {
-                    continue;
+        for (cblkno = 0, bmx = 0; cblkno < prcP->numcblks; ++ cblkno) {
+            jpc_enc_cblk_t * const cblkP = &prcP->cblks[cblkno];
+
+            int mx;
+            uint_fast32_t row;
+
+            for (row = 0, mx = 0;
+                 row < jas_matrix_numrows(cblkP->data);
+                 ++row) {
+
+                uint_fast32_t col;
+
+                for (col = 0; col < jas_matrix_numcols(cblkP->data); ++col) {
+                    int const v = abs(jas_matrix_get(cblkP->data, row, col));
+                    if (v > mx)
+                        mx = v;
                 }
-                for (prcno = 0, prc = band->prcs; prcno < lvl->numprcs; ++prcno, ++prc) {
-                    if (!prc->cblks) {
-                        continue;
-                    }
-                    bmx = 0;
-                    endcblks = &prc->cblks[prc->numcblks];
-                    for (cblk = prc->cblks; cblk != endcblks; ++cblk) {
-                        mx = 0;
-                        for (i = 0; i < jas_matrix_numrows(cblk->data); ++i) {
-                            for (j = 0; j < jas_matrix_numcols(cblk->data); ++j) {
-                                v = abs(jas_matrix_get(cblk->data, i, j));
-                                if (v > mx) {
-                                    mx = v;
-                                }
-                            }
-                        }
-                        if (mx > bmx) {
-                            bmx = mx;
-                        }
-                        cblk->numbps = JAS_MAX(jpc_firstone(mx) + 1 - JPC_NUMEXTRABITS, 0);
-                    }
+            }
+            if (mx > bmx)
+                bmx = mx;
 
-                    for (cblk = prc->cblks; cblk != endcblks; ++cblk) {
-                        cblk->numimsbs = band->numbps - cblk->numbps;
-                        assert(cblk->numimsbs >= 0);
-                    }
+            cblkP->numbps = MAX(jpc_firstone(mx) + 1 - JPC_NUMEXTRABITS, 0);
+        }
+
+        for (cblkno = 0; cblkno < prcP->numcblks; ++ cblkno) {
+            jpc_enc_cblk_t * const cblkP = &prcP->cblks[cblkno];
 
-                    for (cblk = prc->cblks; cblk != endcblks; ++cblk) {
-                        if (jpc_enc_enccblk(enc, cblk->stream, tcmpt, band, cblk)) {
-                            return -1;
+            assert(cblkP->numbps <= bandP->numbps);
+        }
+
+        for (cblkno = 0, *errorP = NULL;
+             cblkno < prcP->numcblks && !*errorP;
+             ++ cblkno) {
+
+            jpc_enc_cblk_t * const cblkP = &prcP->cblks[cblkno];
+
+            int rc;
+
+            rc = jpc_enc_enccblk(encoderP,
+                                 cblkP->stream, tcmptP, bandP, cblkP);
+            if (rc != 0)
+                pm_asprintf(errorP, "Encoding failed on code block %u "
+                            "of %u", (unsigned)cblkno,
+                            (unsigned)prcP->numcblks);
+        }
+    } else
+        *errorP = NULL;
+}
+
+
+
+int
+jpc_enc_enccblks(jpc_enc_t * const encoderP) {
+/*----------------------------------------------------------------------------
+  Encode all of the code blocks associated with the current tile.
+-----------------------------------------------------------------------------*/
+    jpc_enc_tile_t * const tileP = encoderP->curtile;
+
+    uint_fast32_t cmptno;
+
+    for (cmptno = 0; cmptno < tileP->numtcmpts; ++cmptno) {
+        jpc_enc_tcmpt_t * const tcmptP = &tileP->tcmpts[cmptno];
+
+        unsigned int lvlno;
+        for (lvlno = 0; lvlno < tcmptP->numrlvls; ++ lvlno) {
+            jpc_enc_rlvl_t * const lvlP = &tcmptP->rlvls[lvlno];
+
+            if (lvlP->bands) {
+                uint_fast32_t bandno;
+
+                for (bandno = 0; bandno < lvlP->numbands; ++bandno) {
+                    jpc_enc_band_t * const bandP = &lvlP->bands[bandno];
+
+                    if (bandP->data) {
+                        uint_fast32_t prcno;
+
+                        for (prcno = 0; prcno < lvlP->numprcs; ++prcno) {
+
+                            const char * error;
+
+                            encodeBlocksOfPrecinct(&bandP->prcs[prcno],
+                                                   bandP,
+                                                   tcmptP,
+                                                   encoderP,
+                                                   &error);
+
+                            if (error) {
+                                pm_strfree(error);
+                                return -1;
+                            }
                         }
                     }
                 }
@@ -226,6 +265,8 @@ int jpc_enc_enccblks(jpc_enc_t *enc)
     return 0;
 }
 
+
+
 static int getthebyte(jas_stream_t *in, long off)
 {
     int c;
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_util.c b/converter/other/jpeg2000/libjasper/jpc/jpc_util.c
index fede2bef..e6e3942a 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_util.c
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_util.c
@@ -114,9 +114,9 @@
  * $Id$
  */
 
-/******************************************************************************\
+/*****************************************************************************\
 * Includes
-\******************************************************************************/
+\*****************************************************************************/
 
 #include <assert.h>
 #include <stdio.h>
@@ -133,21 +133,21 @@
 #include "jpc_flt.h"
 #include "jpc_util.h"
 
-/******************************************************************************\
+/*****************************************************************************\
 * Miscellaneous Functions
-\******************************************************************************/
+\*****************************************************************************/
 
-int jpc_atoaf(const char *s, int *numvalues, double **values)
-{
-	static char delim[] = ", \t\n";
+static unsigned int
+countOfTokens(const char * const s,
+			  const char * const delim) {
+
+	unsigned int n;
 	char buf[4096];
-	int n;
-	double *vs;
-	char *cp;
+	const char * cp;
 
 	strncpy(buf, s, sizeof(buf));
 	buf[sizeof(buf) - 1] = '\0';
-	n = 0;
+	n = 0;  /* initial value */
 	if ((cp = strtok(buf, delim))) {
 		++n;
 		while ((cp = strtok(0, delim))) {
@@ -156,32 +156,57 @@ int jpc_atoaf(const char *s, int *numvalues, double **values)
 			}
 		}
 	}
+	return n;
+}
+
+
+
+int
+jpc_atoaf(const char * const s,
+		  int *        const numvaluesP,
+		  double **    const valuesP) {
+/*----------------------------------------------------------------------------
+   Parse a string like "3.2,9,-5".  Return as *numvaluesP the number of
+   values in the string and as *valuesP a malloced array of the values.
 
-	if (n) {
-		if (!(vs = jas_malloc(n * sizeof(double)))) {
+   But if the string is empty (*numvaluesP is zero), return *valuesP NULL.
+
+   Delimiters can be comma as in the example or space, tab, or newline.
+-----------------------------------------------------------------------------*/
+	char const delim[] = ", \t\n";
+
+	unsigned int const valueCt = countOfTokens(s, delim);
+
+	if (valueCt > 0) {
+		unsigned int i;
+		double * vs;
+		const char * cp;
+		char buf[4096];
+
+		if (!(vs = jas_malloc(valueCt * sizeof(double)))) {
 			return -1;
 		}
 
 		strncpy(buf, s, sizeof(buf));
 		buf[sizeof(buf) - 1] = '\0';
-		n = 0;
+		i = 0;
 		if ((cp = strtok(buf, delim))) {
-			vs[n] = atof(cp);
-			++n;
+			vs[i] = atof(cp);
+			++i;
 			while ((cp = strtok(0, delim))) {
 				if (cp[0] != '\0') {
-					vs[n] = atof(cp);
-					++n;
+					vs[i] = atof(cp);
+					++i;
 				}
 			}
 		}
+		assert(i == valueCt);
+		*numvaluesP = valueCt;
+		*valuesP    = vs;
 	} else {
-		vs = 0;
+		*valuesP    = NULL;
+		*numvaluesP = 0;
 	}
-
-	*numvalues = n;
-	*values = vs;
-
 	return 0;
 }
 
diff --git a/converter/other/jpeg2000/libjasper_compat.c b/converter/other/jpeg2000/libjasper_compat.c
new file mode 100644
index 00000000..101820a3
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper_compat.c
@@ -0,0 +1,26 @@
+#include "netpbm/nstring.h"
+
+#include "jasper/jasper.h"
+#include "jasper/jas_image.h"
+
+#ifndef JAS_HAVE_PMJAS_IMAGE_DECODE
+
+void
+pmjas_image_decode(jas_stream_t * const in,
+                   int            const fmtArg,
+                   const char *   const optstr,
+                   jas_image_t ** const imagePP,
+                   const char **  const errorP) {
+
+    jas_image_t * const jasperP = jas_image_decode(in, fmtArg, optstr);
+
+    if (jasperP) {
+        *imagePP = jasperP;
+        *errorP  = errorP;
+    } else {
+        pm_asprintf(errorP, "Failed.  Details may have been written to "
+                    "Standard Error");
+    }
+}
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper_compat.h b/converter/other/jpeg2000/libjasper_compat.h
index 401144a3..103b1d09 100644
--- a/converter/other/jpeg2000/libjasper_compat.h
+++ b/converter/other/jpeg2000/libjasper_compat.h
@@ -1,12 +1,18 @@
 /* Here's some stuff to create backward compatibility with older Jasper
    libraries.  Unfortunately, new versions of the Jasper library are not
    backward compatible with old applications.
+
+   This also makes the programs compatible with both distributed Jasper
+   libraries and the Netpbm fork of Jasper distributed with Netpbm.
 */
 /* The color space thing got more complex between Version 1.600 and
    1.701.  For example, it now allows for multiple kinds of RGB, whereas
    in 1.600 RGB meant SRGB.  As part of that change, names changed
    from "colorspace" to "clrspc".
 */
+#include "jasper/jasper.h"
+#include "jasper/jas_image.h"
+
 #if defined(jas_image_setcolorspace)
 /* Old style color space */
 #define jas_image_setclrspc jas_image_setcolorspace
@@ -22,3 +28,32 @@
 #define JAS_CLRSPC_FAM_UNKNOWN JAS_IMAGE_CS_UNKNOWN
 
 #endif
+
+
+#ifndef JAS_HAVE_PMJAS_IMAGE_DECODE
+
+/* The Netpbm version of jas_image_decode (pmjas_image_decode) returns a
+   description of the problem when it fails and does not molest Standard
+   Error.  Real libjasper just indicates that it failed, after writing some
+   explanation (but not as much as the Netpbm version returns) to Standard
+   Error.
+*/
+void
+pmjas_image_decode(jas_stream_t * const in,
+                   int            const fmtArg,
+                   const char *   const optstr,
+                   jas_image_t ** const imagePP,
+                   const char **  const errorP) {
+
+    jas_image_t * const jasperP = jas_image_decode(in, fmtArg, optstr);
+
+    if (jasperP) {
+        *imagePP = jasperP;
+        *errorP  = NULL;
+    } else {
+        pm_asprintf(errorP, "Failed.  Details may have been written to "
+                    "Standard Error");
+    }
+}
+
+#endif
diff --git a/converter/other/jpeg2000/pamtojpeg2k.c b/converter/other/jpeg2000/pamtojpeg2k.c
index a886c390..8f7409c0 100644
--- a/converter/other/jpeg2000/pamtojpeg2k.c
+++ b/converter/other/jpeg2000/pamtojpeg2k.c
@@ -35,7 +35,7 @@ enum compmode {COMPMODE_INTEGER, COMPMODE_REAL};
 
 enum progression {PROG_LRCP, PROG_RLCP, PROG_RPCL, PROG_PCRL, PROG_CPRL};
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -53,6 +53,8 @@ struct cmdlineInfo {
     enum compmode compmode;
     unsigned int compressionSpec;
     float        compression;
+    unsigned int size;
+    unsigned int sizeSpec;
     char *       ilyrrates;
     enum progression progression;
     unsigned int numrlvls;
@@ -73,10 +75,10 @@ struct cmdlineInfo {
 
 static void
 parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo * const cmdlineP) {
+                 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
+   *cmdlineP structure are actually in the supplied argv array.  And
    sometimes, one of these strings is actually just a suffix of an entry
    in argv!
 -----------------------------------------------------------------------------*/
@@ -126,6 +128,8 @@ parseCommandLine(int argc, char ** argv,
             &modeSpec,           0);
     OPTENT3(0, "compression",  OPT_FLOAT,  &cmdlineP->compression,
             &cmdlineP->compressionSpec,    0);
+    OPTENT3(0, "size",         OPT_UINT,   &cmdlineP->size,
+            &cmdlineP->sizeSpec,           0);
     OPTENT3(0, "ilyrrates",    OPT_STRING, &cmdlineP->ilyrrates,
             &ilyrratesSpec,      0);
     OPTENT3(0, "progression",  OPT_STRING, &progressionOpt,
@@ -219,6 +223,9 @@ parseCommandLine(int argc, char ** argv,
     if (!debuglevelSpec)
         cmdlineP->debuglevel = 0;
 
+    if (cmdlineP->compressionSpec && cmdlineP->sizeSpec)
+        pm_error("You cannot specify by -compression and -size");
+
     if (argc - 1 == 0)
         cmdlineP->inputFilename = strdup("-");  /* he wants stdin */
     else if (argc - 1 == 1)
@@ -372,9 +379,11 @@ convertToJasperImage(struct pam *   const inpamP,
 
 static void
 writeJpc(jas_image_t *      const jasperP,
-         struct cmdlineInfo const cmdline,
-         FILE *             const ofP) {
-
+         struct CmdlineInfo const cmdline,
+         int                const ofd) {
+/*----------------------------------------------------------------------------
+   Write the image *jasperP to open file 'ofd'.
+-----------------------------------------------------------------------------*/
     jas_stream_t * outStreamP;
     const char * options;
     const char * ilyrratesOpt;
@@ -403,6 +412,8 @@ writeJpc(jas_image_t *      const jasperP,
 
     if (cmdline.compressionSpec)
         sprintf(rateOpt, "rate=%1.9f", 1.0/cmdline.compression);
+    else if (cmdline.sizeSpec)
+        sprintf(rateOpt, "rate=%uB", cmdline.size);
     else {
         /* No 'rate' option.  This means there is no constraint on the image
            size, so the encoder will compress losslessly.  Note that the
@@ -459,7 +470,7 @@ writeJpc(jas_image_t *      const jasperP,
     pm_strfree(ilyrratesOpt);
 
     /* Open the output image file (Standard Output) */
-    outStreamP = jas_stream_fdopen(fileno(ofP), "w+b");
+    outStreamP = jas_stream_fdopen(ofd, "w+b");
     if (outStreamP == NULL)
         pm_error("Unable to open output stream.  jas_stream_fdopen() "
                  "failed");
@@ -500,7 +511,7 @@ writeJpc(jas_image_t *      const jasperP,
 int
 main(int argc, char **argv)
 {
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     FILE * ifP;
     struct pam inpam;
     jas_image_t * jasperP;
@@ -526,7 +537,7 @@ main(int argc, char **argv)
 
     convertToJasperImage(&inpam, &jasperP);
 
-    writeJpc(jasperP, cmdline, stdout);
+    writeJpc(jasperP, cmdline, fileno(stdout));
 
 	jas_image_destroy(jasperP);
 
diff --git a/converter/other/jpegtopnm.c b/converter/other/jpegtopnm.c
index 6357e859..7d1750a7 100644
--- a/converter/other/jpegtopnm.c
+++ b/converter/other/jpegtopnm.c
@@ -4,13 +4,13 @@
   This program is part of the Netpbm package.
 
   This program converts from the JFIF format, which is based on JPEG, to
-  the fundamental ppm or pgm format (depending on whether the JFIF 
+  the fundamental ppm or pgm format (depending on whether the JFIF
   image is gray scale or color).
 
   This program is by Bryan Henderson on 2000.03.20, but is derived
   with permission from the program djpeg, which is in the Independent
   Jpeg Group's JPEG library package.  Under the terms of that permission,
-  redistribution of this software is restricted as described in the 
+  redistribution of this software is restricted as described in the
   file README.JPEG.
 
   Copyright (C) 1991-1998, Thomas G. Lane.
@@ -45,13 +45,14 @@
     (http://topo.math.u-psud.fr/~bousch/exifdump.py) and Jhead
     (http://www.sentex.net/~mwandel/jhead).
 
-    
+
 *****************************************************************************/
 
 #define _DEFAULT_SOURCE 1  /* New name for SVID & BSD source defines */
 #define _BSD_SOURCE 1      /* Make sure strdup() is in string.h */
 #define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
 
+#include <stdbool.h>
 #include <ctype.h>		/* to declare isprint() */
 #include <string.h>
 #include <stdlib.h>
@@ -73,76 +74,78 @@
 
 #define EXIT_WARNING 2  /* Goes with EXIT_FAILURE, EXIT_SUCCESS in stdlib.h */
 
-enum inklevel {NORMAL, ADOBE, GUESS};
+enum Inklevel {NORMAL, ADOBE, GUESS};
    /* This describes image samples that represent ink levels.  NORMAL
       means 0 is no ink; ADOBE means 0 is maximum ink.  GUESS means we
-      don't know what 0 means, so we have to guess from information in 
+      don't know what 0 means, so we have to guess from information in
       the image.
       */
 
-enum colorspace {
+enum Colorspace {
     /* These are the color spaces in which we can get pixels from the
        JPEG decompressor.  We include only those that are possible
        given our particular inputs to the decompressor.  The
        decompressor is theoretically capable of other, e.g. YCCK.
        Unlike the JPEG library, this type distinguishes between the
-       Adobe and non-Adobe style of CMYK samples.  
+       Adobe and non-Adobe style of CMYK samples.
     */
     GRAYSCALE_COLORSPACE,
-    RGB_COLORSPACE, 
-    CMYK_NORMAL_COLORSPACE, 
+    RGB_COLORSPACE,
+    CMYK_NORMAL_COLORSPACE,
     CMYK_ADOBE_COLORSPACE
     };
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    char *input_filespec;
-    char *exif_filespec;
-        /* Filespec in which to save EXIF information.  NULL means don't
+    char * inputFileName;
+    char * exifFileName;
+        /* Name of file in which to save EXIF information.  NULL means don't
            save.  "-" means standard output
         */
-    unsigned int verbose;
-    unsigned int nosmooth;
-    J_DCT_METHOD dct_method;
-    long int max_memory_to_use;
-    unsigned int trace_level;
-    enum inklevel inklevel;
-    unsigned int comments;
-    unsigned int dumpexif;
-    unsigned int multiple;
-    unsigned int repair;
+    unsigned int  verbose;
+    unsigned int  nosmooth;
+    J_DCT_METHOD  dctMethod;
+    long int      maxMemoryToUse;
+    unsigned int  traceLevel;
+    enum Inklevel inklevel;
+    unsigned int  comments;
+    unsigned int  dumpexif;
+    unsigned int  traceexif;
+    unsigned int  multiple;
+    unsigned int  repair;
 };
 
 
 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) { 
+static void
+interpretMaxmemory(bool         const maxmemorySpec,
+                   const char * const maxmemory,
+                   long int *   const maxMemoryToUseP) {
 /*----------------------------------------------------------------------------
    Interpret the "maxmemory" command line option.
 -----------------------------------------------------------------------------*/
     long int lval;
     char ch;
-    
+
     if (!maxmemorySpec) {
-        *max_memory_to_use_p = -1;  /* unspecified */
+        *maxMemoryToUseP = -1;  /* unspecified */
     } else if (sscanf(maxmemory, "%ld%c", &lval, &ch) < 1) {
         pm_error("Invalid value for --maxmemory option: '%s'.", maxmemory);
     } else {
         if (ch == 'm' || ch == 'M') lval *= 1000L;
-        *max_memory_to_use_p = lval * 1000L;
+        *maxMemoryToUseP = lval * 1000L;
     }
 }
 
 
 static void
-interpret_adobe(const int adobe, const int notadobe, 
-                enum inklevel * const inklevel_p) {
+interpretAdobe(int             const adobe,
+               int             const notadobe,
+               enum Inklevel * const inklevelP) {
 /*----------------------------------------------------------------------------
    Interpret the adobe/notadobe command line options
 -----------------------------------------------------------------------------*/
@@ -150,11 +153,11 @@ interpret_adobe(const int adobe, const int notadobe,
         pm_error("You cannot specify both -adobe and -notadobe options.");
     else {
         if (adobe)
-            *inklevel_p = ADOBE;
+            *inklevelP = ADOBE;
         else if (notadobe)
-            *inklevel_p = NORMAL;
-        else 
-            *inklevel_p = GUESS;
+            *inklevelP = NORMAL;
+        else
+            *inklevelP = GUESS;
     }
 }
 
@@ -163,7 +166,7 @@ interpret_adobe(const int adobe, const int notadobe,
 static void
 parseCommandLine(int                  const argc,
                  char **              const argv,
-                 struct cmdlineInfo * const cmdlineP) {
+                 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,7 +176,7 @@ parseCommandLine(int                  const argc,
    On the other hand, unlike other option processing functions, we do
    not change argv at all.
 -----------------------------------------------------------------------------*/
-    optEntry *option_def;
+    optEntry * option_def;
         /* Instructions to pm_optParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
@@ -192,7 +195,7 @@ parseCommandLine(int                  const argc,
 
     MALLOCARRAY_NOFAIL(option_def, 100);
     MALLOCARRAY_NOFAIL(argv_parse, argc);
-    
+
     /* argv, except we modify it as we parse */
 
     option_def_index = 0;   /* incremented by OPTENTRY */
@@ -200,62 +203,63 @@ parseCommandLine(int                  const argc,
     OPTENT3(0, "dct",         OPT_STRING, &dctval,
             &dctvalSpec, 0);
     OPTENT3(0, "maxmemory",   OPT_STRING, &maxmemory,
-            &maxmemorySpec, 0); 
+            &maxmemorySpec, 0);
     OPTENT3(0, "nosmooth",    OPT_FLAG,   NULL, &cmdlineP->nosmooth,      0);
-    OPTENT3(0, "tracelevel",  OPT_UINT,   &cmdlineP->trace_level,   
+    OPTENT3(0, "tracelevel",  OPT_UINT,   &cmdlineP->traceLevel,
             &tracelevelSpec, 0);
     OPTENT3(0, "adobe",       OPT_FLAG,   NULL, &adobe,                   0);
     OPTENT3(0, "notadobe",    OPT_FLAG,   NULL, &notadobe,                0);
     OPTENT3(0, "comments",    OPT_FLAG,   NULL, &cmdlineP->comments,      0);
-    OPTENT3(0, "exif",        OPT_STRING, &cmdlineP->exif_filespec, 
+    OPTENT3(0, "exif",        OPT_STRING, &cmdlineP->exifFileName,
             &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);
+    OPTENT3(0, "traceexif",   OPT_FLAG,   NULL, &cmdlineP->traceexif,     0);
 
     opt.opt_table = option_def;
-    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
-    opt.allowNegNum = FALSE;  /* We may have parms that are negative numbers */
+    opt.short_allowed = false;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = false;  /* We may have parms that are negative numbers */
 
     /* Make private copy of arguments for pm_optParseOptions to corrupt */
     argc_parse = argc;
     for (i=0; i < argc; ++i)
         argv_parse[i] = argv[i];
 
-    pm_optParseOptions3( &argc_parse, argv_parse, opt, sizeof(opt), 0);
-        /* Uses and sets argc_parse, argv_parse, 
+    pm_optParseOptions3(&argc_parse, argv_parse, opt, sizeof(opt), 0);
+        /* Uses and sets argc_parse, argv_parse,
            and some of *cmdlineP and others. */
 
     if (!tracelevelSpec)
-        cmdlineP->trace_level = 0;
+        cmdlineP->traceLevel = 0;
 
     if (!exifSpec)
-        cmdlineP->exif_filespec = NULL;
+        cmdlineP->exifFileName = NULL;
 
     if (argc_parse - 1 == 0)
-        cmdlineP->input_filespec = strdup("-");  /* he wants stdin */
+        cmdlineP->inputFileName = strdup("-");  /* he wants stdin */
     else if (argc_parse - 1 == 1)
-        cmdlineP->input_filespec = strdup(argv_parse[1]);
-    else 
+        cmdlineP->inputFileName = strdup(argv_parse[1]);
+    else
         pm_error("Too many arguments.  The only argument accepted "
                  "is the input file specification");
 
     if (!dctvalSpec)
-        cmdlineP->dct_method = JDCT_DEFAULT;
+        cmdlineP->dctMethod = JDCT_DEFAULT;
     else {
         if (streq(dctval, "int"))
-            cmdlineP->dct_method = JDCT_ISLOW;
+            cmdlineP->dctMethod = JDCT_ISLOW;
         else if (streq(dctval, "fast"))
-            cmdlineP->dct_method = JDCT_IFAST;
+            cmdlineP->dctMethod = JDCT_IFAST;
         else if (streq(dctval, "float"))
-            cmdlineP->dct_method = JDCT_FLOAT;
+            cmdlineP->dctMethod = JDCT_FLOAT;
         else pm_error("Invalid value for the --dct option: '%s'.", dctval);
     }
 
-    interpret_maxmemory(maxmemorySpec, maxmemory, 
-                        &cmdlineP->max_memory_to_use);
+    interpretMaxmemory(maxmemorySpec, maxmemory,
+                       &cmdlineP->maxMemoryToUse);
 
-    interpret_adobe(adobe, notadobe, &cmdlineP->inklevel);
+    interpretAdobe(adobe, notadobe, &cmdlineP->inklevel);
 
     free(argv_parse);
 }
@@ -270,70 +274,72 @@ parseCommandLine(int                  const argc,
 
 #if 0
 static unsigned int
-jpeg_getc (j_decompress_ptr cinfo)
+jpegGetc (j_decompress_ptr const cinfoP) {
+
 /* Read next byte */
-{
-  struct jpeg_source_mgr * datasrc = cinfo->src;
-
-  if (datasrc->bytes_in_buffer == 0) {
-      if (! (*datasrc->fill_input_buffer) (cinfo)) 
-          pm_error("Can't suspend here.");
-  }
-  datasrc->bytes_in_buffer--;
-  return GETJOCTET(*datasrc->next_input_byte++);
+    struct jpeg_source_mgr * datasrcP = cinfoP->src;
+
+    if (datasrcP->bytes_in_buffer == 0) {
+        if (! (*datasrcP->fill_input_buffer) (cinfoP))
+            pm_error("Can't suspend here.");
+    }
+    datasrcP->bytes_in_buffer--;
+    return GETJOCTET(*datasrcP->next_input_byte++);
 }
 
 
-static boolean
-print_text_marker (j_decompress_ptr cinfo) {
+static bool
+printTextMarker(j_decompress_ptr const cinfoP) {
 /*----------------------------------------------------------------------------
    This is a routine that you can register with the Jpeg decompressor
    with e.g.
 
-     jpeg_set_marker_processor(cinfoP, JPEG_APP0 + app_type, 
-                               print_text_marker);
+     jpeg_set_marker_processor(cinfoP, JPEG_APP0 + appType,
+                               printTextMarker);
 
   The decompressor then calls it when it encounters a miscellaneous marker
   of the specified type (e.g. APP1).  At that time, the jpeg input stream
   is positioned to the marker contents -- first 2 bytes of length information,
   MSB first, where the length includes those two bytes, then the data.
-  
+
   We just get and print the contents of the marker.
 
   This routine is no longer used; it is kept as an example in case we want
   to use it in the future.  Instead, we use jpeg_save_markers() and have
   the Jpeg library store all the markers in memory for our later access.
 -----------------------------------------------------------------------------*/
-    const boolean traceit = (cinfo->err->trace_level >= 1);
-    const boolean display_value = 
-        traceit || (cinfo->unread_marker == JPEG_COM && displayComments);
-    
+    const bool traceit = (cinfoP->err->trace_level >= 1);
+    const bool display_value =
+        traceit || (cinfoP->unread_marker == JPEG_COM && displayComments);
+
     INT32 length;
     unsigned int ch;
-    unsigned int lastch = 0;
-    
-    length = jpeg_getc(cinfo) << 8;
-    length += jpeg_getc(cinfo);
+    unsigned int lastch;
+
+    lastch = 0;  /* initial value */
+
+    length = jpeg_getc(cinfoP) << 8;
+    length += jpeg_getc(cinfoP);
     length -= 2;			/* discount the length word itself */
 
     if (traceit) {
-        if (cinfo->unread_marker == JPEG_COM)
+        if (cinfoP->unread_marker == JPEG_COM)
             fprintf(stderr, "Comment, length %ld:\n", (long) length);
         else			/* assume it is an APPn otherwise */
             fprintf(stderr, "APP%d, length %ld:\n",
-                    cinfo->unread_marker - JPEG_APP0, (long) length);
+                    cinfoP->unread_marker - JPEG_APP0, (long) length);
     }
-    
-    if (cinfo->unread_marker == JPEG_COM && displayComments)
+
+    if (cinfoP->unread_marker == JPEG_COM && displayComments)
         fprintf(stderr, "COMMENT: ");
-    
+
     while (--length >= 0) {
-        ch = jpeg_getc(cinfo);
+        ch = jpeg_getc(cinfoP);
         if (display_value) {
             /* Emit the character in a readable form.
              * Nonprintables are converted to \nnn form,
              * while \ is converted to \\.
-             * Newlines in CR, CR/LF, or LF form will be printed as one 
+             * Newlines in CR, CR/LF, or LF form will be printed as one
              * newline.
              */
             if (ch == '\r') {
@@ -351,18 +357,18 @@ print_text_marker (j_decompress_ptr cinfo) {
           lastch = ch;
         }
     }
-    
+
     if (display_value)
         fprintf(stderr, "\n");
-    
-    return TRUE;
+
+    return true;
 }
 #endif
 
 
 
 static void
-print_marker(struct jpeg_marker_struct const marker) {
+printMarker(struct jpeg_marker_struct const marker) {
 
     if (marker.original_length != marker.data_length) {
         /* This should be impossible, because we asked for up to 65535
@@ -376,12 +382,12 @@ print_marker(struct jpeg_marker_struct const marker) {
         int i;
         JOCTET lastch;
 
-        lastch = 0;
+        lastch = 0;  /* initial value */
         for (i = 0; i < marker.data_length; i++) {
             /* Emit the character in a readable form.
              * Nonprintables are converted to \nnn form,
              * while \ is converted to \\.
-             * Newlines in CR, CR/LF, or LF form will be printed as one 
+             * Newlines in CR, CR/LF, or LF form will be printed as one
              * newline.
              */
             if (marker.data[i] == '\r') {
@@ -407,29 +413,29 @@ typedef struct rgb {unsigned int r; unsigned int g; unsigned int b;} rgb_type;
 
 
 static rgb_type *
-read_rgb(JSAMPLE *ptr, const enum colorspace color_space, 
-         const unsigned int maxval) {
+read_rgb(JSAMPLE *       const ptr,
+         enum Colorspace const colorspace,
+         unsigned int    const maxval) {
 /*----------------------------------------------------------------------------
   Return the RGB triple corresponding to the color of the JPEG pixel at
-  'ptr', which is in color space 'color_space'.  
+  'ptr', which is in color space 'color_space'.
 
   Assume 'maxval' is the maximum sample value in the input pixel, and also
   use it for the maximum sample value in the return value.
 -----------------------------------------------------------------------------*/
     static rgb_type rgb;  /* Our return value */
 
-    switch (color_space) {
+    switch (colorspace) {
     case RGB_COLORSPACE: {
         rgb.r = GETJSAMPLE(*(ptr+0));
-        rgb.g = GETJSAMPLE(*(ptr+1)); 
-        rgb.b = GETJSAMPLE(*(ptr+2)); 
-    }
-        break;
+        rgb.g = GETJSAMPLE(*(ptr+1));
+        rgb.b = GETJSAMPLE(*(ptr+2));
+    } break;
     case CMYK_NORMAL_COLORSPACE: {
-        const int c = GETJSAMPLE(*(ptr+0));
-        const int m = GETJSAMPLE(*(ptr+1));
-        const int y = GETJSAMPLE(*(ptr+2));
-        const int k = GETJSAMPLE(*(ptr+3));
+        int const c = GETJSAMPLE(*(ptr+0));
+        int const m = GETJSAMPLE(*(ptr+1));
+        int const y = GETJSAMPLE(*(ptr+2));
+        int const k = GETJSAMPLE(*(ptr+3));
 
         /* I swapped m and y below, because they looked wrong.
            -Bryan 2000.08.20
@@ -437,74 +443,71 @@ read_rgb(JSAMPLE *ptr, const enum colorspace color_space,
         rgb.r = ((maxval-k)*(maxval-c))/maxval;
         rgb.g = ((maxval-k)*(maxval-m))/maxval;
         rgb.b = ((maxval-k)*(maxval-y))/maxval;
-    }
-        break;
+    } break;
     case CMYK_ADOBE_COLORSPACE: {
-        const int c = GETJSAMPLE(*(ptr+0));
-        const int m = GETJSAMPLE(*(ptr+1));
-        const int y = GETJSAMPLE(*(ptr+2));
-        const int k = GETJSAMPLE(*(ptr+3));
+        int const c = GETJSAMPLE(*(ptr+0));
+        int const m = GETJSAMPLE(*(ptr+1));
+        int const y = GETJSAMPLE(*(ptr+2));
+        int const k = GETJSAMPLE(*(ptr+3));
 
         rgb.r = (k*c)/maxval;
         rgb.g = (k*m)/maxval;
         rgb.b = (k*y)/maxval;
-    }
-        break;
+    } break;
     default:
         pm_error("Internal error: unknown color space %d passed to "
-                 "read_rgb().", (int) color_space);
+                 "read_rgb().", (int) colorspace);
     }
-    return(&rgb);
+    return &rgb;
 }
 
 
 
-/* pnmbuffer is declared global because it would be improper to pass a
-   pointer to it as input to copy_pixel_row(), since it isn't
-   logically a parameter of the operation, but rather is private to
-   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 void
-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) {
+convertPixelRow(JSAMPROW        const jpegbuffer,
+                unsigned int    const width,
+                unsigned int    const samplesPerPixel,
+                enum Colorspace const colorSpace,
+                int             const format,
+                xelval          const maxval,
+                xel *           const pnmbuffer) {
+/*----------------------------------------------------------------------------
+  Convert the pixels in 'jpegbuffer' from libjpeg format to libnetpbm
+  format in 'pnmbuffer'.
 
+  The row has 'width' pixels and the data in 'jpegbuffer' is formatted with
+  'samplesPerPixel' samples per pixel with colorspace 'colorSpace'.
+
+  The output Netpbm data is in format 'format' with maxval '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);
+            const rgb_type * const rgbP = read_rgb(ptr, colorSpace, maxval);
+            PPM_ASSIGN(currentPixel, rgbP->r, rgbP->g, rgbP->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);
 }
 
 
 
 static void
-set_color_spaces(const J_COLOR_SPACE jpeg_color_space,
-                 int * const output_type_p,
-                 J_COLOR_SPACE * const out_color_space_p) {
+setColorSpaces(J_COLOR_SPACE   const jpegColorSpace,
+               int *           const outputTypeP,
+               J_COLOR_SPACE * const outColorSpaceP) {
 /*----------------------------------------------------------------------------
-   Decide what type of output (PPM or PGM) we shall generate and what 
+   Decide what type of output (PPM or PGM) we shall generate and what
    color space we must request from the JPEG decompressor, based on the
-   color space of the input JPEG image, 'jpeg_color_space'.
+   color space of the input JPEG image, 'jpegColorSpace'.
 
    Write to stderr a message telling which type we picked.
 
@@ -515,72 +518,72 @@ set_color_spaces(const J_COLOR_SPACE jpeg_color_space,
        CMYK or YCCK to RGB, but can translate YCCK to CMYK.
     */
 
-    switch (jpeg_color_space) {
+    switch (jpegColorSpace) {
     case JCS_UNKNOWN:
         pm_error("Input JPEG image has 'unknown' color space "
-                 "(JCS_UNKNOWN).\n"
+                 "(JCS_UNKNOWN).  "
                  "We cannot interpret this image.");
         break;
     case JCS_GRAYSCALE:
-        *output_type_p = PGM_TYPE;
-        *out_color_space_p = JCS_GRAYSCALE;
+        *outputTypeP    = PGM_TYPE;
+        *outColorSpaceP = JCS_GRAYSCALE;
         break;
     case JCS_RGB:
-        *output_type_p = PPM_TYPE;
-        *out_color_space_p = JCS_RGB;
+        *outputTypeP    = PPM_TYPE;
+        *outColorSpaceP = JCS_RGB;
         break;
     case JCS_YCbCr:
-        *output_type_p = PPM_TYPE;
-        *out_color_space_p = JCS_RGB;
+        *outputTypeP    = PPM_TYPE;
+        *outColorSpaceP = JCS_RGB;
         /* Design note:  We found this YCbCr->RGB conversion increases
            user mode CPU time by 2.5%.  2002.10.12
         */
         break;
     case JCS_CMYK:
-        *output_type_p = PPM_TYPE;
-        *out_color_space_p = JCS_CMYK;
+        *outputTypeP    = PPM_TYPE;
+        *outColorSpaceP = JCS_CMYK;
         break;
     case JCS_YCCK:
-        *output_type_p = PPM_TYPE;
-        *out_color_space_p = JCS_CMYK;
+        *outputTypeP    = PPM_TYPE;
+        *outColorSpaceP = JCS_CMYK;
         break;
     default:
-        pm_error("Internal error: unknown color space code %d passed "
-                 "to set_color_spaces().", jpeg_color_space);
+        pm_error("INTERNAL ERROR: unknown color space code %d passed "
+                 "to setColorSpaces().", jpegColorSpace);
     }
-    pm_message("WRITING %s FILE", 
-               *output_type_p == PPM_TYPE ? "PPM" : "PGM");
+    pm_message("WRITING %s FILE",
+               *outputTypeP == PPM_TYPE ? "PPM" : "PGM");
 }
 
 
 
 static const char *
-colorspace_name(const J_COLOR_SPACE jpeg_color_space) {
-
-    const char *retval;
-
-    switch(jpeg_color_space) {
-    case JCS_UNKNOWN: retval = "JCS_UNKNOWN"; break;
-    case JCS_GRAYSCALE: retval= "JCS_GRAYSCALE"; break;
-    case JCS_RGB: retval = "JCS_RGB"; break;
-    case JCS_YCbCr: retval = "JCS_YCbCr"; break;
-    case JCS_CMYK: retval = "JCS_CMYK"; break;
-    case JCS_YCCK: retval = "JCS_YCCK"; break;
-    default: retval = "invalid"; break;
+colorspaceName(J_COLOR_SPACE const jpegColorSpace) {
+
+    const char * retval;
+
+    switch(jpegColorSpace) {
+    case JCS_UNKNOWN:   retval = "JCS_UNKNOWN";   break;
+    case JCS_GRAYSCALE: retval = "JCS_GRAYSCALE"; break;
+    case JCS_RGB:       retval = "JCS_RGB";       break;
+    case JCS_YCbCr:     retval = "JCS_YCbCr";     break;
+    case JCS_CMYK:      retval = "JCS_CMYK";      break;
+    case JCS_YCCK:      retval = "JCS_YCCK";      break;
+    default:            retval = "invalid";       break;
     };
-    return(retval);
+    return retval;
 }
 
 
 
 static void
-print_verbose_info_about_header(struct jpeg_decompress_struct const cinfo){
+printVerboseInfoAboutHeader(struct jpeg_decompress_struct const cinfo){
 
     struct jpeg_marker_struct * markerP;
 
-    pm_message("input color space is %d (%s)\n", 
-               cinfo.jpeg_color_space, 
-               colorspace_name(cinfo.jpeg_color_space));
+    pm_message("input color space is %d (%s)",
+               cinfo.jpeg_color_space,
+               colorspaceName(cinfo.jpeg_color_space));
 
     /* Note that raw information about marker, including marker type code,
        was already printed by the jpeg library, because of the jpeg library
@@ -595,15 +598,15 @@ print_verbose_info_about_header(struct jpeg_decompress_struct const cinfo){
     for (markerP = cinfo.marker_list; markerP; markerP = markerP->next) {
         if (markerP->marker == JPEG_COM)
             pm_message("Comment marker (COM):");
-        else if (markerP->marker >= JPEG_APP0 && 
+        else if (markerP->marker >= JPEG_APP0 &&
                  markerP->marker <= JPEG_APP0+15)
-            pm_message("Miscellaneous marker type APP%d:", 
+            pm_message("Miscellaneous marker type APP%d:",
                        markerP->marker - JPEG_APP0);
         else
             pm_message("Miscellaneous marker of unknown type (0x%X):",
                        markerP->marker);
-        
-        print_marker(*markerP);
+
+        printMarker(*markerP);
     }
 }
 
@@ -611,80 +614,84 @@ print_verbose_info_about_header(struct jpeg_decompress_struct const cinfo){
 
 static void
 beginJpegInput(struct jpeg_decompress_struct * const cinfoP,
-               const boolean verbose, 
-               const J_DCT_METHOD dct_method, 
-               const int max_memory_to_use, 
-               const boolean nosmooth) {
+               bool                            const verbose,
+               J_DCT_METHOD                    const dctMethod,
+               int                             const maxMemoryToUse,
+               bool                            const nosmooth) {
 /*----------------------------------------------------------------------------
    Read the JPEG header, create decompressor object (and
    allocate memory for it), set up decompressor.
 -----------------------------------------------------------------------------*/
     /* Read file header, set default decompression parameters */
-    jpeg_read_header(cinfoP, TRUE);
+    jpeg_read_header(cinfoP, true);
 
-    cinfoP->dct_method = dct_method;
-    if (max_memory_to_use != -1)
-        cinfoP->mem->max_memory_to_use = max_memory_to_use;
+    cinfoP->dct_method = dctMethod;
+    if (maxMemoryToUse != -1)
+        cinfoP->mem->max_memory_to_use = maxMemoryToUse;
     if (nosmooth)
-        cinfoP->do_fancy_upsampling = FALSE;
-    
+        cinfoP->do_fancy_upsampling = false;
+
 }
 
 
 
 static void
-print_comments(struct jpeg_decompress_struct const cinfo) {
-    
+printComments(struct jpeg_decompress_struct const cinfo) {
+
     struct jpeg_marker_struct * markerP;
 
     for (markerP = cinfo.marker_list;
-         markerP; markerP = markerP->next) 
+         markerP; markerP = markerP->next) {
         if (markerP->marker == JPEG_COM) {
             pm_message("COMMENT:");
-            print_marker(*markerP);
+            printMarker(*markerP);
         }
+    }
 }
 
 
 
 static void
-print_exif_info(struct jpeg_marker_struct const marker) {
+printExifInfo(struct jpeg_marker_struct const marker,
+              bool                      const wantTagTrace) {
 /*----------------------------------------------------------------------------
    Dump as informational messages the contents of the Jpeg miscellaneous
    marker 'marker', assuming it is an Exif header.
 -----------------------------------------------------------------------------*/
-    bool const wantTagTrace = false;
     exif_ImageInfo imageInfo;
     const char * error;
 
     assert(marker.data_length >= 6);
 
-    exif_parse(marker.data+6, marker.data_length-6, 
+    exif_parse(marker.data+6, marker.data_length-6,
                &imageInfo, wantTagTrace, &error);
 
     if (error) {
         pm_message("EXIF header is invalid.  %s", error);
         pm_strfree(error);
-    } else
+    } else {
         exif_showImageInfo(&imageInfo);
+
+        exif_terminateImageInfo(&imageInfo);
+    }
 }
 
 
 
-static boolean
-is_exif(struct jpeg_marker_struct const marker) {
+static bool
+isExif(struct jpeg_marker_struct const marker) {
 /*----------------------------------------------------------------------------
-   Return true iff the JPEG miscellaneous marker 'marker' is an Exif 
+   Return true iff the JPEG miscellaneous marker 'marker' is an Exif
    header.
 -----------------------------------------------------------------------------*/
-    boolean retval;
-    
+    bool retval;
+
     if (marker.marker == JPEG_APP0+1) {
         if (marker.data_length >=6 && memcmp(marker.data, "Exif", 4) == 0)
-            retval = TRUE;
-        else retval = FALSE;
+            retval = true;
+        else retval = false;
     }
-    else retval = FALSE;
+    else retval = false;
 
     return retval;
 }
@@ -692,69 +699,71 @@ is_exif(struct jpeg_marker_struct const marker) {
 
 
 static void
-dump_exif(struct jpeg_decompress_struct const cinfo) {
+dumpExif(struct jpeg_decompress_struct const cinfo,
+         bool                          const wantTrace) {
 /*----------------------------------------------------------------------------
    Dump as informational messages the contents of all EXIF headers in
    the image, interpreted.  An EXIF header is an APP1 marker.
 -----------------------------------------------------------------------------*/
     struct jpeg_marker_struct * markerP;
-    boolean found_one;
-
-    found_one = FALSE;  /* initial value */
+    bool foundOne;
 
-    for (markerP = cinfo.marker_list; markerP; markerP = markerP->next) 
-        if (is_exif(*markerP)) {
+    for (markerP = cinfo.marker_list, foundOne = false;
+         markerP;
+         markerP = markerP->next) {
+        if (isExif(*markerP)) {
             pm_message("EXIF INFO:");
-            print_exif_info(*markerP);
-            found_one = TRUE;
+            printExifInfo(*markerP, wantTrace);
+            foundOne = true;
         }
-    if (!found_one)
+    }
+    if (!foundOne)
         pm_message("No EXIF info in image.");
 }
 
 
 
 static void
-save_exif(struct jpeg_decompress_struct const cinfo, 
-          const char *                  const exif_filespec) {
+saveExif(struct jpeg_decompress_struct const cinfo,
+         const char *                  const exifFileName) {
 /*----------------------------------------------------------------------------
-  Write the contents of the first Exif header in the image into the
-  file with filespec 'exif_filespec'.  Start with the two byte length
-  field.  If 'exif_filespec' is "-", write to standard output.
+  Write the contents of the first Exif header in the image into the file with
+  name 'exifFileName'.  Start with the two byte length field.  If
+  'exifFileName' is "-", write to standard output.
 
-  If there is no Exif header in the image, write just zero, as a two
-  byte pure binary integer.
+  If there is no Exif header in the image, write just zero, as a two byte pure
+  binary integer.
 -----------------------------------------------------------------------------*/
-    FILE * exif_file;
+    FILE * exifFileP;
     struct jpeg_marker_struct * markerP;
 
-    exif_file = pm_openw(exif_filespec);
+    exifFileP = pm_openw(exifFileName);
 
-    for (markerP = cinfo.marker_list; 
-         markerP && !is_exif(*markerP);
+    for (markerP = cinfo.marker_list;
+         markerP && !isExif(*markerP);
          markerP = markerP->next);
 
     if (markerP) {
-        pm_writebigshort(exif_file, markerP->data_length+2);
-        if (ferror(exif_file))
-            pm_error("Write of Exif header to %s failed on first byte.",
-                     exif_filespec);
+        pm_writebigshort(exifFileP, markerP->data_length+2);
+        if (ferror(exifFileP))
+            pm_error("Write of Exif header to file '%s' failed on first byte.",
+                     exifFileName);
         else {
             int rc;
 
-            rc = fwrite(markerP->data, 1, markerP->data_length, exif_file);
+            rc = fwrite(markerP->data, 1, markerP->data_length, exifFileP);
             if (rc != markerP->data_length)
                 pm_error("Write of Exif header to '%s' failed.  Wrote "
                          "length successfully, but then failed after "
-                         "%d characters of data.", exif_filespec, rc);
+                         "%d characters of data.", exifFileName, rc);
         }
     } else {
         /* There is no Exif header in the image */
-        pm_writebigshort(exif_file, 0);
-        if (ferror(exif_file))
-            pm_error("Write of Exif header file '%s' failed.", exif_filespec);
+        pm_writebigshort(exifFileP, 0);
+        if (ferror(exifFileP))
+            pm_error("Write of Exif header file '%s' failed.", exifFileName);
     }
-    pm_close(exif_file);
+    pm_close(exifFileP);
 }
 
 
@@ -762,25 +771,25 @@ save_exif(struct jpeg_decompress_struct const cinfo,
 static void
 tellDetails(struct jpeg_decompress_struct const cinfo,
             xelval                        const maxval,
-            int                           const output_type) {
+            int                           const outputType) {
 
-    print_verbose_info_about_header(cinfo);
+    printVerboseInfoAboutHeader(cinfo);
 
-    pm_message("Input image data precision = %d bits", 
+    pm_message("Input image data precision = %d bits",
                cinfo.data_precision);
     pm_message("Output file will have format %c%c "
-               "with max sample value of %d.", 
-               (char) (output_type/256), (char) (output_type % 256),
+               "with max sample value of %d.",
+               (char) (outputType/256), (char) (outputType % 256),
                maxval);
-}  
+}
 
 
 
-static enum colorspace
+static enum Colorspace
 computeColorSpace(struct jpeg_decompress_struct * const cinfoP,
-                  enum inklevel                   const inklevel) {
-    
-    enum colorspace colorSpace;
+                  enum Inklevel                   const inklevel) {
+
+    enum Colorspace colorSpace;
 
     if (cinfoP->out_color_space == JCS_GRAYSCALE)
         colorSpace = GRAYSCALE_COLORSPACE;
@@ -806,33 +815,45 @@ computeColorSpace(struct jpeg_decompress_struct * const cinfoP,
 
 static void
 convertRaster(struct jpeg_decompress_struct * const cinfoP,
-              enum colorspace                 const color_space,
+              enum Colorspace                 const colorspace,
               FILE *                          const ofP,
               xelval                          const format,
               unsigned int                    const maxval) {
-              
+/*----------------------------------------------------------------------------
+   Read the raster from the input and write it out in Netpbm format
+   to file *ofP, in format 'format', with maxval 'maxval'.
+-----------------------------------------------------------------------------*/
     JSAMPROW jpegbuffer;  /* Input buffer.  Filled by jpeg_scanlines() */
 
+    xel * pnmbuffer;      /* Output buffer */
+
     jpegbuffer = ((*cinfoP->mem->alloc_sarray)
                   ((j_common_ptr) cinfoP, JPOOL_IMAGE,
-                   cinfoP->output_width * cinfoP->output_components, 
+                   cinfoP->output_width * cinfoP->output_components,
                    (JDIMENSION) 1)
         )[0];
 
+    pnmbuffer = pnm_allocrow(cinfoP->output_width);
+
     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);
+        if (ofP) {
+            convertPixelRow(jpegbuffer, cinfoP->output_width,
+                            cinfoP->out_color_components,
+                            colorspace, format, maxval, pnmbuffer);
+
+            pnm_writepnmrow(ofP, pnmbuffer, cinfoP->output_width,
+                            maxval, format, false);
+        }
     }
+    pnm_freerow(pnmbuffer);
 }
 
 
 
 static void
-convertImage(FILE *                          const ofP, 
-             struct cmdlineInfo              const cmdline,
+convertImage(FILE *                          const ofP,
+             struct CmdlineInfo              const cmdline,
              struct jpeg_decompress_struct * const cinfoP) {
 
     int format;
@@ -840,23 +861,23 @@ convertImage(FILE *                          const ofP,
            or PGM_TYPE, which conveniently also pass as format values
            PPM_FORMAT and PGM_FORMAT.
         */
-    xelval maxval;  
+    xelval maxval;
         /* The maximum value of a sample (color component), both in the input
            and the output.
         */
-    enum colorspace color_space;
+    enum Colorspace colorspace;
         /* The color space of the pixels coming out of the JPEG decompressor */
 
-    beginJpegInput(cinfoP, cmdline.verbose, 
-                   cmdline.dct_method, 
-                   cmdline.max_memory_to_use, cmdline.nosmooth);
-                   
-    set_color_spaces(cinfoP->jpeg_color_space, &format,
-                     &cinfoP->out_color_space);
+    beginJpegInput(cinfoP, cmdline.verbose,
+                   cmdline.dctMethod,
+                   cmdline.maxMemoryToUse, cmdline.nosmooth);
+
+    setColorSpaces(cinfoP->jpeg_color_space, &format,
+                   &cinfoP->out_color_space);
 
     maxval = pm_bitstomaxval(cinfoP->data_precision);
 
-    if (cmdline.verbose) 
+    if (cmdline.verbose)
         tellDetails(*cinfoP, maxval, format);
 
     /* Calculate output image dimensions so we can allocate space */
@@ -868,22 +889,18 @@ convertImage(FILE *                          const ofP,
     if (ofP)
         /* Write pnm output header */
         pnm_writepnminit(ofP, cinfoP->output_width, cinfoP->output_height,
-                         maxval, format, FALSE);
+                         maxval, format, false);
 
-    pnmbuffer = pnm_allocrow(cinfoP->output_width);
-    
-    color_space = computeColorSpace(cinfoP, cmdline.inklevel);
-    
-    convertRaster(cinfoP, color_space, ofP, format, maxval);
+    colorspace = computeColorSpace(cinfoP, cmdline.inklevel);
+
+    convertRaster(cinfoP, colorspace, ofP, format, maxval);
 
     if (cmdline.comments)
-        print_comments(*cinfoP);
+        printComments(*cinfoP);
     if (cmdline.dumpexif)
-        dump_exif(*cinfoP);
-    if (cmdline.exif_filespec)
-        save_exif(*cinfoP, cmdline.exif_filespec);
-
-    pnm_freerow(pnmbuffer);
+        dumpExif(*cinfoP, cmdline.traceexif);
+    if (cmdline.exifFileName)
+        saveExif(*cinfoP, cmdline.exifFileName);
 
     /* Finish decompression and release decompressor memory. */
     jpeg_finish_decompress(cinfoP);
@@ -895,18 +912,18 @@ convertImage(FILE *                          const ofP,
 static void
 saveMarkers(struct jpeg_decompress_struct * const cinfoP) {
 
-    unsigned int app_type;
+    unsigned int appType;
     /* Get all the miscellaneous markers (COM and APPn) saved for our
        later access.
     */
     jpeg_save_markers(cinfoP, JPEG_COM, 65535);
-    for (app_type = 0; app_type <= 15; ++app_type) {
-        if (app_type == 0 || app_type == 14) {
+    for (appType = 0; appType <= 15; ++appType) {
+        if (appType == 0 || appType == 14) {
             /* The jpeg library uses APP0 and APP14 internally (see
                libjpeg.doc), so we don't mess with those.
             */
         } else
-            jpeg_save_markers(cinfoP, JPEG_APP0 + app_type, 65535);
+            jpeg_save_markers(cinfoP, JPEG_APP0 + appType, 65535);
     }
 }
 
@@ -914,10 +931,10 @@ saveMarkers(struct jpeg_decompress_struct * const cinfoP) {
 
 static void
 convertImages(FILE *                          const ofP,
-              struct cmdlineInfo              const cmdline,
+              struct CmdlineInfo              const cmdline,
               struct jpeg_decompress_struct * const cinfoP,
               struct sourceManager *          const sourceManagerP) {
-              
+
     if (cmdline.multiple) {
         unsigned int imageSequence;
         for (imageSequence = 0; dsDataLeft(sourceManagerP); ++imageSequence) {
@@ -943,19 +960,19 @@ convertImages(FILE *                          const ofP,
 
 
 int
-main(int argc, char **argv) {
+main(int argc, const char **argv) {
 
     FILE * ofP;
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     struct jpeg_decompress_struct cinfo;
     struct jpeg_error_mgr jerr;
     struct sourceManager * sourceManagerP;
 
-    pnm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
-    parseCommandLine(argc, argv, &cmdline);
+    parseCommandLine(argc, (char **)argv, &cmdline);
 
-    if (cmdline.exif_filespec && streq(cmdline.exif_filespec, "-"))
+    if (cmdline.exifFileName && streq(cmdline.exifFileName, "-"))
         /* He's got exif going to stdout, so there can be no image output */
         ofP = NULL;
     else
@@ -967,14 +984,14 @@ main(int argc, char **argv) {
     cinfo.err = jpeg_std_error(&jerr);
     jpeg_create_decompress(&cinfo);
 
-    if (cmdline.trace_level == 0 && cmdline.verbose) 
+    if (cmdline.traceLevel == 0 && cmdline.verbose)
         cinfo.err->trace_level = 1;
-    else 
-        cinfo.err->trace_level = cmdline.trace_level;
-    
+    else
+        cinfo.err->trace_level = cmdline.traceLevel;
+
     saveMarkers(&cinfo);
 
-    sourceManagerP = dsCreateSource(cmdline.input_filespec);
+    sourceManagerP = dsCreateSource(cmdline.inputFileName);
 
     cinfo.src = dsJpegSourceMgr(sourceManagerP);
 
@@ -985,14 +1002,17 @@ main(int argc, char **argv) {
     if (ofP) {
         int rc;
         rc = fclose(ofP);
-        if (rc == EOF) 
+        if (rc == EOF)
             pm_error("Error writing output file.  Errno = %s (%d).",
                      strerror(errno), errno);
     }
 
     dsDestroySource(sourceManagerP);
 
-    free(cmdline.input_filespec);
-  
+    free(cmdline.inputFileName);
+
     exit(jerr.num_warnings > 0 ? EXIT_WARNING : EXIT_SUCCESS);
 }
+
+
+
diff --git a/converter/other/pamtofits.c b/converter/other/pamtofits.c
index 92e29c7e..fe81d94d 100644
--- a/converter/other/pamtofits.c
+++ b/converter/other/pamtofits.c
@@ -45,12 +45,12 @@ struct cmdlineInfo {
 
 
 
-static void 
+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.  
+   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.
@@ -95,7 +95,7 @@ parseCommandLine(int argc, char ** argv,
         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);
@@ -127,7 +127,7 @@ padToMultipleOf36Cards(unsigned int const nCardsAlreadyWritten) {
 
     unsigned int const npadCard = 36 - (nCardsAlreadyWritten % 36);
     unsigned int i;
-    
+
     for (i = 0; i < npadCard; ++i)
         writeHeaderCard("");
 }
@@ -146,7 +146,7 @@ writeFitsHeader(int    const bitpix,
 
     char buffer[80+1];
     unsigned int cardsWritten;
-                
+
     cardsWritten = 0;  /* initial value */
 
     sprintf(buffer, "%-20.20s%10.10s", "SIMPLE  =", "T");
@@ -178,7 +178,7 @@ writeFitsHeader(int    const bitpix,
     sprintf(buffer, "%-18.18s%12.5E", "BSCALE  =", bscale);
     writeHeaderCard(buffer);
     ++cardsWritten;
-    
+
     sprintf(buffer, "%-18.18s%12.5E", "BZERO   =", fitsBzero);
     writeHeaderCard(buffer);
     ++cardsWritten;
@@ -263,7 +263,7 @@ main(int argc, char * argv[]) {
            the default case, that PNM sample value is also the FITS "physical"
            value, but user options can change that.
         */
-    
+
     pnm_init(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
@@ -287,7 +287,7 @@ main(int argc, char * argv[]) {
     assert(datamax > datamin);
 
     bscale = (datamax - datamin) / pam.maxval;
-    
+
     if (pam.maxval > 255) {
         bitpix = 16;
         /* Because 16 bit FITS samples are signed, we have to do a 2**15
@@ -315,3 +315,6 @@ main(int argc, char * argv[]) {
 
     return 0;
 }
+
+
+
diff --git a/converter/other/pamtogif.c b/converter/other/pamtogif.c
index 022b7343..341c9c03 100644
--- a/converter/other/pamtogif.c
+++ b/converter/other/pamtogif.c
@@ -19,15 +19,14 @@
 
 #define MAXCMAPSIZE 256
 
-static unsigned int const gifMaxval = 255;
-
 static bool verbose;
 
 
 enum TransparencyType {TRANS_NONE, TRANS_COLOR, TRANS_ALPHA};
-    // The source of transparency for the GIF: nothing is transparent,
-    // All pixels of a certain color are transparent, or the alpha plane
-    // in the input tells what is transparent.
+    /* The source of transparency for the GIF: nothing is transparent,
+       All pixels of a certain color are transparent, or the alpha plane
+       in the input tells what is transparent.
+    */
 
 typedef unsigned int StringCode;
     /* A code to be place in the GIF raster.  It represents
@@ -813,7 +812,7 @@ typedef struct {
         */
     bool lzw;
         /* We're actually doing LZW compression.  False means we follow
-           the algorithm enough tht an LZW decompressor will recover the
+           the algorithm enough that 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.
         */
@@ -1676,7 +1675,7 @@ computeTransparent(enum TransparencyType const transType,
     case TRANS_NONE: {
         cmapP->haveTransparent = FALSE;
     } break;
-    }  // switch
+    }  /* switch */
     reportTransparent(transType, cmapP);
 }
 
@@ -1893,14 +1892,14 @@ computeColormapFromInput(struct pam *   const pamP,
 
 
 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) {
+computeLibnetpbmColormap(struct pam *          const pamP,
+                         enum TransparencyType const transType,
+                         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.
@@ -1914,21 +1913,23 @@ computeLibnetpbmColormap(struct pam *   const pamP,
    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
+   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 'transType' is
+   'TRANS_ALPHA'.  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;
+    unsigned int const maxcolors =
+        transType == TRANS_ALPHA ? 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;
+    unsigned int const nInputComp =
+        pamAlphaPlane(pamP) ? pamP->depth - 1 : pamP->depth;
         /* Number of color components (not alpha) in the input image */
 
     unsigned int i;
@@ -2011,16 +2012,16 @@ main(int argc, char *argv[]) {
 
     pm_tell2(ifP, &rasterPos, sizeof(rasterPos));
 
-    computeLibnetpbmColormap(&pam, !!pamAlphaPlane(&pam), cmdline.mapfile,
+    transType = cmdline.transparent ? TRANS_COLOR :
+        pamAlphaPlane(&pam) ? TRANS_ALPHA :
+        TRANS_NONE;
+
+    computeLibnetpbmColormap(&pam, transType, cmdline.mapfile,
                              cmap.color, &cmap.tuplehash,
                              &cmap.pam, &cmap.cmapSize, cmdline.sort);
 
     assert(cmap.pam.maxval == pam.maxval);
 
-    transType = cmdline.transparent ? TRANS_COLOR :
-        pamAlphaPlane(&pam) ? TRANS_ALPHA :
-        TRANS_NONE;
-
     if (transType == TRANS_ALPHA) {
         /* Add a fake entry to the end of the colormap for transparency.
            Make its color black.
@@ -2036,7 +2037,7 @@ main(int argc, char *argv[]) {
     gifEncode(&pam, stdout, rasterPos,
               cmdline.interlace, 0, bitsPerPixel, &cmap, cmdline.comment,
               cmdline.aspect, !cmdline.nolzw, cmdline.noclear,
-              !cmdline.transparent);
+              transType==TRANS_ALPHA);
 
     destroyCmap(&cmap);
 
diff --git a/converter/other/pamtopdbimg.c b/converter/other/pamtopdbimg.c
index ce2f7659..da0f5064 100644
--- a/converter/other/pamtopdbimg.c
+++ b/converter/other/pamtopdbimg.c
@@ -32,6 +32,7 @@
 #include <stdlib.h>
 #include <assert.h>
 #include <string.h>
+#include <time.h>
 #include <sys/stat.h>
 
 #include "pm_c_util.h"
@@ -45,7 +46,7 @@
 
 enum CompMode {COMPRESSED, MAYBE, UNCOMPRESSED};
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -54,16 +55,17 @@ struct cmdlineInfo {
     const char * notefile;  /* NULL if not specified */
     enum CompMode compMode;
     unsigned int depth4;
+    unsigned int fixedtime;
 };
 
 
 
 static void
 parseCommandLine(int argc, const char ** argv,
-                 struct cmdlineInfo * const cmdlineP) {
+                 struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    parse program command line described in Unix standard form by argc
-   and argv.  Return the information in the options as *cmdlineP.  
+   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.
@@ -96,6 +98,8 @@ parseCommandLine(int argc, const char ** argv,
             &uncompressed,            0);
     OPTENT3(0, "4depth",              OPT_FLAG,      NULL,
             &cmdlineP->depth4,        0);
+    OPTENT3(0, "fixedtime",           OPT_FLAG,      NULL,
+            &cmdlineP->fixedtime,     0);
 
     opt.opt_table = option_def;
     opt.short_allowed = false;  /* We have no short (old-fashioned) options */
@@ -110,7 +114,7 @@ parseCommandLine(int argc, const char ** argv,
 
     if (!notefileSpec)
         cmdlineP->notefile = NULL;
-    
+
     if (compressed + uncompressed + maybeCompressed > 1)
         pm_error("You may specify only one of -compressed, -uncompressed, "
                  "-maybecompressed");
@@ -144,6 +148,42 @@ parseCommandLine(int argc, const char ** argv,
 
 
 
+static uint32_t const unixepoch = (66*365+17)*24*3600;
+    /* The unix epoch in Mac time (the Mac epoch is 00:00 UTC 1904.01.01).
+       The 17 is the number of leap years.
+    */
+
+
+
+static void
+setPdbHeader(PDBHEAD *    const pdbHeadP,
+             const char * const name,
+             bool         const wantFixedTime) {
+
+    STRSCPY(pdbHeadP->name, name);
+
+    {
+        /*
+         * All of the Image Viewer pdb files that I've come across have
+         * 3510939142U (1997.08.16 14:38:22 UTC) here.  I don't know where
+         * this bizarre datetime comes from but the real date works fine so
+         * I'm using it unless user asked for a fixed time (probably just so he
+         * gets repeatable output).
+         */
+
+        uint32_t const stdTime = 3510939142U;
+
+        uint32_t const hdrDt =
+            wantFixedTime ? stdTime : (uint32_t)time(NULL) + unixepoch;
+
+        pdbHeadP->ctime = pdbHeadP->mtime = hdrDt;
+    }
+    MEMSCPY(&pdbHeadP->type, IPDB_vIMG);
+    MEMSCPY(&pdbHeadP->id,   IPDB_View);
+}
+
+
+
 static int
 pdbheadWrite(PDBHEAD * const pdbheadP,
              FILE *    const fileP) {
@@ -232,7 +272,7 @@ imageWrite(IMAGE *   const imgP,
 static int
 textWrite(TEXT * const textP,
           FILE * const fileP) {
-    
+
     if (textP)
         fwrite(textP->data, 1, strlen(textP->data), fileP);
 
@@ -249,9 +289,9 @@ compressIfRequired(IPDB *     const pdbP,
 
     if (comp == IPDB_NOCOMPRESS) {
         *compressedDataP = pdbP->i->data;
-        *compressedSizeP = ipdb_img_size(pdbP->i);
+        *compressedSizeP = ipdb_imgSize(pdbP->i);
     } else {
-        int const uncompressedSz = ipdb_img_size(pdbP->i);
+        int const uncompressedSz = ipdb_imgSize(pdbP->i);
 
         unsigned char * outbuf;
         size_t          compressedSz;
@@ -303,7 +343,7 @@ ipdbWrite(IPDB * const pdbP,
     rc = pdbheadWrite(pdbP->p, fileP);
     if (rc != 0)
         pm_error("Failed to write PDB header.  %s", ipdb_err(rc));
-            
+
     rc = rechdrWrite(irP, fileP);
     if (rc != 0)
         pm_error("Failed to write image record header.  %s", ipdb_err(rc));
@@ -475,7 +515,7 @@ imageInsertInit(IPDB * const pdbP,
                      ipdb_typeName(type), MAX_SIZE(type));
         else {
             pdbP->i =
-                ipdb_image_alloc(name, type, adjustedWidth, adjustedHeight);
+                ipdb_imageCreate(name, type, adjustedWidth, adjustedHeight);
             if (pdbP->i == NULL)
                 pm_message("Could not get memory for %u x %u image",
                            adjustedWidth, adjustedHeight);
@@ -513,7 +553,7 @@ insertG16image(IPDB *          const pdbP,
         /* Pad with white on the bottom */
         for (; row < ipdb_height(pdbP); ++row)
             memset(outP, 0, rowSize);
-    } 
+    }
 }
 
 
@@ -544,7 +584,7 @@ insertGimage(IPDB *          const pdbP,
         /* Pad with white on the bottom */
         for (; row < ipdb_height(pdbP); ++row)
             memset(outP, 0, rowSize);
-    } 
+    }
 }
 
 
@@ -575,14 +615,14 @@ insertMimage(IPDB *          const pdbP,
         /* Pad with white on the bottom */
         for (; row < ipdb_height(pdbP); ++row)
             memset(outP, 0, rowSize);
-    } 
+    }
 }
 
 
 
 static int
 insertText(IPDB *       const pdbP,
-           const char * const s) {
+           const char * const content) {
 
     int retval;
 
@@ -591,17 +631,23 @@ insertText(IPDB *       const pdbP,
     else if (pdbP->p->num_recs == 2)
         retval = E_TEXTTHERE;
     else {
-        pdbP->t = ipdb_text_alloc(s);
+        pdbP->t = ipdb_textAlloc();
         if (pdbP->t == NULL)
             retval = ENOMEM;
         else {
-            pdbP->p->num_recs = 2;
+            pdbP->t->data = strdup(content);
 
-            pdbP->i->r->offset += 8;
-            pdbP->t->r->offset =
-                pdbP->i->r->offset + IMAGESIZE + ipdb_img_size(pdbP->i);
+            if (pdbP->t->data == NULL)
+                retval = ENOMEM;
+            else {
+                pdbP->p->num_recs = 2;
 
-            retval = 0;
+                pdbP->i->r->offset += 8;
+                pdbP->t->r->offset =
+                    pdbP->i->r->offset + IMAGESIZE + ipdb_imgSize(pdbP->i);
+
+                retval = 0;
+            }
         }
     }
     return retval;
@@ -689,7 +735,7 @@ readtxt(IPDB *       const pdbP,
 int
 main(int argc, const char **argv) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     IPDB * pdbP;
     FILE * ifP;
     int comp;
@@ -709,11 +755,13 @@ main(int argc, const char **argv) {
     if (strlen(cmdline.title) > 31)
         pm_error("Title too long.  Max length is 31 characters.");
 
-    pdbP = ipdb_alloc(cmdline.title);
+    pdbP = ipdb_alloc();
 
     if (pdbP == NULL)
         pm_error("Failed to allocate IPDB structure");
 
+    setPdbHeader(pdbP->p, cmdline.title, cmdline.fixedtime);
+
     readimg(pdbP, ifP, cmdline.depth4);
 
     if (cmdline.notefile)
@@ -730,3 +778,6 @@ main(int argc, const char **argv) {
 
     return EXIT_SUCCESS;
 }
+
+
+
diff --git a/converter/other/pamtopng.c b/converter/other/pamtopng.c
index 3164bc29..088db3c8 100644
--- a/converter/other/pamtopng.c
+++ b/converter/other/pamtopng.c
@@ -16,7 +16,7 @@
     had become rather complex.  This program is roughly 1/3 the size of
     pnmtopng.c that it replaces.
 
-  - In 1995, bandwith was limited and therefore filesize had to be kept
+  - In 1995, bandwid was limited and therefore filesize had to be kept
     small. The original program tried to optimize for that by applying
     many "clever tricks". Today that isn't an issue anymore, so gone
     are filters, palettes, etc. Also, image conversions were removed,
@@ -251,7 +251,7 @@ colorTypeFromInputType(const struct pam * const pamP) {
 -----------------------------------------------------------------------------*/
     png_byte retval;
 
-    if (pamP->depth < 1 && pamP->depth > 4)
+    if (pamP->depth < 1 || pamP->depth > 4)
         pm_error ("Number of color planes must be between 1 and 4 inclusive");
 
     if (pamP->maxval != 1 && pamP->maxval != 3 && pamP->maxval != 15 &&
@@ -278,7 +278,7 @@ colorTypeFromInputType(const struct pam * const pamP) {
             retval = PNG_COLOR_TYPE_GRAY_ALPHA;
         else
             pm_error("Input tuple type is GRAYSCALE_ALPHA, "
-                     "but number of planes is %u instread of 2",
+                     "but number of planes is %u instead of 2",
                      pamP->depth);
     } else if (strneq(pamP->tuple_type, "GRAYSCALE", 9)) {
         if (pamP->depth == 1)
@@ -932,7 +932,7 @@ pamtopng(FILE *             const ifP,
 
     if (cmdline.interlace) {
         /* Libpng will expect us to provide pixels in interlaced sequence
-           if we write row-by-row, and that is much to difficult, so we
+           if we write row-by-row, and that is much too difficult, so we
            do whole-image-at-once and let Libpng do the work.
         */
         writeRasterWholeImg(&pam, pngxP, pnmBitDepth);
diff --git a/converter/other/pamtoqoi.c b/converter/other/pamtoqoi.c
new file mode 100644
index 00000000..638efa3a
--- /dev/null
+++ b/converter/other/pamtoqoi.c
@@ -0,0 +1,439 @@
+/*
+  pamtoqoi -  Converts PAM to a QOI - The "Quite OK Image" format file
+
+  This program is part of Netpbm.
+
+  ---------------------------------------------------------------------
+
+  QOI - The "Quite OK Image" format for fast, lossless image compression
+
+  Encoder by Dominic Szablewski - https://phoboslab.org
+
+  -- LICENSE: The MIT License(MIT)
+
+  Copyright(c) 2021 Dominic Szablewski
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files(the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions :
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+
+  For more information on the format visit: https//qoiformat.org/ .
+
+  Modifications for Netpbm read routines by Akira F. Urushibata.
+
+*/
+
+#include <string.h>
+#include <assert.h>
+#include "pam.h"
+#include "nstring.h"
+#include "mallocvar.h"
+#include "shhopt.h"
+
+#include "qoi.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;  /* '-' if stdin */
+};
+
+
+
+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 pm_optParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+
+    MALLOCARRAY(option_def, 100);
+
+    OPTENTINIT;
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (argc-1 < 1)
+        cmdlineP->inputFileName = "-";
+    else if (argc-1 == 1)
+        cmdlineP->inputFileName = argv[1];
+    else
+        pm_error("Program takes at most one argument: input file name.  "
+            "you specified %d", argc-1);
+}
+
+
+
+static void
+encodeQoiHeader(qoi_Desc const qoiDesc) {
+
+    assert (QOI_MAGIC_SIZE + 4 + 4 + 1 + 1 == QOI_HEADER_SIZE);
+
+    fwrite (qoi_magic, QOI_MAGIC_SIZE, 1, stdout);
+    pm_writebiglongu(stdout, qoiDesc.width);
+    pm_writebiglongu(stdout, qoiDesc.height);
+    putchar(qoiDesc.channelCt);
+    putchar(qoiDesc.colorspace);
+
+}
+
+enum Tupletype {BW, BWAlpha, GRAY, GRAYAlpha, RGB, RGBAlpha,
+                GRAY255, GRAY255Alpha, RGB255, RGB255Alpha};
+
+
+
+static void
+createSampleMap(sample    const oldMaxval,
+                sample ** const sampleMapP) {
+
+    unsigned int i;
+    sample * sampleMap;
+    sample   const newMaxval = 255;
+
+    MALLOCARRAY_NOFAIL(sampleMap, oldMaxval+1);
+
+    for (i = 0; i <= oldMaxval; ++i)
+        sampleMap[i] = ROUNDDIV(i * newMaxval, oldMaxval);
+
+    *sampleMapP = sampleMap;
+}
+
+
+
+static enum Tupletype
+tupleTypeFmPam(const char * const pamTupleType,
+               sample       const maxval) {
+
+    enum Tupletype retval;
+
+    if (streq(pamTupleType, PAM_PBM_TUPLETYPE)) {
+        if (maxval !=1)
+            pm_error("Invalid maxval (%lu) for tuple type '%s'.",
+                     maxval, pamTupleType);
+        else
+            retval =  BW;
+    } else if (streq(pamTupleType, PAM_PBM_ALPHA_TUPLETYPE)) {
+      if (maxval !=1)
+          pm_error("Invalid maxval (%lu) for tuple type '%s'.",
+                    maxval, pamTupleType);
+      else
+          retval =  BWAlpha;
+    } else if (maxval == 255) {
+        if (streq(pamTupleType, PAM_PPM_TUPLETYPE))
+            retval =  RGB255;
+        else if(streq(pamTupleType, PAM_PPM_ALPHA_TUPLETYPE))
+            retval =  RGB255Alpha;
+        else if(streq(pamTupleType, PAM_PGM_TUPLETYPE))
+            retval =  GRAY255;
+        else if(streq(pamTupleType, PAM_PGM_ALPHA_TUPLETYPE))
+            retval =  GRAY255Alpha;
+        else
+            pm_error("Don't know how to convert tuple type '%s'.",
+                     pamTupleType);
+    } else {
+        if (streq(pamTupleType, PAM_PPM_TUPLETYPE))
+            retval =  RGB;
+        else if(streq(pamTupleType, PAM_PPM_ALPHA_TUPLETYPE))
+            retval =  RGBAlpha;
+        else if(streq(pamTupleType, PAM_PGM_TUPLETYPE))
+            retval =  GRAY;
+        else if(streq(pamTupleType, PAM_PGM_ALPHA_TUPLETYPE))
+            retval =  GRAYAlpha;
+        else
+            pm_error("Don't know how to convert tuple type '%s'.",
+                     pamTupleType);
+    }
+
+    return retval;
+}
+
+
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wreturn-type"
+
+static unsigned int
+channelCtFmTupleType(enum Tupletype const tupleType) {
+
+    switch (tupleType) {
+        case RGB:
+          return 3;
+        case RGB255:
+          return 3;
+        case RGBAlpha:
+          return 4;
+        case RGB255Alpha:
+          return 4;
+        case BW:
+        case GRAY:
+          return 3;
+        case GRAY255:
+          return 3;
+        case BWAlpha:
+        case GRAYAlpha:
+          return 4;
+        case GRAY255Alpha:
+          return 4;
+    }
+}
+#pragma GCC diagnostic pop
+
+
+
+static qoi_Rgba
+pxFmTuple(tuple          const tuple0,
+          const sample * const sampleMap,
+          enum Tupletype const tupleType) {
+/*----------------------------------------------------------------------------
+   Convert PAM tuple to qoi rgba pixel struct
+-----------------------------------------------------------------------------*/
+    qoi_Rgba px;
+
+    switch (tupleType) {
+    case RGB:
+        px.rgba.r = sampleMap[tuple0[PAM_RED_PLANE]];
+        px.rgba.g = sampleMap[tuple0[PAM_GRN_PLANE]];
+        px.rgba.b = sampleMap[tuple0[PAM_BLU_PLANE]];
+        px.rgba.a = 255;
+        break;
+    case RGB255:
+        px.rgba.r = tuple0[PAM_RED_PLANE];
+        px.rgba.g = tuple0[PAM_GRN_PLANE];
+        px.rgba.b = tuple0[PAM_BLU_PLANE];
+        px.rgba.a = 255;
+        break;
+    case RGBAlpha:
+        px.rgba.r = sampleMap[tuple0[PAM_RED_PLANE]];
+        px.rgba.g = sampleMap[tuple0[PAM_GRN_PLANE]];
+        px.rgba.b = sampleMap[tuple0[PAM_BLU_PLANE]];
+        px.rgba.a = sampleMap[tuple0[PAM_TRN_PLANE]];
+        break;
+    case RGB255Alpha:
+        px.rgba.r = tuple0[PAM_RED_PLANE];
+        px.rgba.g = tuple0[PAM_GRN_PLANE];
+        px.rgba.b = tuple0[PAM_BLU_PLANE];
+        px.rgba.a = tuple0[PAM_TRN_PLANE];
+        break;
+    case BW:
+    case GRAY : {
+        unsigned char const qoiSample = sampleMap[tuple0[0]];
+        px.rgba.r = qoiSample;
+        px.rgba.g = qoiSample;
+        px.rgba.b = qoiSample;
+        px.rgba.a = 255;
+    } break;
+    case GRAY255: {
+        unsigned char const qoiSample = tuple0[0];
+        px.rgba.r = qoiSample;
+        px.rgba.g = qoiSample;
+        px.rgba.b = qoiSample;
+        px.rgba.a = 255;
+    } break;
+    case BWAlpha:
+    case GRAYAlpha: {
+        unsigned char const qoiSample = sampleMap[tuple0[0]];
+        px.rgba.r = qoiSample;
+        px.rgba.g = qoiSample;
+        px.rgba.b = qoiSample;
+        px.rgba.a = sampleMap[tuple0[PAM_GRAY_TRN_PLANE]];
+    } break;
+    case GRAY255Alpha: {
+        unsigned char const qoiSample = tuple0[0];
+        px.rgba.r = qoiSample;
+        px.rgba.g = qoiSample;
+        px.rgba.b = qoiSample;
+        px.rgba.a = tuple0[PAM_GRAY_TRN_PLANE];
+    } break;
+    }
+
+    return px;
+}
+
+
+
+static void
+encodeNewPixel(qoi_Rgba const px,
+               qoi_Rgba const pxPrev) {
+
+    if (px.rgba.a == pxPrev.rgba.a) {
+        signed char const vr = px.rgba.r - pxPrev.rgba.r;
+        signed char const vg = px.rgba.g - pxPrev.rgba.g;
+        signed char const vb = px.rgba.b - pxPrev.rgba.b;
+
+        signed char const vgR = vr - vg;
+        signed char const vgB = vb - vg;
+
+        if (
+            vr > -3 && vr < 2 &&
+            vg > -3 && vg < 2 &&
+            vb > -3 && vb < 2
+            ) {
+            putchar(QOI_OP_DIFF |
+                    (vr + 2) << 4 | (vg + 2) << 2 | (vb + 2));
+        } else if (
+            vgR >  -9 && vgR <  8 &&
+            vg  > -33 && vg  < 32 &&
+            vgB >  -9 && vgB <  8
+            ) {
+            putchar(QOI_OP_LUMA    | (vg   + 32));
+            putchar((vgR + 8) << 4 | (vgB +  8));
+        } else {
+            putchar(QOI_OP_RGB);
+            putchar(px.rgba.r);
+            putchar(px.rgba.g);
+            putchar(px.rgba.b);
+        }
+    } else {
+        putchar(QOI_OP_RGBA);
+        putchar(px.rgba.r);
+        putchar(px.rgba.g);
+        putchar(px.rgba.b);
+        putchar(px.rgba.a);
+    }
+}
+
+
+
+static void
+qoiEncode(FILE           * const ifP,
+          struct pam     * const inpamP) {
+
+    tuple * tuplerow;
+    unsigned int row;
+
+    qoi_Rgba index[QOI_INDEX_SIZE];
+    qoi_Rgba pxPrev;
+    unsigned int run;
+    sample * sampleMap;
+    qoi_Desc qoiDesc;
+
+    enum Tupletype const tupleType =
+      tupleTypeFmPam(inpamP->tuple_type, inpamP->maxval);
+
+    if (inpamP->height > QOI_PIXELS_MAX / inpamP->width)
+        pm_error("Too many pixels for QOI: %u x %u (max is %u)",
+                 inpamP->height, inpamP->width, QOI_PIXELS_MAX);
+
+    qoiDesc.colorspace = QOI_SRGB;
+    qoiDesc.width      = inpamP->width;
+    qoiDesc.height     = inpamP->height;
+    qoiDesc.channelCt  = channelCtFmTupleType(tupleType);
+
+    encodeQoiHeader(qoiDesc);
+
+    tuplerow = pnm_allocpamrow(inpamP);
+
+    if (inpamP->maxval != 255)
+        createSampleMap(inpamP->maxval, &sampleMap);
+
+    qoi_clearQoiIndex(index);
+
+    pxPrev.rgba.r = 0;
+    pxPrev.rgba.g = 0;
+    pxPrev.rgba.b = 0;
+    pxPrev.rgba.a = 255;
+
+    /* Read and convert rows. */
+    for (row = 0, run = 0; row < inpamP->height; ++row) {
+        unsigned int col;
+
+        pnm_readpamrow(inpamP, tuplerow);
+
+        for (col = 0; col < inpamP->width; ++col) {
+            qoi_Rgba const px = pxFmTuple(tuplerow[col], sampleMap, tupleType);
+
+            if (px.v == pxPrev.v) {
+                ++run;
+                if (run == 62) {
+                    putchar(QOI_OP_RUN | (run - 1));
+                    run = 0;
+                }
+            } else {
+                unsigned int const indexPos = qoi_colorHash(px);
+
+                if (run > 0) {
+                    putchar(QOI_OP_RUN | (run - 1));
+                    run = 0;
+                }
+
+                if (index[indexPos].v == px.v) {
+                    putchar(QOI_OP_INDEX | indexPos);
+
+                } else {
+                    index[indexPos] = px;
+                    encodeNewPixel(px, pxPrev);
+                }
+            }
+            pxPrev = px;
+        }
+    }
+
+    if (run > 0)
+        putchar(QOI_OP_RUN | (run - 1));
+
+    fwrite(qoi_padding, sizeof(qoi_padding), 1, stdout);
+
+    if (inpamP->maxval != 255)
+        free(sampleMap);
+    pnm_freepamrow(tuplerow);
+}
+
+
+
+int
+main(int argc, const char **argv) {
+
+    struct CmdlineInfo cmdline;
+    struct pam inpam;
+    FILE * ifP;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
+
+    qoiEncode(ifP, &inpam);
+
+    return 0;
+}
+
+
diff --git a/converter/other/pamtosvg/fit.c b/converter/other/pamtosvg/fit.c
index 5ba7a2f6..179b3bdf 100644
--- a/converter/other/pamtosvg/fit.c
+++ b/converter/other/pamtosvg/fit.c
@@ -67,7 +67,7 @@ real_to_int_coord(float_coord const real_coord) {
 
     int_coord.col = ROUND(real_coord.x);
     int_coord.row = ROUND(real_coord.y);
-    
+
     return int_coord;
 }
 
@@ -152,7 +152,7 @@ find_vectors(unsigned int       const 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.
     */
@@ -160,7 +160,7 @@ find_vectors(unsigned int       const test_index,
          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;
@@ -207,19 +207,19 @@ lookAheadForBetterCorner(pixel_outline_type  const outline,
 
     bestCornerIndex = basePixelSeq;     /* initial assumption */
     bestCornerAngle = baseCornerAngle;    /* initial assumption */
-    
+
     equallyGoodList = new_index_list();
-    
+
     q = basePixelSeq;
     i = basePixelSeq + 1;  /* Start with the next pixel */
-    
+
     while (i < bestCornerIndex + cornerSurround &&
            i < O_LENGTH(outline) &&
            !at_exception_got_fatal(exceptionP)) {
 
         vector_type inVector, outVector;
         float cornerAngle;
-        
+
         /* Check the angle.  */
 
         q = i % O_LENGTH(outline);
@@ -446,7 +446,7 @@ filter(curve *             const curveP,
 
     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
@@ -460,26 +460,26 @@ filter(curve *             const curveP,
     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.
@@ -488,12 +488,12 @@ filter(curve *             const curveP,
             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.
             */
@@ -503,18 +503,18 @@ filter(curve *             const curveP,
             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);
@@ -528,13 +528,13 @@ filter(curve *             const curveP,
                 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 {
@@ -543,7 +543,7 @@ filter(curve *             const curveP,
             */
             if (offset)
                 append_point(newcurveP, LAST_CURVE_POINT(curveP));
-            
+
             /* Set the original curve to the newly filtered one, and go
                again.
             */
@@ -560,7 +560,7 @@ removeAdjacent(index_list_type *   const cornerListP,
                pixel_outline_type  const outline,
                fitting_opts_type * const fittingOptsP,
                at_exception_type * const exception) {
-               
+
     /* We never want two corners next to each other, since the
        only way to fit such a ``curve'' would be with a straight
        line, which usually interrupts the continuity dreadfully.
@@ -598,7 +598,7 @@ find_corners(pixel_outline_type  const outline,
 
     establishCornerSearchLimits(outline, fittingOptsP,
                                 &firstPixelSeq, &lastPixelSeq);
-    
+
     /* Consider each pixel on the outline in turn.  */
     for (p = firstPixelSeq; p <= lastPixelSeq;) {
         vector_type inVector, outVector;
@@ -655,10 +655,10 @@ find_corners(pixel_outline_type  const outline,
                 && bestCornerIndex >= p) {
 
                 unsigned int j;
-                
+
                 appendCorner(&cornerList, bestCornerIndex,
                              outline, bestCornerAngle, '/');
-                
+
                 for (j = 0; j < INDEX_LIST_LENGTH (equallyGoodList); ++j)
                     appendCorner(&cornerList, GET_INDEX(equallyGoodList, j),
                                  outline, bestCornerAngle, '@');
@@ -675,7 +675,7 @@ find_corners(pixel_outline_type  const outline,
     }
     removeAdjacent(&cornerList, outline, fittingOptsP, exceptionP);
 
-cleanup:  
+cleanup:
     return cornerList;
 }
 
@@ -696,12 +696,12 @@ makeOutlineOneCurve(pixel_outline_type const outline,
 
     for (pixelSeq = 0; pixelSeq < O_LENGTH(outline); ++pixelSeq)
         append_pixel(curveP, O_COORDINATE(outline, pixelSeq));
-    
+
     if (outline.open)
         CURVE_CYCLIC(curveP) = false;
     else
         CURVE_CYCLIC(curveP) = true;
-    
+
     /* Make it a one-curve cycle */
     NEXT_CURVE(curveP)     = curveP;
     PREVIOUS_CURVE(curveP) = curveP;
@@ -728,23 +728,23 @@ addCurveStartingAtCorner(pixel_outline_type const outline,
    Don't include beginning and ending slope information for that curve.
 -----------------------------------------------------------------------------*/
     unsigned int const cornerPixelSeq = GET_INDEX(cornerList, cornerSeq);
-    
+
     unsigned int lastPixelSeq;
     curve * curveP;
     unsigned int pixelSeq;
-    
+
     if (cornerSeq + 1 >= cornerList.length)
         /* No more corners, so we go through the end of the outline. */
         lastPixelSeq = O_LENGTH(outline) - 1;
     else
         /* Go through the next corner */
         lastPixelSeq = GET_INDEX(cornerList, cornerSeq + 1);
-    
+
     curveP = new_curve();
 
     for (pixelSeq = cornerPixelSeq; pixelSeq <= lastPixelSeq; ++pixelSeq)
         append_pixel(curveP, O_COORDINATE(outline, pixelSeq));
-    
+
     append_curve(curveListP, curveP);
     {
         /* Add the new curve to the outline chain */
@@ -803,7 +803,7 @@ divideOutlineWithCorners(pixel_outline_type const outline,
         */
         curve * curveP;
         unsigned int pixelSeq;
-        
+
         curveP = new_curve();
 
         for (pixelSeq = 0; pixelSeq <= GET_INDEX(cornerList, 0); ++pixelSeq)
@@ -897,7 +897,7 @@ split_at_corners(pixel_outline_list_type const pixel_list,
         curve_list.open  = outline.open;
 
         LOG1("#%u:", outlineSeq);
-        
+
         /* If the outline does not have enough points, we can't do
            anything.  The endpoints of the outlines are automatically
            corners.  We need at least `corner_surround' more pixels on
@@ -926,7 +926,7 @@ split_at_corners(pixel_outline_list_type const pixel_list,
             makeOutlineOneCurve(outline, &curve_list);
         else
             divideOutlineWithCorners(outline, corner_list, &curve_list);
-        
+
         LOG1(" [%u].\n", corner_list.length);
         free_index_list(&corner_list);
 
@@ -947,7 +947,7 @@ removeKnees(curve_list_type const curveList) {
   removing a point that should be a corner.
 -----------------------------------------------------------------------------*/
     unsigned int curveSeq;
-    
+
     LOG("\nRemoving knees:\n");
     for (curveSeq = 0; curveSeq < curveList.length; ++curveSeq) {
         LOG1("#%u:", curveSeq);
@@ -955,7 +955,7 @@ removeKnees(curve_list_type const curveList) {
                            CURVE_LIST_CLOCKWISE(curveList));
     }
 }
-    
+
 
 
 static void
@@ -966,7 +966,7 @@ computePointWeights(curve_list_type     const curveList,
     unsigned int const height = distP->height;
 
     unsigned int curveSeq;
-    
+
     for (curveSeq = 0; curveSeq < curveList.length; ++curveSeq) {
         unsigned pointSeq;
         curve_type const curve = CURVE_LIST_ELT(curveList, curveSeq);
@@ -974,13 +974,13 @@ computePointWeights(curve_list_type     const curveList,
             float_coord * const coordP = &CURVE_POINT(curve, pointSeq);
             unsigned int x = coordP->x;
             unsigned int y = height - (unsigned int)coordP->y - 1;
-            
+
             float width, w;
 
             /* Each (x, y) is a point on the skeleton of the curve, which
                might be offset from the true centerline, where the width
                is maximal.  Therefore, use as the local line width the
-               maximum distance over the neighborhood of (x, y). 
+               maximum distance over the neighborhood of (x, y).
             */
             width = distP->d[y][x];  /* initial value */
             if (y - 1 >= 0) {
@@ -1017,7 +1017,7 @@ computePointWeights(curve_list_type     const curveList,
 static void
 filterCurves(curve_list_type     const curveList,
              fitting_opts_type * const fittingOptsP) {
-             
+
     unsigned int curveSeq;
 
     LOG("\nFiltering curves:\n");
@@ -1044,8 +1044,8 @@ logSplinesForCurve(unsigned int     const curveSeq,
         if (log_file)
             print_spline(log_file, SPLINE_LIST_ELT(curveSplines, splineSeq));
     }
-}     
-       
+}
+
 
 
 static void
@@ -1212,7 +1212,7 @@ fitWithLine(curve * const curveP) {
 #define B3(t) CUBE (t)
 
 static spline_type
-fitOneSpline(curve *             const curveP, 
+fitOneSpline(curve *             const curveP,
              vector_type         const begSlope,
              vector_type         const endSlope,
              at_exception_type * const exceptionP) {
@@ -1311,7 +1311,7 @@ fitOneSpline(curve *             const curveP,
     free(A);
 
     C.end.beg = C.beg.end;
-    
+
     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;
@@ -1328,7 +1328,7 @@ fitOneSpline(curve *             const curveP,
         CONTROL2(spline) = Vadd_point(END_POINT(spline),
                                       Vmult_scalar(tang.end, alpha.end));
         SPLINE_DEGREE(spline) = CUBICTYPE;
-    }        
+    }
     return spline;
 }
 
@@ -1341,7 +1341,7 @@ logSplineFit(spline_type const spline) {
         LOG("  fitted to line:\n");
     else
         LOG("  fitted to spline:\n");
-    
+
     if (log_file) {
         LOG ("    ");
         print_spline (log_file, spline);
@@ -1458,7 +1458,7 @@ findTangent(curve *       const curveP,
   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
@@ -1478,7 +1478,7 @@ findTangent(curve *       const curveP,
             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);
@@ -1487,7 +1487,7 @@ findTangent(curve *       const curveP,
     } while (slope.dx == 0.0 && slope.dy == 0.0);
 
     *tangentP = slope;
-    
+
     LOG3("(%.3f,%.3f,%.3f).\n",
          tangentP->dx, tangentP->dy, tangentP->dz);
 }
@@ -1502,8 +1502,8 @@ findError(curve *             const curveP,
           at_exception_type * const exceptionP) {
 /*----------------------------------------------------------------------------
   Tell how good a fit 'spline' is for *curveP.
-  
-  Return the error (maximum Euclidian distance between a point on
+
+  Return the error (maximum Euclidean 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.
@@ -1521,7 +1521,7 @@ findError(curve *             const curveP,
     totalError = 0.0;  /* initial value */
     worstError = FLT_MIN; /* initial value */
     worstPoint = 0;
-        
+
     for (thisPoint = 0; thisPoint < CURVE_LENGTH(curveP); ++thisPoint) {
         float_coord const curvePoint = CURVE_POINT(curveP, thisPoint);
         float const t = CURVE_T(curveP, thisPoint);
@@ -1608,7 +1608,7 @@ subdivideCurve(curve *                   const curveP,
   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.
@@ -1670,7 +1670,7 @@ leftRightConcat(const spline_list_type *  const leftSplineListP,
    of splines to that side of the curve.
 -----------------------------------------------------------------------------*/
     spline_list_type * retval;
-                
+
     retval = new_spline_list();
 
     if (leftSplineListP == NULL) {
@@ -1678,7 +1678,7 @@ leftRightConcat(const spline_list_type *  const leftSplineListP,
         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");
@@ -1742,7 +1742,7 @@ divideAndFit(curve *                   const curveP,
            subcurve.
         */
     spline_list_type * leftSplineListP;
-    
+
     assert(subdivisionIndex > 1);
     assert(subdivisionIndex < CURVE_LENGTH(curveP)-1);
     subdivideCurve(curveP, subdivisionIndex, fittingOptsP,
@@ -1792,18 +1792,18 @@ fitWithLeastSquares(curve *                   const curveP,
 /*----------------------------------------------------------------------------
   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. 
+  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) {
@@ -1822,7 +1822,7 @@ fitWithLeastSquares(curve *                   const curveP,
         unsigned int worstPoint;
 
         logSplineFit(spline);
-        
+
         findError(curveP, spline, &error, &worstPoint, exceptionP);
         assert(worstPoint < CURVE_LENGTH(curveP));
 
@@ -1873,7 +1873,7 @@ fitCurve(curve *                   const curveP,
 
     if (CURVE_LENGTH(curveP) < 2) {
         LOG("Tried to fit curve with fewer than two points");
-        at_exception_warning(exceptionP, 
+        at_exception_warning(exceptionP,
                              "Tried to fit curve with less than two points");
         fittedSplinesP = NULL;
     } else if (CURVE_LENGTH(curveP) < 4)
@@ -1894,12 +1894,12 @@ fitCurves(curve_list_type           const curveList,
           const fitting_opts_type * const fittingOptsP,
           spline_list_type *        const splinesP,
           at_exception_type *       const exceptionP) {
-          
+
     spline_list_type curveListSplines;
     unsigned int curveSeq;
 
     curveListSplines = empty_spline_list();
-    
+
     curveListSplines.open      = curveList.open;
     curveListSplines.clockwise = curveList.clockwise;
     curveListSplines.color     = color;
@@ -1932,13 +1932,13 @@ fitCurves(curve_list_type           const curveList,
                 at_exception_warning(exceptionP, "Could not fit curve");
             } else {
                 logSplinesForCurve(curveSeq, *curveSplinesP);
-                
+
                 /* After fitting, we may need to change some would-be lines
                    back to curves, because they are in a list with other
                    curves.
                 */
                 change_bad_lines(curveSplinesP, fittingOptsP);
-                
+
                 concat_spline_lists(&curveListSplines, *curveSplinesP);
                 free_spline_list(*curveSplinesP);
                 free(curveSplinesP);
@@ -1950,7 +1950,7 @@ fitCurves(curve_list_type           const curveList,
     else
         *splinesP = curveListSplines;
 }
-    
+
 
 
 static void
@@ -1989,7 +1989,7 @@ fitCurveList(curve_list_type     const curveList,
 
     if (dist != NULL)
         computePointWeights(curveList, fittingOptsP, dist);
-    
+
     /* We filter all the curves in 'curveList' at once; otherwise, we
        would look at an unfiltered curve when computing tangents.
     */
@@ -2030,12 +2030,12 @@ fitCurvesToSplines(curve_list_array_type    const curveArray,
                    unsigned short           const width,
                    unsigned short           const height,
                    at_exception_type *      const exception,
-                   at_progress_func               notifyProgress, 
+                   at_progress_func               notifyProgress,
                    void *                   const progressData,
                    at_testcancel_func             testCancel,
                    void *                   const testcancelData,
                    spline_list_array_type * const splineListArrayP) {
-    
+
     unsigned splineListSeq;
     bool cancelled;
     spline_list_array_type splineListArray;
@@ -2049,7 +2049,7 @@ fitCurvesToSplines(curve_list_array_type    const curveArray,
     /* Set dummy values. Real value is set in upper context. */
     splineListArray.width  = width;
     splineListArray.height = height;
-    
+
     for (splineListSeq = 0, cancelled = false;
          splineListSeq < CURVE_LIST_ARRAY_LENGTH(curveArray) &&
              !at_exception_got_fatal(exception) && !cancelled;
@@ -2057,7 +2057,7 @@ fitCurvesToSplines(curve_list_array_type    const curveArray,
 
         curve_list_type const curveList =
             CURVE_LIST_ARRAY_ELT(curveArray, splineListSeq);
-      
+
         spline_list_type curveSplineList;
 
         if (notifyProgress)
@@ -2087,7 +2087,7 @@ fit_outlines_to_splines(pixel_outline_list_type  const pixelOutlineList,
                         unsigned short           const width,
                         unsigned short           const height,
                         at_exception_type *      const exception,
-                        at_progress_func               notifyProgress, 
+                        at_progress_func               notifyProgress,
                         void *                   const progressData,
                         at_testcancel_func             testCancel,
                         void *                   const testcancelData,
@@ -2104,7 +2104,7 @@ fit_outlines_to_splines(pixel_outline_list_type  const pixelOutlineList,
                        testCancel, testcancelData, splineListArrayP);
 
     free_curve_list_array(&curveListArray, notifyProgress, progressData);
-    
+
     flush_log_output();
 }
 
diff --git a/converter/other/pamtotiff.c b/converter/other/pamtotiff.c
index 115b8b4a..1718c933 100644
--- a/converter/other/pamtotiff.c
+++ b/converter/other/pamtotiff.c
@@ -838,7 +838,7 @@ computeRasterParm(struct pam *     const pamP,
   2. Direct mode (specified with -output)
 
      We have the Tiff library write output to the specified file.  As the Tiff
-     library requires taht it be be seekable and readable, we fail the program
+     library requires that it be be seekable and readable, we fail the program
      rather than ask the Tiff library to use the file if it does not meet
      these requirements.
 
diff --git a/converter/other/pamtowinicon.c b/converter/other/pamtowinicon.c
index 3d77d731..3c2c06bf 100644
--- a/converter/other/pamtowinicon.c
+++ b/converter/other/pamtowinicon.c
@@ -71,8 +71,6 @@ parseCommandLine(int argc, const char **argv,
 
 static bool verbose;
 
-static unsigned char const pngHeader[] = PNG_HEADER;
-
 
 
 struct Palette {
@@ -285,10 +283,10 @@ writeBmpImageHeader(unsigned int const width,
 /*----------------------------------------------------------------------------
 
   Write BMP image header
-    
+
   Note: bm_height is sum of rows in XOR mask and AND mask, while
   image_size is the size of the AND mask only.
-    
+
   image_size does not include the sizes of the (optional) palette
   and the (mandatory) AND mask.
 -----------------------------------------------------------------------------*/
@@ -319,8 +317,8 @@ write32BitBmp(const struct pam *   const pamP,
   Write a 32-bit BMP encoded image to file *ofP.
 -----------------------------------------------------------------------------*/
     int row;
-    
-    writeBmpImageHeader(pamP->width, pamP->height, 32, 
+
+    writeBmpImageHeader(pamP->width, pamP->height, 32,
                         pamP->width * 4 * pamP->height, ofP);
 
     /*  write "XOR mask" */
@@ -336,7 +334,7 @@ write32BitBmp(const struct pam *   const pamP,
                 + ((uint32_t) pixel[PAM_GRN_PLANE] <<  8)
                 + ((uint32_t) pixel[PAM_BLU_PLANE] <<  0)
                 ;
-            
+
             if (haveAlpha)
                 val += (uint32_t) tuples[row][col][alphaPlane] << 24;
 
@@ -362,7 +360,7 @@ writeBmpPalette(const struct Palette * const paletteP,
                             +(paletteP->color[i][PAM_RED_PLANE] << 16)
                             +(paletteP->color[i][PAM_GRN_PLANE] <<  8)
                             +(paletteP->color[i][PAM_BLU_PLANE] <<  0));
-    
+
     for (; i < maxColors; ++i)
         pm_writelittlelongu(ofP, 0);
 }
@@ -384,7 +382,7 @@ writeXorMask(const struct pam *     const pamP,
     unsigned int const maxCol = ((pamP->width * bpp + 31) & ~31) / bpp;
 
     int row;
-                 
+
     for (row = pamP->height - 1; row >= 0; --row) {
         uint8_t  val;
         uint16_t mask;
@@ -502,7 +500,7 @@ writeAndMask(const struct pam * const pamP,
             mask <<= 1;
             val  <<= 1;
 
-            if (!andMakesOpaque(pamP, tuples, row, col, 
+            if (!andMakesOpaque(pamP, tuples, row, col,
                                 haveAlpha, alphaPlane, haveAnd, andPlane))
                 val |= 0x1;
 
@@ -539,7 +537,7 @@ makeAlphaFile(const struct pam * const imagePamP,
     struct pam alphaPam;
     tuple ** alphaTuples;
     unsigned int row;
-    
+
     pm_make_tmpfile(&alphaFileP, alphaFileNameP);
 
     alphaPam.size   = sizeof(alphaPam);
@@ -640,7 +638,7 @@ writePng(const struct pam * const pamP,
 
     acceptParm.ofP = ofP;
     acceptParm.writeCtP = &pngSize;
-    
+
     if (haveAlpha || haveAnd) {
         const char * alphaFileName;
         const char * alphaOpt;
@@ -652,15 +650,15 @@ writePng(const struct pam * const pamP,
 
         strcpy (pam.tuple_type,
                 pam.depth == 3 ? PAM_PPM_TUPLETYPE: PAM_PGM_TUPLETYPE);
-        
+
         pm_asprintf(&alphaOpt, "-alpha=%s", alphaFileName);
 
         pm_system_lp("pnmtopng", pm_feed_from_pamtuples, &pamTuples,
                      acceptToFile, &acceptParm,
                      "pnmtopng", alphaOpt, NULL);
-    
+
         pm_strfree(alphaOpt);
-    
+
         unlink(alphaFileName);
     } else {
         pm_system_lp("pnmtopng", pm_feed_from_pamtuples, &pamTuples,
@@ -908,19 +906,19 @@ writeIconAndCreateDirEntry(const struct pam *     const pamP,
             if (paletteP->colorCt <= 2) {
                 dirEntryP->color_count    = paletteP->colorCt;
                 dirEntryP->bits_per_pixel = 1;
-                    
+
                 writePaletteBmp(1, pamP, tuples, getPixel, paletteP,
                                 ofP, &bmpSize);
             } else if (paletteP->colorCt <= 16) {
                 dirEntryP->color_count    = paletteP->colorCt;
                 dirEntryP->bits_per_pixel = 4;
-                    
+
                 writePaletteBmp(4, pamP, tuples, getPixel,paletteP,
                                 ofP, &bmpSize);
             } else {
                 dirEntryP->color_count    = 0;
                 dirEntryP->bits_per_pixel = 8;
-                    
+
                 writePaletteBmp(8, pamP, tuples, getPixel, paletteP,
                                 ofP, &bmpSize);
             }
@@ -952,7 +950,7 @@ convertOneImage(unsigned int     const imageNum,
     GetPixelFn *        getPixel;
     struct Palette      palette;
     bool                doingPng;
-        
+
     /*  Output:
      *
      *  threshold^2 pixels or more:
@@ -976,6 +974,10 @@ convertOneImage(unsigned int     const imageNum,
 
     doingPng = pam.width * pam.height >= pngThreshold;
 
+    if (verbose)
+        pm_message("Image %2u: encoding as %s",
+                   imageNum, doingPng ? "PNG" : "BMP");
+
     readAndScalePam(&pam, doingPng, tuples);
 
     determineImageType(&pam, tuples, &getPixel,
@@ -1018,7 +1020,7 @@ convert(FILE *           const ifP,
 -----------------------------------------------------------------------------*/
     unsigned int imageNum;
     int eof;
-    
+
     for (imageNum = 0, eof = false; !eof; ++imageNum) {
         convertOneImage(imageNum, ifP, pngThreshold, mustBlackenXor,
                         ofP, dirP);
@@ -1032,14 +1034,14 @@ convert(FILE *           const ifP,
 static void
 writeIconDirEntry(const struct IconDirEntry * const dirEntryP,
                   FILE *                      const ofP) {
-        
+
     pm_writecharu        (ofP, dirEntryP->width);
     pm_writecharu        (ofP, dirEntryP->height);
     pm_writecharu        (ofP, dirEntryP->color_count);
     pm_writecharu        (ofP, dirEntryP->zero);
     pm_writelittleshortu (ofP, dirEntryP->color_planes);
     pm_writelittleshortu (ofP, dirEntryP->bits_per_pixel);
-    pm_writelittlelongu  (ofP, dirEntryP->size); 
+    pm_writelittlelongu  (ofP, dirEntryP->size);
     pm_writelittlelongu  (ofP, dirEntryP->offset);
 }
 
@@ -1067,7 +1069,7 @@ writeIconDirectory(const struct IconDir * const dirP,
          ++imageNum) {
 
         struct IconDirEntry * const dirEntryP = &dirP->entries[imageNum];
-        
+
         pm_message("image %2u: %3u x %3u x %2u",
                    imageNum,
                    dirEntryP->width,
@@ -1089,7 +1091,7 @@ copyFile(FILE * const ifP,
          FILE * const ofP) {
 
     bool eof;
-    
+
     for (eof = false; !eof; ) {
         unsigned char buffer[1024];
         size_t bytesRead;
diff --git a/converter/other/pamtoxvmini.c b/converter/other/pamtoxvmini.c
index b57bcc74..047de75a 100644
--- a/converter/other/pamtoxvmini.c
+++ b/converter/other/pamtoxvmini.c
@@ -23,16 +23,16 @@ typedef struct xvPalette {
 } xvPalette;
 
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     const char * inputFileName;
 };
 
 
 
 static void
-parseCommandLine(int const argc,
-                 char *    argv[],
-                 struct cmdlineInfo * const cmdlineP) {
+parseCommandLine(int const                  argc,
+                 const char *               argv[],
+                 struct CmdlineInfo * const cmdlineP) {
 
     if (argc-1 < 1)
         cmdlineP->inputFileName = "-";
@@ -75,7 +75,7 @@ static void
 writeXvHeader(FILE *       const ofP,
               unsigned int const cols,
               unsigned int const rows) {
-           
+
     fprintf(ofP, "P7 332\n");
 
     fprintf(ofP, "# Created by Pamtoxvmini\n");
@@ -94,12 +94,14 @@ writeXvHeader(FILE *       const ofP,
 
 static void
 findClosestColor(struct pam *      const pamP,
-                 tuple             const tuple, 
+                 tuple             const tuple,
                  const xvPalette * const xvPaletteP,
                  unsigned int *    const paletteIndexP) {
 /*----------------------------------------------------------------------------
    Find the color in the palette *xvPaletteP that is closest to the color
    'tuple' and return its index in the palette.
+
+   *pamP gives the format of 'tuple', which must be RGB with maxval 255.
 -----------------------------------------------------------------------------*/
     unsigned int paletteIndex;
     unsigned int bestPaletteIndex;
@@ -118,12 +120,12 @@ findClosestColor(struct pam *      const pamP,
         unsigned int const tupleRed = tuple[PAM_RED_PLANE];
         unsigned int const tupleGrn = tuple[PAM_GRN_PLANE];
         unsigned int const tupleBlu = tuple[PAM_BLU_PLANE];
-        
+
         unsigned int const paletteRed = xvPaletteP->red[paletteIndex];
         unsigned int const paletteGrn = xvPaletteP->grn[paletteIndex];
         unsigned int const paletteBlu = xvPaletteP->blu[paletteIndex];
 
-        unsigned int const distance = 
+        unsigned int const distance =
             SQR((int)tupleRed - (int)paletteRed) +
             SQR((int)tupleGrn - (int)paletteGrn) +
             SQR((int)tupleBlu - (int)paletteBlu);
@@ -155,24 +157,29 @@ getPaletteIndexThroughCache(struct pam *      const pamP,
     int found;
     int paletteIndex;
 
+    /* As required by findClosestColor(): */
+    assert(pamP->depth >= 3);
+    assert(pamP->maxval == 255);
+
     pnm_lookuptuple(pamP, paletteHash, tuple, &found, &paletteIndex);
     if (found)
         *paletteIndexP = paletteIndex;
     else {
         int fits;
+
         findClosestColor(pamP, tuple, xvPaletteP, paletteIndexP);
-        
+
         pnm_addtotuplehash(pamP, paletteHash, tuple, *paletteIndexP, &fits);
-        
+
         if (!fits)
             pm_error("Can't get memory for palette hash.");
     }
 }
 
-    
+
 
 static void
-writeXvRaster(struct pam * const pamP,
+writeXvRaster(struct pam * const inpamP,
               xvPalette *  const xvPaletteP,
               FILE *       const ofP) {
 /*----------------------------------------------------------------------------
@@ -190,33 +197,40 @@ writeXvRaster(struct pam * const pamP,
     unsigned int row;
     unsigned char * xvrow;
     struct pam scaledPam;
+    struct pam scaledRgbPam;
+
+    pnm_setminallocationdepth(inpamP, 3);
 
     paletteHash = pnm_createtuplehash();
 
-    tuplerow = pnm_allocpamrow(pamP);
-    xvrow = (unsigned char*)pm_allocrow(pamP->width, 1);
+    tuplerow = pnm_allocpamrow(inpamP);
+    xvrow = (unsigned char*)pm_allocrow(inpamP->width, 1);
 
-    scaledPam = *pamP;
+    scaledPam = *inpamP;  /* initial value */
     scaledPam.maxval = 255;
 
-    for (row = 0; row < pamP->height; ++row) {
+    scaledRgbPam = scaledPam;  /* initial value */
+    scaledRgbPam.depth = MAX(3, scaledPam.depth);
+
+    for (row = 0; row < inpamP->height; ++row) {
         unsigned int col;
 
-        pnm_readpamrow(pamP, tuplerow);
-        pnm_scaletuplerow(pamP, tuplerow, tuplerow, scaledPam.maxval);
+        pnm_readpamrow(inpamP, tuplerow);
+        pnm_scaletuplerow(inpamP, tuplerow, tuplerow, scaledPam.maxval);
         pnm_makerowrgb(&scaledPam, tuplerow);
 
-        for (col = 0; col < scaledPam.width; ++col) {
+        for (col = 0; col < scaledRgbPam.width; ++col) {
             unsigned int paletteIndex;
 
-            getPaletteIndexThroughCache(&scaledPam, tuplerow[col], xvPaletteP,
-                                        paletteHash, &paletteIndex);
+            getPaletteIndexThroughCache(&scaledRgbPam, tuplerow[col],
+                                        xvPaletteP, paletteHash,
+                                        &paletteIndex);
 
             assert(paletteIndex < 256);
 
             xvrow[col] = paletteIndex;
         }
-        fwrite(xvrow, 1, scaledPam.width, ofP);
+        fwrite(xvrow, 1, scaledRgbPam.width, ofP);
     }
 
     pm_freerow((char*)xvrow);
@@ -227,16 +241,16 @@ writeXvRaster(struct pam * const pamP,
 
 
 
-int 
-main(int    argc,
-     char * argv[]) {
+int
+main(int          argc,
+     const char * argv[]) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     FILE * ifP;
     struct pam pam;
     xvPalette xvPalette;
- 
-    pnm_init(&argc, argv);
+
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
@@ -246,13 +260,14 @@ main(int    argc,
 
     pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(allocation_depth));
 
-    pnm_setminallocationdepth(&pam, 3);
-
     writeXvHeader(stdout, pam.width, pam.height);
-    
+
     writeXvRaster(&pam, &xvPalette, stdout);
 
     pm_close(ifP);
 
     return 0;
 }
+
+
+
diff --git a/converter/other/pbmtopgm.c b/converter/other/pbmtopgm.c
index c35e1cbe..817fb5b3 100644
--- a/converter/other/pbmtopgm.c
+++ b/converter/other/pbmtopgm.c
@@ -6,6 +6,7 @@
 #include <limits.h>
 
 #include "pm_c_util.h"
+#include "nstring.h"
 #include "pgm.h"
 
 int
@@ -17,26 +18,23 @@ main(int argc, char *argv[]) {
     int rows, cols;
     FILE *ifd;
     int row;
-    int width, height;
+    unsigned int width, height;
     const char * const usage = "<w> <h> [pbmfile]";
-   
+    const char * error; /* error message of pm_string_to_uint */
 
     pgm_init( &argc, argv );
 
     if (argc > 4 || argc < 3)
         pm_usage(usage);
 
-    width = atoi(argv[1]);
-    height = atoi(argv[2]);
+    pm_string_to_uint(argv[1], &width, &error);
+    if (error)
+        pm_error("Invalid width argument: %s", error);
+    pm_string_to_uint(argv[2], &height, &error);
+    if (error)
+        pm_error("Invalid height argument: %s", error);
     if (width < 1 || height < 1)
         pm_error("width and height must be > 0");
-    if (width > INT_MAX / height)
-        /* prevent overflow of "value" below */
-        pm_error("sample area (%u columns %u rows) too large",
-                 width, height);
-
-    left=width/2; right=width-left;
-    up=height/2; down=height-up;
 
     if (argc == 4)
         ifd = pm_openr(argv[3]);
@@ -44,13 +42,22 @@ main(int argc, char *argv[]) {
         ifd = stdin ;
 
     inbits = pbm_readpbm(ifd, &cols, &rows) ;
-    
+
     if (width > cols)
         pm_error("You specified a sample width (%u columns) which is greater "
                  "than the image width (%u columns)", height, rows);
     if (height > rows)
         pm_error("You specified a sample height (%u rows) which is greater "
                  "than the image height (%u rows)", height, rows);
+    if (width > INT_MAX / height)
+        /* prevent overflow of "value" below */
+        pm_error("sample area (%u columns %u rows) too large",
+                 width, height);
+
+    left = width  / 2;  right = width  - left;
+    up   = height / 2;  down  = height - up;
+
+
 
     outrow = pgm_allocrow(cols) ;
     maxval = MIN(PGM_OVERALLMAXVAL, width*height);
@@ -65,7 +72,7 @@ main(int argc, char *argv[]) {
             int const l = (col > left) ? (col-left) : 0;
             int const r = (col+right < cols) ? (col+right) : cols;
             int const onh = width - (l-col+left) - (col+right-r);
-            int value;
+            int value;  /* See above */
             int x;
 
             value = 0;  /* initial value */
@@ -73,10 +80,10 @@ main(int argc, char *argv[]) {
             for (x = l; x < r; ++x) {
                 int y;
                 for (y = t; y < b; ++y)
-                    if (inbits[y][x] == PBM_WHITE) 
+                    if (inbits[y][x] == PBM_WHITE)
                         ++value;
             }
-            outrow[col] = maxval*value/(onh*onv);
+            outrow[col] = (gray) ((double) maxval*value/(onh*onv));
         }
         pgm_writepgmrow(stdout, outrow, cols, maxval, 0) ;
     }
diff --git a/converter/other/pdbimgtopam.c b/converter/other/pdbimgtopam.c
index 67044109..b191644f 100644
--- a/converter/other/pdbimgtopam.c
+++ b/converter/other/pdbimgtopam.c
@@ -56,7 +56,7 @@ parseCommandLine(int argc, const 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.  
+   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.
@@ -90,7 +90,7 @@ parseCommandLine(int argc, const char ** argv,
 
     if (!notefileSpec)
         cmdlineP->notefile = NULL;
-    
+
     if (argc-1 < 1)
         cmdlineP->inputFileName = "-";
     else if (argc-1 == 1)
@@ -152,7 +152,7 @@ decompress(const uint8_t * const compressed,
         const uint8_t * inP;
         uint8_t *       outP;
         size_t          bytesLeft;
-        
+
         for (bytesLeft = imageSize,
                  inP  = &compressed[0], outP = &uncompressed[0];
              bytesLeft > 0;
@@ -224,7 +224,7 @@ readCompressed(IMAGE *    const imgP,
          * this extra byte and ignore it by paying attention to
          * the image dimensions.
          */
-       size_t const maxCompressedSizeWithBloat = ipdb_img_size(imgP) * 2;
+       size_t const maxCompressedSizeWithBloat = ipdb_imgSize(imgP) * 2;
          /*
           * Provide a buffer large enough for the worst case.
           * See note in lib/util/runlength.c .
@@ -251,7 +251,7 @@ readCompressed(IMAGE *    const imgP,
          * Read to the indicated offset.
          */
         dataSize = end_offset - ftell(fP) + 1;
-        
+
         MALLOCARRAY(buffer, dataSize);
 
         if (buffer == NULL)
@@ -306,9 +306,9 @@ imageReadHeader(FILE *  const fileP,
         pm_message("  Y_anchor: %u", imgP->y_anchor);
         pm_message("  Width: %u", imgP->width);
         pm_message("  Height: %u", imgP->height);
-        pm_message("Pixels per byte: %u", ipdb_img_ppb(imgP));
+        pm_message("Pixels per byte: %u", ipdb_imgPpb(imgP));
         pm_message("Image size: %lu bytes",
-                   (unsigned long)ipdb_img_size(imgP));
+                   (unsigned long)ipdb_imgSize(imgP));
     }
 }
 
@@ -318,7 +318,7 @@ imageReadData(FILE *   const fileP,
               IMAGE *  const imgP,
               uint32_t const end_offset) {
 
-    size_t const imageSize = ipdb_img_size(imgP);  
+    size_t const imageSize = ipdb_imgSize(imgP);
 
     int retval;
     size_t dataSize;
@@ -390,7 +390,7 @@ textRead(TEXT * const textP,
         return 0;
 
     textP->r->offset = (uint32_t)ftell(fileP);
-    
+
     /*
      * What a pain in the ass!  Why the hell isn't there a length
      * attached to the text record?  I suppose the designer wasn't
@@ -453,7 +453,7 @@ pdbheadRead(PDBHEAD * const pdbHeadP,
     pm_readbiglongu2(fileP, &pdbHeadP->next_rec);
     pm_readbigshortu(fileP, &pdbHeadP->num_recs);
 
-    if (!memeq(pdbHeadP->type, IPDB_vIMG, 4) 
+    if (!memeq(pdbHeadP->type, IPDB_vIMG, 4)
         || !memeq(pdbHeadP->id, IPDB_View, 4))
         retval = E_NOTIMAGE;
     else
@@ -531,62 +531,54 @@ ipdbRead(IPDB * const pdbP,
 
     int retval;
 
-    ipdb_clear(pdbP);
+    int status;
 
-    pdbP->p = ipdb_pdbhead_alloc(NULL);
+    status = pdbheadRead(pdbP->p, fileP);
 
-    if (pdbP->p == NULL)
-        retval = ENOMEM;
+    if (status != 0)
+        retval = status;
     else {
-        int status;
-
-        status = pdbheadRead(pdbP->p, fileP);
-
-        if (status != 0)
-            retval = status;
+        pdbP->i = ipdb_imageCreate(pdbP->p->name, IMG_GRAY, 0, 0);
+        if (pdbP->i == NULL)
+            retval = ENOMEM;
         else {
-            pdbP->i = ipdb_image_alloc(pdbP->p->name, IMG_GRAY, 0, 0);
-            if (pdbP->i == NULL)
-                retval = ENOMEM;
+            int status;
+            status = rechdrRead(pdbP->i->r, fileP);
+            if (status != 0)
+                retval = status;
             else {
-                int status;
-                status = rechdrRead(pdbP->i->r, fileP);
-                if (status != 0)
-                    retval = status;
-                else {
-                    if (pdbP->p->num_recs > 1) {
-                        pdbP->t = ipdb_text_alloc(NULL);
-                        if (pdbP->t == NULL)
-                            retval = ENOMEM;
-                        else {
-                            int status;
-                            status = rechdrRead(pdbP->t->r, fileP);
-                            if (status != 0)
-                                retval = status;
-                            else
-                                retval = 0;
-                        }
-                    } else
-                        retval = 0;
-                    
-                    if (retval == 0) {
-                        uint32_t const offset =
-                            pdbP->t == NULL ?
-                            UNKNOWN_OFFSET : pdbP->t->r->offset - 1;
-
+                if (pdbP->p->num_recs > 1) {
+                    pdbP->t = ipdb_textAlloc();
+                    if (pdbP->t == NULL)
+                        retval = ENOMEM;
+                    else {
                         int status;
-
-                        status = imageRead(pdbP->i, offset, fileP, verbose);
+                        status = rechdrRead(pdbP->t->r, fileP);
                         if (status != 0)
                             retval = status;
-                        else {
-                            if (pdbP->t != NULL) {
-                                int status;
-                                
-                                status = textRead(pdbP->t, fileP);
-                                if (status != 0)
-                                    retval = status;
-                            }
+                        else
+                            retval = 0;
+                    }
+                } else
+                    retval = 0;
+
+                if (retval == 0) {
+                    uint32_t const offset =
+                        pdbP->t == NULL ?
+                        UNKNOWN_OFFSET : pdbP->t->r->offset - 1;
+
+                    int status;
+
+                    status = imageRead(pdbP->i, offset, fileP, verbose);
+                    if (status != 0)
+                        retval = status;
+                    else {
+                        if (pdbP->t != NULL) {
+                            int status;
+
+                            status = textRead(pdbP->t, fileP);
+                            if (status != 0)
+                                retval = status;
                         }
                     }
                 }
@@ -663,8 +655,8 @@ static void
 g16row(IPDB *       const pdbP,
        unsigned int const row,
        uint8_t *    const buffer) {
-    
-    g16unpack(ipdb_img_row(pdbP->i, row), buffer, ipdb_width(pdbP));
+
+    g16unpack(ipdb_imgRow(pdbP->i, row), buffer, ipdb_width(pdbP));
 }
 
 
@@ -674,7 +666,7 @@ grow(IPDB *       const pdbP,
      unsigned int const row,
      uint8_t *    const buffer) {
 
-    gunpack(ipdb_img_row(pdbP->i, row), buffer, ipdb_width(pdbP));
+    gunpack(ipdb_imgRow(pdbP->i, row), buffer, ipdb_width(pdbP));
 }
 
 
@@ -684,7 +676,7 @@ mrow(IPDB *       const pdbP,
      unsigned int const row,
      uint8_t *    const buffer) {
 
-    munpack(ipdb_img_row(pdbP->i, row), buffer, ipdb_width(pdbP));
+    munpack(ipdb_imgRow(pdbP->i, row), buffer, ipdb_width(pdbP));
 }
 
 
@@ -715,7 +707,7 @@ writeImgPam(IPDB * const pdbP,
            PAM_PBM_TUPLETYPE : PAM_PGM_TUPLETYPE);
 
     pnm_writepaminit(&pam);
-    
+
     tupleRow = pnm_allocpamrow(&pam);
 
     for (row = 0; row < pam.height; ++row) {
@@ -731,7 +723,7 @@ writeImgPam(IPDB * const pdbP,
 
         for (col = 0; col < pam.width; ++col)
             tupleRow[col][0] = imgRow[col];
-        
+
         pnm_writepamrow(&pam, tupleRow);
     }
     pnm_freepamrow(tupleRow);
@@ -754,7 +746,7 @@ writeText(IPDB *       const pdbP,
         fP = pm_openw(name);
         if (fP == NULL)
             pm_error("Could not open note file '%s' for output", name);
-        
+
         fprintf(fP, "%s\n", note);
 
         pm_close(fP);
@@ -777,7 +769,7 @@ main(int argc, const char ** argv) {
 
     ifP = pm_openr(cmdline.inputFileName);
 
-    pdbP = ipdb_alloc(NULL);
+    pdbP = ipdb_alloc();
     if (pdbP == NULL)
         pm_error("Could not allocate IPDB structure.");
 
@@ -795,3 +787,6 @@ main(int argc, const char ** argv) {
 
     return EXIT_SUCCESS;
 }
+
+
+
diff --git a/converter/other/pgmtopbm.c b/converter/other/pgmtopbm.c
index 67cac468..d5f67a06 100644
--- a/converter/other/pgmtopbm.c
+++ b/converter/other/pgmtopbm.c
@@ -17,19 +17,23 @@
 #include "pgm.h"
 #include "dithers.h"
 #include "mallocvar.h"
+#include "rand.h"
 
 enum halftone {QT_FS, QT_THRESH, QT_DITHER8, QT_CLUSTER, QT_HILBERT};
 
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
     const char *  inputFilespec;
     enum halftone halftone;
     unsigned int  clumpSize;
-    unsigned int  clusterRadius;  
+    unsigned int  clusterRadius;
         /* Defined only for halftone == QT_CLUSTER */
+    unsigned int  randomSeed;
+    unsigned int  randomSeedSpec;
+        /* Defined only for halftone == QT_FS */
     float         threshval;
 };
 
@@ -37,8 +41,8 @@ struct cmdlineInfo {
 
 
 static void
-parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo *cmdlineP) {
+parseCommandLine(int argc, const 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.
@@ -68,22 +72,24 @@ parseCommandLine(int argc, char ** argv,
     OPTENT3(0, "c4",        OPT_FLAG,  NULL, &cluster4Opt,  0);
     OPTENT3(0, "cluster8",  OPT_FLAG,  NULL, &cluster8Opt,  0);
     OPTENT3(0, "c8",        OPT_FLAG,  NULL, &cluster8Opt,  0);
-    OPTENT3(0, "value",     OPT_FLOAT, &cmdlineP->threshval, 
+    OPTENT3(0, "value",     OPT_FLOAT, &cmdlineP->threshval,
             &valueSpec, 0);
-    OPTENT3(0, "clump",     OPT_UINT,  &cmdlineP->clumpSize, 
+    OPTENT3(0, "clump",     OPT_UINT,  &cmdlineP->clumpSize,
             &clumpSpec, 0);
+    OPTENT3(0, "randomseed", OPT_UINT,  &cmdlineP->randomSeed,
+            &cmdlineP->randomSeedSpec, 0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We may have parms that are negative numbers */
 
-    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
-    if (floydOpt + thresholdOpt + hilbertOpt + dither8Opt + 
+    if (floydOpt + thresholdOpt + hilbertOpt + dither8Opt +
         cluster3Opt + cluster4Opt + cluster8Opt == 0)
         cmdlineP->halftone = QT_FS;
-    else if (floydOpt + thresholdOpt + dither8Opt + 
+    else if (floydOpt + thresholdOpt + dither8Opt +
         cluster3Opt + cluster4Opt + cluster8Opt > 1)
         pm_error("No cannot specify more than one halftoning type");
     else {
@@ -104,7 +110,7 @@ parseCommandLine(int argc, char ** argv,
         } else if (cluster8Opt) {
             cmdlineP->halftone = QT_CLUSTER;
             cmdlineP->clusterRadius = 8;
-        } else 
+        } else
             pm_error("INTERNAL ERROR.  No halftone option");
     }
 
@@ -118,7 +124,7 @@ parseCommandLine(int argc, char ** argv,
             pm_error("-value cannot be greater than one.  You specified %f",
                      cmdlineP->threshval);
     }
-            
+
     if (!clumpSpec)
         cmdlineP->clumpSize = 5;
     else {
@@ -127,6 +133,10 @@ parseCommandLine(int argc, char ** argv,
                      cmdlineP->clumpSize);
     }
 
+    if (cmdlineP->halftone != QT_FS && cmdlineP->randomSeedSpec)
+        pm_message ("Ignoring -randomseed value "
+                    "(meaningful only with Floyd-Steinberg)");
+
     if (argc-1 > 1)
         pm_error("Too many arguments (%d).  There is at most one "
                  "non-option argument:  the file name",
@@ -150,11 +160,11 @@ static int hil_x,hil_y;
 static int hil_stage[MAXORD];
 static int hil_width,hil_height;
 
-static void 
-init_hilbert(int const w, 
+static void
+init_hilbert(int const w,
              int const h) {
 /*----------------------------------------------------------------------------
-  Initialize the Hilbert curve tracer 
+  Initialize the Hilbert curve tracer
 -----------------------------------------------------------------------------*/
     int big,ber;
     hil_width = w;
@@ -169,7 +179,7 @@ init_hilbert(int const w,
 
 
 
-static int 
+static int
 hilbert(int * const px, int * const py) {
 /*----------------------------------------------------------------------------
   Return non-zero if got another point
@@ -215,7 +225,7 @@ hilbert(int * const px, int * const py) {
             temp = hil_dy;
             hil_dy = -hil_turn * hil_dx;
             hil_dx = hil_turn * temp;
-            if (hil_ord > 0) { 
+            if (hil_ord > 0) {
                 /* recurse */
 
                 hil_stage[hil_ord] = 3;
@@ -338,7 +348,7 @@ static void doHilbert(FILE *       const ifP,
 struct converter {
     void (*convertRow)(struct converter * const converterP,
                        unsigned int       const row,
-                       gray                     grayrow[], 
+                       gray                     grayrow[],
                        bit                      bitrow[]);
     void (*destroy)(struct converter * const converterP);
     unsigned int cols;
@@ -379,7 +389,7 @@ fsConvertRow(struct converter * const converterP,
 
     unsigned int limitcol;
     unsigned int col;
-    
+
     for (col = 0; col < converterP->cols + 2; ++col)
         nexterr[col] = 0;
     if (stateP->fs_forward) {
@@ -395,20 +405,20 @@ fsConvertRow(struct converter * const converterP,
     }
     do {
         long sum;
-        sum = ((long) *gP * fs_scale) / converterP->maxval + 
+        sum = ((long) *gP * fs_scale) / converterP->maxval +
             thiserr[col + 1];
         if (sum >= stateP->threshval) {
             *bP = PBM_WHITE;
             sum = sum - stateP->threshval - half_fs_scale;
         } else
             *bP = PBM_BLACK;
-        
+
         if (stateP->fs_forward) {
             thiserr[col + 2] += (sum * 7) / 16;
             nexterr[col    ] += (sum * 3) / 16;
             nexterr[col + 1] += (sum * 5) / 16;
             nexterr[col + 2] += (sum    ) / 16;
-            
+
             ++col;
             ++gP;
             ++bP;
@@ -417,13 +427,13 @@ fsConvertRow(struct converter * const converterP,
             nexterr[col + 2] += (sum * 3) / 16;
             nexterr[col + 1] += (sum * 5) / 16;
             nexterr[col    ] += (sum    ) / 16;
-            
+
             --col;
             --gP;
             --bP;
         }
     } while (col != limitcol);
-    
+
     stateP->thiserr = nexterr;
     stateP->nexterr = thiserr;
     stateP->fs_forward = ! stateP->fs_forward;
@@ -439,9 +449,11 @@ fsDestroy(struct converter * const converterP) {
 
 
 static struct converter
-createFsConverter(unsigned int const cols, 
+createFsConverter(unsigned int const cols,
                   gray         const maxval,
-                  float        const threshFraction) {
+                  float        const threshFraction,
+                  unsigned int const randomSeedSpec,
+                  unsigned int const randomSeed) {
 
     struct fsState * stateP;
     struct converter converter;
@@ -451,14 +463,19 @@ createFsConverter(unsigned int const cols,
     /* Initialize Floyd-Steinberg error vectors. */
     MALLOCARRAY_NOFAIL(stateP->thiserr, cols + 2);
     MALLOCARRAY_NOFAIL(stateP->nexterr, cols + 2);
-    srand(pm_randseed());
 
     {
         /* (random errors in [-fs_scale/8 .. fs_scale/8]) */
         unsigned int col;
+        struct pm_randSt randSt;
+        pm_randinit(&randSt);
+        pm_srand2(&randSt, randomSeedSpec, randomSeed);
+
         for (col = 0; col < cols + 2; ++col)
-            stateP->thiserr[col] = 
-                (long)(rand() % fs_scale - half_fs_scale) / 4;
+            stateP->thiserr[col] =
+                (long)(pm_rand(&randSt) % fs_scale - half_fs_scale) / 4;
+
+        pm_randterm(&randSt);
     }
 
     stateP->fs_forward = TRUE;
@@ -488,7 +505,7 @@ threshConvertRow(struct converter * const converterP,
                  unsigned int       const row,
                  gray                     grayrow[],
                  bit                      bitrow[]) {
-    
+
     struct threshState * const stateP = converterP->stateP;
 
     unsigned int col;
@@ -509,7 +526,7 @@ threshDestroy(struct converter * const converterP) {
 
 
 static struct converter
-createThreshConverter(unsigned int const cols, 
+createThreshConverter(unsigned int const cols,
                       gray         const maxval,
                       float        const threshFraction) {
 
@@ -571,7 +588,7 @@ dither8Destroy(struct converter * const converterP) {
 
 
 static struct converter
-createDither8Converter(unsigned int const cols, 
+createDither8Converter(unsigned int const cols,
                        gray         const maxval) {
 
     struct converter converter;
@@ -642,7 +659,7 @@ clusterDestroy(struct converter * const converterP) {
         free(stateP->clusterMatrix[row]);
 
     free(stateP->clusterMatrix);
-    
+
     free(stateP);
 }
 
@@ -650,9 +667,9 @@ clusterDestroy(struct converter * const converterP) {
 
 static struct converter
 createClusterConverter(unsigned int const radius,
-                       unsigned int const cols, 
+                       unsigned int const cols,
                        gray         const maxval) {
-    
+
     int const clusterNormalizer = radius * radius * 2;
     unsigned int const diameter = 2 * radius;
 
@@ -674,7 +691,7 @@ createClusterConverter(unsigned int const radius,
         unsigned int col;
 
         MALLOCARRAY_NOFAIL(stateP->clusterMatrix[row], diameter);
-        
+
         for (col = 0; col < diameter; ++col) {
             int val;
             switch (radius) {
@@ -686,7 +703,7 @@ createClusterConverter(unsigned int const radius,
             }
             stateP->clusterMatrix[row][col] = val * maxval / clusterNormalizer;
         }
-    }            
+    }
 
     converter.stateP = stateP;
 
@@ -696,14 +713,14 @@ createClusterConverter(unsigned int const radius,
 
 
 int
-main(int argc, char *argv[]) {
+main(int argc, const char *argv[]) {
 
-    struct cmdlineInfo cmdline;
-    FILE* ifP;
-    gray* grayrow;
-    bit* bitrow;
+    struct CmdlineInfo cmdline;
+    FILE * ifP;
+    gray * grayrow;
+    bit *  bitrow;
 
-    pgm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
@@ -719,24 +736,26 @@ main(int argc, char *argv[]) {
         int row;
 
         pgm_readpgminit(ifP, &cols, &rows, &maxval, &format);
-        
+
         pbm_writepbminit(stdout, cols, rows, 0);
 
         switch (cmdline.halftone) {
         case QT_FS:
-            converter = createFsConverter(cols, maxval, cmdline.threshval);
+            converter = createFsConverter(cols, maxval, cmdline.threshval,
+                                          cmdline.randomSeedSpec,
+                                          cmdline.randomSeed);
             break;
         case QT_THRESH:
             converter = createThreshConverter(cols, maxval, cmdline.threshval);
             break;
-        case QT_DITHER8: 
-            converter = createDither8Converter(cols, maxval); 
+        case QT_DITHER8:
+            converter = createDither8Converter(cols, maxval);
             break;
-        case QT_CLUSTER: 
-            converter = 
+        case QT_CLUSTER:
+            converter =
                 createClusterConverter(cmdline.clusterRadius, cols, maxval);
             break;
-        case QT_HILBERT: 
+        case QT_HILBERT:
                 pm_error("INTERNAL ERROR: halftone is QT_HILBERT where it "
                          "shouldn't be.");
                 break;
@@ -749,7 +768,7 @@ main(int argc, char *argv[]) {
             pgm_readpgmrow(ifP, grayrow, cols, maxval, format);
 
             converter.convertRow(&converter, row, grayrow, bitrow);
-            
+
             pbm_writepbmrow(stdout, bitrow, cols, 0);
         }
         pbm_freerow(bitrow);
@@ -763,3 +782,6 @@ main(int argc, char *argv[]) {
 
     return 0;
 }
+
+
+
diff --git a/converter/other/pgmtoppm.c b/converter/other/pgmtoppm.c
index c3a26594..dea6c4ca 100644
--- a/converter/other/pgmtoppm.c
+++ b/converter/other/pgmtoppm.c
@@ -17,27 +17,30 @@
 
 #include "pm_c_util.h"
 #include "mallocvar.h"
+#include "nstring.h"
 #include "shhopt.h"
 #include "ppm.h"
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
     const char * inputFilename;  /* '-' if stdin */
     const char * map;
-    const char * colorBlack;
-    const char * colorWhite;
+    const char * colorBlack;  /* malloc'ed */
+        /* The color to which the user says to map black */
+    const char * colorWhite;  /* malloc'ed */
+        /* The color to which the user says to map white */
 };
 
 
 
 static void
-parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo * const cmdlineP) {
+parseCommandLine(int argc, const 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.  
+   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.
@@ -52,11 +55,18 @@ parseCommandLine(int argc, char ** argv,
 
     unsigned int option_def_index;
 
-    unsigned int mapSpec;
+    unsigned int blackSpec, whiteSpec, mapSpec;
+
+    const char * blackOpt;
+    const char * whiteOpt;
 
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "black",          OPT_STRING,    &blackOpt,
+            &blackSpec,          0);
+    OPTENT3(0, "white",          OPT_STRING,    &whiteOpt,
+            &whiteSpec,          0);
     OPTENT3(0, "map",            OPT_STRING,    &cmdlineP->map,
             &mapSpec,            0);
 
@@ -64,13 +74,20 @@ parseCommandLine(int argc, char ** argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (!mapSpec)
         cmdlineP->map = NULL;
 
     if (mapSpec) {
+        if (blackSpec || whiteSpec)
+            pm_error("You may not specify -black or -white "
+                     "together with -map");
+
+        cmdlineP->colorBlack = NULL;
+        cmdlineP->colorWhite = NULL;
+
         /* No color argument; only argument is file name */
         if (argc-1 < 1)
             cmdlineP->inputFilename = "-";
@@ -81,37 +98,77 @@ parseCommandLine(int argc, char ** argv,
                          "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";
+        /* For default colors, we use "rgbi:..." instead of the simpler
+           "black" and "white" so that we don't have an unnecessary dependency
+           on a color dictionary being available.
+        */
+        if (blackSpec || whiteSpec) {
+            cmdlineP->colorBlack =
+                pm_strdup(blackSpec ? blackOpt : "rgbi:0/0/0");
+            cmdlineP->colorWhite =
+                pm_strdup(whiteSpec ? whiteOpt : "rgbi:1/1/1");
+
+            /* The only possibly argument is input file name */
+            if (argc-1 < 1)
+                cmdlineP->inputFilename = "-";
+            else {
+                cmdlineP->inputFilename = argv[1];
+                if (argc-1 > 1)
+                    pm_error("Whten you specify -black or -white, "
+                             "there can be at most one non-option arguments:  "
+                             "the file name.  "
+                             "You specified %u", argc-1);
+            }
         } else {
-            char * buffer = strdup(argv[1]);
-            char * hyphenPos = strchr(buffer, '-');
-            if (hyphenPos) {
-                *hyphenPos = '\0';
-                cmdlineP->colorBlack = buffer;
-                cmdlineP->colorWhite = hyphenPos+1;
+            /* Arguments are color or color range and optional file name */
+
+            if (argc-1 < 1) {
+                cmdlineP->colorBlack = pm_strdup("rgbi:0/0/0");
+                cmdlineP->colorWhite = pm_strdup("rgbi:1/1/1");
             } else {
-                cmdlineP->colorBlack = "black";
-                cmdlineP->colorWhite = buffer;
+                char * buffer = strdup(argv[1]);
+                if (!buffer)
+                    pm_error("Out of memory allocating tiny buffer");
+                char * hyphenPos = strchr(buffer, '-');
+                if (hyphenPos) {
+                    *hyphenPos = '\0';
+                    cmdlineP->colorBlack = pm_strdup(buffer);
+                    cmdlineP->colorWhite = pm_strdup(hyphenPos+1);
+                } else {
+                    cmdlineP->colorBlack = pm_strdup("rgbi:0/0/0");
+                    cmdlineP->colorWhite = pm_strdup(buffer);
+                }
+                free(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);
             }
         }
-        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
+freeCommandLine(struct CmdlineInfo const cmdline) {
+
+    if (cmdline.colorBlack)
+        pm_strfree(cmdline.colorBlack);
+    if (cmdline.colorWhite)
+        pm_strfree(cmdline.colorWhite);
+}
+
+
+
+static void
 convertWithMap(FILE * const ifP,
                unsigned int const cols,
                unsigned int const rows,
@@ -128,7 +185,7 @@ convertWithMap(FILE * const ifP,
     pixval mapmaxval;
     pixel ** mappixels;
     unsigned int mapmaxcolor;
-    
+
     mapFileP = pm_openr(mapFileName);
     mappixels = ppm_readppm(mapFileP, &mapcols, &maprows, &mapmaxval);
     pm_close(mapFileP);
@@ -138,7 +195,7 @@ convertWithMap(FILE * const ifP,
 
     for (row = 0; row < rows; ++row) {
         unsigned int col;
-            
+
         pgm_readpgmrow(ifP, grayrow, cols, maxval, format);
 
         for (col = 0; col < cols; ++col) {
@@ -168,22 +225,20 @@ convertLinear(FILE * const ifP,
               gray *       const grayrow,
               pixel *      const pixelrow) {
 
-    pixel colorBlack, colorWhite;
-    pixval red0, grn0, blu0, red1, grn1, blu1;
+    pixel const colorBlack = ppm_parsecolor(colorNameBlack, maxval);
+    pixel const colorWhite = ppm_parsecolor(colorNameWhite, maxval);
+
+    pixval const red0 = PPM_GETR(colorBlack);
+    pixval const grn0 = PPM_GETG(colorBlack);
+    pixval const blu0 = PPM_GETB(colorBlack);
+    pixval const red1 = PPM_GETR(colorWhite);
+    pixval const grn1 = PPM_GETG(colorWhite);
+    pixval const blu1 = PPM_GETB(colorWhite);
+
     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;
 
@@ -204,17 +259,17 @@ convertLinear(FILE * const ifP,
 
 
 int
-main(int    argc,
-     char * argv[]) {
+main(int          argc,
+     const char * argv[]) {
 
     FILE * ifP;
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     gray * grayrow;
     pixel * pixelrow;
     int rows, cols, format;
     gray maxval;
 
-    ppm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
@@ -228,7 +283,7 @@ main(int    argc,
         convertWithMap(ifP, cols, rows, maxval, format, cmdline.map,
                        stdout, grayrow, pixelrow);
     else
-        convertLinear(ifP, cols, rows, maxval, format, 
+        convertLinear(ifP, cols, rows, maxval, format,
                       cmdline.colorBlack, cmdline.colorWhite, stdout,
                       grayrow, pixelrow);
 
@@ -236,8 +291,13 @@ main(int    argc,
     pgm_freerow(grayrow);
     pm_close(ifP);
 
+    freeCommandLine(cmdline);
+
     /* 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
index 1023c6c6..3c0f81a5 100644
--- a/converter/other/pngtopam.c
+++ b/converter/other/pngtopam.c
@@ -22,7 +22,7 @@
 #include <math.h>
 #include <float.h>
 #include <png.h>
-/* Becaues of a design error in png.h, you must not #include <setjmp.h> before
+/* Because of a design error in png.h, you must not #include <setjmp.h> before
    <png.h>.  If you do, png.h won't compile.
 */
 #include <setjmp.h>
@@ -668,10 +668,16 @@ dumpPngInfo(struct pngx * const pngxP) {
                    background.blue);
     }
 
-    if (pngx_chunkIsPresent(pngxP, PNG_INFO_tRNS))
-        pm_message("tRNS chunk (transparency): %u entries",
-                   pngx_trns(pngxP).numTrans);
-    else
+    if (pngx_chunkIsPresent(pngxP, PNG_INFO_tRNS)) {
+        struct pngx_trns const trns = pngx_trns(pngxP);
+
+        pm_message("tRNS chunk (transparency):");
+        pm_message("  %u palette entries", trns.numTrans);
+        pm_message("  transparent color = (%u,%u,%u)",
+                   trns.transColor.red,
+                   trns.transColor.green,
+                   trns.transColor.blue);
+    } else
         pm_message("tRNS chunk (transparency): not present");
 
     if (pngx_chunkIsPresent(pngxP, PNG_INFO_gAMA))
@@ -868,17 +874,17 @@ paletteHasPartialTransparency(struct pngx * const pngxP) {
         if (pngx_chunkIsPresent(pngxP, PNG_INFO_tRNS)) {
             struct pngx_trns const trans = pngx_trns(pngxP);
 
-            bool foundGray;
+            bool foundPartial;
             unsigned int i;
 
-            for (i = 0, foundGray = FALSE;
-                 i < trans.numTrans && !foundGray;
+            for (i = 0, foundPartial = FALSE;
+                 i < trans.numTrans && !foundPartial;
                  ++i) {
                 if (trans.trans[i] != 0 && trans.trans[i] != pngxP->maxval) {
-                    foundGray = TRUE;
+                    foundPartial = TRUE;
                 }
             }
-            retval = foundGray;
+            retval = foundPartial;
         } else
             retval = FALSE;
     } else
diff --git a/converter/other/pngx.c b/converter/other/pngx.c
index 4bb09421..7840b2da 100644
--- a/converter/other/pngx.c
+++ b/converter/other/pngx.c
@@ -24,7 +24,7 @@ errorHandler(png_structp     const png_ptr,
 
     jmp_buf * jmpbufP;
 
-    /* this function, aside from the extra step of retrieving the "error
+    /* 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
@@ -416,6 +416,26 @@ void
 pngx_setFilter(struct pngx * const pngxP,
                int           const filterSet) {
 
+    /* This sets the allowed filters in the compressor.  The filters, and thus
+       the interpretation of 'filterSet', is specific to a filter method (aka
+       filter type), which you set with pngx_setIhdr.  There is only one
+       filter method defined today, though (PNG_FILTER_TYPE_BASE).
+
+       For filter method Base, 'filterSet' is the OR of the following masks,
+       each one allowing the compressor to use one filter.  Not that  the
+       compressor decides on a row-by-row basis what filter to use.
+
+         PNG_FILTER_NONE
+         PNG_FILTER_SUB
+         PNG_FILTER_UP
+         PNG_FILTER_AVG
+         PNG_FILTER_PAETH
+
+       There are also
+
+         PNG_NO_FILTERS
+         PNG_ALL_FILTERS
+    */
     png_set_filter(pngxP->png_ptr, 0, filterSet);
 }
 
diff --git a/converter/other/pnmtoddif.c b/converter/other/pnmtoddif.c
index ac02e425..b7b942b3 100644
--- a/converter/other/pnmtoddif.c
+++ b/converter/other/pnmtoddif.c
@@ -53,7 +53,7 @@ typedef struct {
 #define CONS 1
 
 /* "tag": Emit an ASN tag of the specified class and tag number.    */
-/* This is used in conjuntion with the                  */
+/* This is used in conjunction with the                  */
 /* wr_xxx routines that follow to construct the various ASN.1 entities. */
 /* Writing each entity is a two-step process, where first the tag is    */
 /* written and then the length and value.               */
@@ -263,7 +263,7 @@ write_header(FILE *file, imageparams *ip)
     tag(&p,CONTEXT,CONS, 0); ind(&p);        /* Document Descriptor */
     tag(&p,CONTEXT,PRIM, 0); wr_int(&p,1);  /* Major Version */
     tag(&p,CONTEXT,PRIM, 1); wr_int(&p,3);  /* Minor Version */
-    tag(&p,CONTEXT,PRIM, 2); wr_string(&p,"PBM+"); /* Product Indentifier */
+    tag(&p,CONTEXT,PRIM, 2); wr_string(&p,"PBM+"); /* Product Identifier */
     tag(&p,CONTEXT,CONS, 3); ind(&p);       /* Product Name */
     tag(&p,PRIVATE,PRIM, 9); emit_isolatin1(&p,"PBMPLUS Writer V1.0");
     eoc(&p);
diff --git a/converter/other/pnmtojpeg.c b/converter/other/pnmtojpeg.c
index 44826245..e3458319 100644
--- a/converter/other/pnmtojpeg.c
+++ b/converter/other/pnmtojpeg.c
@@ -9,7 +9,7 @@
   This program is by Bryan Henderson on 2000.03.06, but is derived
   with permission from the program cjpeg, which is in the Independent
   Jpeg Group's JPEG library package.  Under the terms of that permission,
-  redistribution of this software is restricted as described in the 
+  redistribution of this software is restricted as described in the
   file README.JPEG.
 
   Copyright (C) 1991-1998, Thomas G. Lane.
@@ -84,12 +84,12 @@ struct cmdlineInfo {
     struct density density;
 };
 
-static void 
-interpret_maxmemory (const char * const maxmemory, 
-                     long int * const max_memory_to_use_p) { 
+static void
+interpret_maxmemory (const char * const maxmemory,
+                     long int * const max_memory_to_use_p) {
     long int lval;
     char ch;
-    
+
     if (maxmemory == NULL) {
         *max_memory_to_use_p = -1;  /* unspecified */
     } else if (sscanf(maxmemory, "%ld%c", &lval, &ch) < 1) {
@@ -119,9 +119,9 @@ interpret_restart(const char * const restart,
         long lval;
         char ch;
         unsigned int matches;
-        
+
         matches= sscanf(restart, "%ld%c", &lval, &ch);
-        if (matches == 0) 
+        if (matches == 0)
             pm_error("Invalid value for the --restart option : '%s'.",
                      restart);
         else {
@@ -160,7 +160,7 @@ interpret_density(const char *        const densityString,
         int horiz, vert;
 
         unitName = malloc(strlen(densityString)+1);
-    
+
         matched = sscanf(densityString, "%dx%d%s", &horiz, &vert, unitName);
 
         if (matched < 2)
@@ -178,7 +178,7 @@ interpret_density(const char *        const densityString,
                 densityP->horiz = horiz;
                 densityP->vert  = vert;
 
-                if (matched < 3) 
+                if (matched < 3)
                     densityP->unit = DEN_UNSPECIFIED;
                 else {
                     if (streq(unitName, "dpi") || streq(unitName, "DPI"))
@@ -235,7 +235,7 @@ parseCommandLine(const int argc, char ** argv,
 
     option_def_index = 0;   /* incremented by OPTENTRY */
     OPTENT3(0, "verbose",     OPT_FLAG,   NULL, &cmdlineP->verbose,        0);
-    OPTENT3(0, "quality",     OPT_UINT,   &cmdlineP->quality, 
+    OPTENT3(0, "quality",     OPT_UINT,   &cmdlineP->quality,
             &qualitySpec,        0);
     OPTENT3(0, "baseline",    OPT_FLAG,   NULL, &cmdlineP->force_baseline, 0);
     OPTENT3(0, "progressive", OPT_FLAG,   NULL, &cmdlineP->progressive,    0);
@@ -250,14 +250,14 @@ parseCommandLine(const int argc, char ** argv,
     OPTENT3(0, "qtables",     OPT_STRING, &cmdlineP->qtablefile,  NULL,    0);
     OPTENT3(0, "sample",      OPT_STRING, &cmdlineP->sample,      NULL,    0);
     OPTENT3(0, "scans",       OPT_STRING, &cmdlineP->scans,       NULL,    0);
-    OPTENT3(0, "smooth",      OPT_UINT,   &cmdlineP->smoothing_factor, 
+    OPTENT3(0, "smooth",      OPT_UINT,   &cmdlineP->smoothing_factor,
             &smoothSpec,  0);
     OPTENT3(0, "optimize",    OPT_FLAG,   NULL, &cmdlineP->optimize,       0);
     OPTENT3(0, "optimise",    OPT_FLAG,   NULL, &cmdlineP->optimize,       0);
     OPTENT3(0, "restart",     OPT_STRING, &restart, NULL,                   0);
     OPTENT3(0, "comment",     OPT_STRING, &cmdlineP->comment, NULL,        0);
     OPTENT3(0, "exif",        OPT_STRING, &cmdlineP->exif_filespec, NULL,  0);
-    OPTENT3(0, "density",     OPT_STRING, &density, 
+    OPTENT3(0, "density",     OPT_STRING, &density,
             &cmdlineP->density_spec, 0);
 
     /* Set the defaults */
@@ -295,7 +295,7 @@ parseCommandLine(const int argc, char ** argv,
         cmdlineP->input_filespec = strdup("-");  /* he wants stdin */
     else if (argc_parse - 1 == 1)
         cmdlineP->input_filespec = strdup(argv_parse[1]);
-    else 
+    else
         pm_error("Too many arguments.  The only argument accepted "
                  "is the input file specification.");
     if (dctval == NULL)
@@ -314,15 +314,15 @@ parseCommandLine(const int argc, char ** argv,
     interpret_maxmemory(maxmemory, &cmdlineP->max_memory_to_use);
     interpret_restart(restart, &cmdlineP->restart_value,
                       &cmdlineP->restart_unit);
-    if (cmdlineP->density_spec) 
+    if (cmdlineP->density_spec)
         interpret_density(density, &cmdlineP->density);
-    
+
     if (cmdlineP->smoothing_factor > 100)
         pm_error("Smoothing factor %d is greater than 100 (%%).",
                  cmdlineP->smoothing_factor);
 
     if (streq(cmdlineP->input_filespec, "=") &&
-        cmdlineP->exif_filespec && 
+        cmdlineP->exif_filespec &&
         streq(cmdlineP->exif_filespec, "-"))
 
         pm_error("Cannot have both input image and exif header be from "
@@ -336,7 +336,7 @@ parseCommandLine(const int argc, char ** argv,
 
 static void
 report_compressor(const struct jpeg_compress_struct cinfo) {
-    
+
     if (cinfo.scan_info == NULL)
         pm_message("No scan script is being used");
     else {
@@ -346,7 +346,7 @@ report_compressor(const struct jpeg_compress_struct cinfo) {
         for (i = 0; i < cinfo.num_scans; i++) {
             int j;
             pm_message("    Scan %2d: Ss=%2d Se=%2d Ah=%2d Al=%2d  "
-                       "%d components", 
+                       "%d components",
                        i,
                        cinfo.scan_info[i].Ss,
                        cinfo.scan_info[i].Se,
@@ -364,11 +364,11 @@ report_compressor(const struct jpeg_compress_struct cinfo) {
 
 
 static void
-setup_jpeg_source_parameters(struct jpeg_compress_struct * const cinfoP, 
-                             int const width, int const height, 
+setup_jpeg_source_parameters(struct jpeg_compress_struct * const cinfoP,
+                             int const width, int const height,
                              int const format) {
 /*----------------------------------------------------------------------------
-   Set up in the compressor descriptor *cinfoP the description of the 
+   Set up in the compressor descriptor *cinfoP the description of the
    source image as required by the compressor.
 -----------------------------------------------------------------------------*/
 
@@ -379,7 +379,7 @@ setup_jpeg_source_parameters(struct jpeg_compress_struct * const cinfoP,
         cinfoP->input_components = 1;
         break;
     case PPM_TYPE:
-        cinfoP->in_color_space = JCS_RGB; 
+        cinfoP->in_color_space = JCS_RGB;
         cinfoP->input_components = 3;
         break;
     default:
@@ -391,7 +391,7 @@ setup_jpeg_source_parameters(struct jpeg_compress_struct * const cinfoP,
 
 
 static void
-setup_jpeg_density(struct jpeg_compress_struct * const cinfoP, 
+setup_jpeg_density(struct jpeg_compress_struct * const cinfoP,
                    struct density                const density) {
 /*----------------------------------------------------------------------------
    Set up in the compressor descriptor *cinfoP the density information
@@ -402,7 +402,7 @@ setup_jpeg_density(struct jpeg_compress_struct * const cinfoP,
     case DEN_DOTS_PER_INCH: cinfoP->density_unit = 1; break;
     case DEN_DOTS_PER_CM:   cinfoP->density_unit = 2; break;
     }
-    
+
     cinfoP->X_density = density.horiz;
     cinfoP->Y_density = density.vert;
 }
@@ -411,7 +411,7 @@ 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
+   the JPEG library.  They perform the functions specified by the following
    pnmtojpeg options:
 
    -qtables file          Read quantization tables from text file
@@ -426,7 +426,7 @@ text_getc (FILE * file)
 /* A comment/newline sequence is returned as a newline */
 {
     register int ch;
-  
+
     ch = getc(file);
     if (ch == '#') {
         do {
@@ -454,12 +454,12 @@ readTextInteger(FILE * const fileP,
 -----------------------------------------------------------------------------*/
     int ch;
     boolean retval;
-  
+
     /* Skip any leading whitespace, detect EOF */
     do {
         ch = text_getc(fileP);
     } while (isspace(ch));
-  
+
     if (!isdigit(ch))
         retval = FALSE;
     else {
@@ -554,7 +554,7 @@ read_scan_script(j_compress_ptr const cinfo,
         ncomps = 1;
         while (termchar == ' ') {
             if (ncomps >= MAX_COMPS_IN_SCAN) {
-                pm_message("Too many components in one scan in file %s", 
+                pm_message("Too many components in one scan in file %s",
                            filename);
                 fclose(fp);
                 return FALSE;
@@ -603,10 +603,10 @@ read_scan_script(j_compress_ptr const cinfo,
         /* 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.  
+           want JPOOL_PERMANENT.
         */
         const unsigned int scan_info_size = nscans * sizeof(jpeg_scan_info);
-        jpeg_scan_info * const scan_info = 
+        jpeg_scan_info * const scan_info =
             (jpeg_scan_info *)
             (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
                                         scan_info_size);
@@ -656,7 +656,7 @@ read_quant_tables (j_compress_ptr cinfo, char * filename,
                 if (tblno >= NUM_QUANT_TBLS) {
                     pm_message("Too many tables in file %s", filename);
                     error = TRUE;
-                } else { 
+                } else {
                     unsigned int table[DCTSIZE2];
                     unsigned int i;
 
@@ -686,7 +686,7 @@ read_quant_tables (j_compress_ptr cinfo, char * filename,
         fclose(fp);
         retval = !error;
     }
-        
+
     return retval;
 }
 
@@ -717,7 +717,7 @@ set_quant_slots (j_compress_ptr cinfo, char *arg)
                 return FALSE;
             }
             cinfo->comp_info[ci].quant_tbl_no = val;
-            while (*arg && *arg++ != ',') 
+            while (*arg && *arg++ != ',')
                 /* advance to next segment of arg string */
                 ;
         } else {
@@ -747,7 +747,7 @@ set_sample_factors (j_compress_ptr cinfo, char *arg)
             if ((ch1 != 'x' && ch1 != 'X') || ch2 != ',') /* syntax check */
                 return FALSE;
             if (val1 <= 0 || val1 > 4) {
-                pm_message("Invalid sampling factor: %d.  " 
+                pm_message("Invalid sampling factor: %d.  "
                            "JPEG sampling factors must be 1..4", val1);
                 return FALSE;
             }
@@ -758,11 +758,11 @@ set_sample_factors (j_compress_ptr cinfo, char *arg)
             }
             cinfo->comp_info[ci].h_samp_factor = val1;
             cinfo->comp_info[ci].v_samp_factor = val2;
-            while (*arg && *arg++ != ',') 
+            while (*arg && *arg++ != ',')
                 /* advance to next segment of arg string */
                 ;
         } else {
-            /* reached end of parameter, set remaining components 
+            /* 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;
@@ -776,13 +776,13 @@ set_sample_factors (j_compress_ptr cinfo, char *arg)
 static void
 setup_jpeg(struct jpeg_compress_struct * const cinfoP,
            struct jpeg_error_mgr       * const jerrP,
-           struct cmdlineInfo            const cmdline, 
+           struct cmdlineInfo            const cmdline,
            int                           const width,
            int                           const height,
            pixval                        const maxval,
            int                           const input_fmt,
            FILE *                        const output_file) {
-  
+
     int quality;
     int q_scale_factor;
 
@@ -794,14 +794,14 @@ setup_jpeg(struct jpeg_compress_struct * const cinfoP,
 
     jpeg_set_defaults(cinfoP);
 
-    cinfoP->data_precision = BITS_IN_JSAMPLE; 
+    cinfoP->data_precision = BITS_IN_JSAMPLE;
         /* we always rescale data to this */
     cinfoP->image_width = (unsigned int) width;
     cinfoP->image_height = (unsigned int) height;
 
     cinfoP->arith_code = cmdline.arith_code;
     cinfoP->dct_method = cmdline.dct_method;
-    if (cmdline.trace_level == 0 && cmdline.verbose) 
+    if (cmdline.trace_level == 0 && cmdline.verbose)
         cinfoP->err->trace_level = 1;
     else cinfoP->err->trace_level = cmdline.trace_level;
     if (cmdline.grayscale)
@@ -822,26 +822,26 @@ setup_jpeg(struct jpeg_compress_struct * const cinfoP,
         quality = cmdline.quality;
         q_scale_factor = jpeg_quality_scaling(cmdline.quality);
     }
-    if (cmdline.smoothing_factor != -1) 
+    if (cmdline.smoothing_factor != -1)
         cinfoP->smoothing_factor = cmdline.smoothing_factor;
 
     /* Set quantization tables for selected quality. */
     /* Some or all may be overridden if user specified --qtables. */
     jpeg_set_quality(cinfoP, quality, cmdline.force_baseline);
-                   
+
     if (cmdline.qtablefile != NULL) {
         if (! read_quant_tables(cinfoP, cmdline.qtablefile,
-                                q_scale_factor, cmdline.force_baseline)) 
+                                q_scale_factor, cmdline.force_baseline))
             pm_error("Can't use quantization table file '%s'.",
                      cmdline.qtablefile);
     }
-   
+
     if (cmdline.qslots != NULL) {
         if (! set_quant_slots(cinfoP, cmdline.qslots))
-            pm_error("Bad quantization-table-selectors parameter string '%s'.", 
+            pm_error("Bad quantization-table-selectors parameter string '%s'.",
                      cmdline.qslots);
     }
-          
+
     if (cmdline.sample != NULL) {
         if (! set_sample_factors(cinfoP, cmdline.sample))
             pm_error("Bad sample-factors parameters string '%s'.",
@@ -878,7 +878,7 @@ write_exif_header(struct jpeg_compress_struct * const cinfoP,
 /*----------------------------------------------------------------------------
    Generate an APP1 marker in the JFIF output that is an Exif header.
 
-   The contents of the Exif header are in the file with filespec 
+   The contents of the Exif header are in the file with filespec
    'exif_filespec' (file spec and contents are not validated).
 
    exif_filespec = "-" means Standard Input.
@@ -888,7 +888,7 @@ write_exif_header(struct jpeg_compress_struct * const cinfoP,
 -----------------------------------------------------------------------------*/
     FILE * exif_file;
     unsigned short length;
-    
+
     exif_file = pm_openr(exif_filespec);
 
     pm_readbigshort(exif_file, (short*)&length);
@@ -900,7 +900,7 @@ write_exif_header(struct jpeg_compress_struct * const cinfoP,
     else {
         unsigned char * exif_data;
         size_t rc;
-        size_t const data_length = length - 2;  
+        size_t const data_length = length - 2;
             /* Subtract 2 byte length field*/
 
         assert(data_length > 0);
@@ -917,16 +917,16 @@ write_exif_header(struct jpeg_compress_struct * const cinfoP,
                      "%u bytes of data, read only %u",
                      (unsigned)data_length, (unsigned)rc);
 
-        jpeg_write_marker(cinfoP, JPEG_APP0+1, 
+        jpeg_write_marker(cinfoP, JPEG_APP0+1,
                           (const JOCTET *) exif_data, data_length);
 
         free(exif_data);
     }
-    
+
     pm_close(exif_file);
 }
 
-                  
+
 
 static void
 compute_rescaling_array(JSAMPLE ** const rescale_p, const pixval maxval,
@@ -940,7 +940,7 @@ compute_rescaling_array(JSAMPLE ** const rescale_p, const pixval maxval,
 
   *rescale_p = (JSAMPLE *)
     (cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_IMAGE,
-                              (size_t) (((long) maxval + 1L) * 
+                              (size_t) (((long) maxval + 1L) *
                                         sizeof(JSAMPLE)));
   for (val = 0; val <= maxval; val++) {
     /* The multiplication here must be done in 32 bits to avoid overflow */
@@ -951,9 +951,9 @@ compute_rescaling_array(JSAMPLE ** const rescale_p, const pixval maxval,
 
 
 static void
-translate_row(const pixel pnm_buffer[], 
-              JSAMPLE jpeg_buffer[], 
-              int const width, 
+translate_row(const pixel pnm_buffer[],
+              JSAMPLE jpeg_buffer[],
+              int const width,
               int const input_components,
               const JSAMPLE translate[]) {
 /*----------------------------------------------------------------------------
@@ -971,16 +971,16 @@ translate_row(const pixel pnm_buffer[],
 
   switch (input_components) {
   case 1:
-      for (column = 0; column < width; column++) 
+      for (column = 0; column < width; column++)
           jpeg_buffer[column] = translate[(int)PNM_GET1(pnm_buffer[column])];
       break;
   case 3:
       for (column = 0; column < width; column++) {
-          jpeg_buffer[column*3+0] = 
+          jpeg_buffer[column*3+0] =
               translate[(int)PPM_GETR(pnm_buffer[column])];
-          jpeg_buffer[column*3+1] = 
+          jpeg_buffer[column*3+1] =
               translate[(int)PPM_GETG(pnm_buffer[column])];
-          jpeg_buffer[column*3+2] = 
+          jpeg_buffer[column*3+2] =
               translate[(int)PPM_GETB(pnm_buffer[column])];
       }
       break;
@@ -1000,17 +1000,17 @@ convert_scanlines(struct jpeg_compress_struct * const cinfo_p,
                   int                           const input_fmt,
                   JSAMPLE                             xlate_table[]){
 /*----------------------------------------------------------------------------
-   Read scan lines from the input file, which is already opened in the 
-   netpbm library sense and ready for reading, and write them to the 
+   Read scan lines from the input file, which is already opened in the
+   netpbm library sense and ready for reading, and write them to the
    output JPEG object.  Translate the pnm sample values to JPEG sample
    values through the thable xlate_table[].
 -----------------------------------------------------------------------------*/
-  xel * pnm_buffer;  
+  xel * pnm_buffer;
     /* contains the row of the input image currently being processed,
        in pnm_readpnmrow format
     */
   JSAMPARRAY buffer;
-    /* Row 0 of this array contains the row of the output image currently 
+    /* Row 0 of this array contains the row of the output image currently
        being processed, in JPEG compressor input format.  The array only
        has that one row.
     */
@@ -1018,26 +1018,26 @@ convert_scanlines(struct jpeg_compress_struct * const cinfo_p,
   /* Allocate the libpnm output and compressor input buffers */
   buffer = (*cinfo_p->mem->alloc_sarray)
     ((j_common_ptr) cinfo_p, JPOOL_IMAGE,
-     (unsigned int) cinfo_p->image_width * cinfo_p->input_components, 
+     (unsigned int) cinfo_p->image_width * cinfo_p->input_components,
      (unsigned int) 1);
-  
+
   pnm_buffer = pnm_allocrow(cinfo_p->image_width);
 
   while (cinfo_p->next_scanline < cinfo_p->image_height) {
-    if (cinfo_p->err->trace_level > 1) 
+    if (cinfo_p->err->trace_level > 1)
         pm_message("Converting Row %d...", cinfo_p->next_scanline);
-    pnm_readpnmrow(input_file, pnm_buffer, cinfo_p->image_width, 
+    pnm_readpnmrow(input_file, pnm_buffer, cinfo_p->image_width,
                    maxval, input_fmt);
-    translate_row(pnm_buffer, buffer[0], 
+    translate_row(pnm_buffer, buffer[0],
                   cinfo_p->image_width, cinfo_p->input_components,
                   xlate_table);
     jpeg_write_scanlines(cinfo_p, buffer, 1);
-    if (cinfo_p->err->trace_level > 1) 
+    if (cinfo_p->err->trace_level > 1)
         pm_message("Done.");
   }
 
   pnm_freerow(pnm_buffer);
-  /* Don't worry about the compressor input buffer; it gets freed 
+  /* Don't worry about the compressor input buffer; it gets freed
      automatically
   */
 }
@@ -1053,11 +1053,11 @@ main(int     argc,
     struct jpeg_error_mgr jerr;
     FILE * input_file;
     FILE * output_file;
-    int height;  
+    int height;
         /* height of the input image in rows, as specified by its header */
-    int width;   
+    int width;
         /* width of the input image in columns, as specified by its header */
-    pixval maxval;  
+    pixval maxval;
         /* maximum value of an input pixel component, as specified by header */
     int input_fmt;
         /* The input format, as determined by its header.  */
@@ -1081,7 +1081,7 @@ main(int     argc,
     if (cmdline.verbose) {
         pm_message("Input file has format %c%c.\n"
                    "It has %d rows of %d columns of pixels "
-                   "with max sample value of %d.", 
+                   "with max sample value of %d.",
                    (char) (input_fmt/256), (char) (input_fmt % 256),
                    height, width, maxval);
     }
@@ -1091,13 +1091,13 @@ main(int     argc,
 
     compute_rescaling_array(&rescale, maxval, cinfo);
 
-    if (cmdline.comment) 
-        jpeg_write_marker(&cinfo, JPEG_COM, (const JOCTET *) cmdline.comment, 
+    if (cmdline.comment)
+        jpeg_write_marker(&cinfo, JPEG_COM, (const JOCTET *) cmdline.comment,
                           strlen(cmdline.comment));
 
     if (cmdline.exif_filespec)
         write_exif_header(&cinfo, cmdline.exif_filespec);
-    
+
     /* Translate and copy over the actual scanlines */
     convert_scanlines(&cinfo, input_file, maxval, input_fmt, rescale);
 
@@ -1110,7 +1110,10 @@ main(int     argc,
         pm_close(input_file);
 
     /* Program may have exited with non-zero completion code via
-       various function calls above. 
+       various function calls above.
     */
     return jerr.num_warnings > 0 ? EXIT_WARNING : EXIT_SUCCESS;
 }
+
+
+
diff --git a/converter/other/pnmtopalm/README b/converter/other/pnmtopalm/README
index ebae9492..3a2cf18d 100644
--- a/converter/other/pnmtopalm/README
+++ b/converter/other/pnmtopalm/README
@@ -40,7 +40,7 @@ Usage: ppmtoTbmp [-2bit] [file.ppm]
 If the ppm file is not specified, one is read from stdin.  The -2bit option
 produces a 2-bit bitmap instead of the normal 1-bit bitmap.  The ppm must
 have at most 4 colors in it (for 2-bit) or at most 2 colors (for 1-bit).
-Common invokations might be:
+Common invocations might be:
 
 xbmtopbm icon.xbm | ppmquant -fs -map q2.map | ppmtoTbmp > tAIB03e8.bin
 giftopnm image.gif | ppmquant -fs -map q4.map | ppmtoTbmp -2bit > Tbmp0bb8.bin
diff --git a/converter/other/pnmtopalm/palmtopnm.c b/converter/other/pnmtopalm/palmtopnm.c
index 0666141d..a64ab01c 100644
--- a/converter/other/pnmtopalm/palmtopnm.c
+++ b/converter/other/pnmtopalm/palmtopnm.c
@@ -798,10 +798,12 @@ readRleRow(FILE *          const ifP,
         if (incount == 0)
             pm_error("Invalid (zero) count in RLE compression.");
         if (j + incount > bytesPerRow)
-            pm_error("Bytes in RLE compressed row exceed bytes per row.  "
-                     "Bytes per row is %u.  A run length of %u bytes "
-                     "pushes the bytes in this row up to %u bytes (and then "
-                     "we gave up).", bytesPerRow, incount, j + incount);
+            pm_error("Invalid Palm image input.  Header says %u bytes "
+                     "per row after uncompressing from RLE, "
+                     "but we encountered a row with a run length of %u bytes "
+                     "that pushes the bytes in the row up to %u bytes "
+                     "(and we didn't look at the rest of the row)",
+                     bytesPerRow, incount, j + incount);
         pm_readcharu(ifP, &inval);
         memset(palmrow + j, inval, incount);
         j += incount;
@@ -867,10 +869,11 @@ readPackBitsRow16(FILE *          const ifP,
             j += nonrunlength;
         }
         if (j > bytesPerRow)
-            pm_error("Bytes in PackBits compressed row exceed bytes per row.  "
-                     "Bytes per row is %u.  "
-                     "The bytes in this row were pushed up to %u bytes "
-                     "(and then we gave up).", bytesPerRow, j);
+            pm_error("Invalid Palm image input.  Header says %u bytes "
+                     "per row after uncompressing from 16-bit Packbits at, "
+                     "but we counted %u bytes in a row, "
+                     "before we stopped processing the row",
+                     bytesPerRow, j);
     }
 }
 
@@ -915,10 +918,11 @@ readPackBitsRow(FILE *          const ifP,
             j += nonrunlength;
         }
         if (j > bytesPerRow)
-            pm_error("Bytes in PackBits compressed row exceed bytes per row.  "
-                     "Bytes per row is %u.  "
-                     "The bytes in this row were pushed up to %u bytes "
-                     "(and then we gave up).", bytesPerRow, j);
+            pm_error("Invalid Palm image input.  Header says %u bytes "
+                     "per row after uncompressing from 8-bit Packbits, "
+                     "but we counted %u bytes in a row, "
+                     "before we stopped processing the row",
+                     bytesPerRow, j);
     }
 }
 
diff --git a/converter/other/pnmtopalm/pnmtopalm.c b/converter/other/pnmtopalm/pnmtopalm.c
index 25c8af2e..9fc92790 100644
--- a/converter/other/pnmtopalm/pnmtopalm.c
+++ b/converter/other/pnmtopalm/pnmtopalm.c
@@ -74,27 +74,27 @@ parseCommandLine(int argc, const char ** argv, struct CmdlineInfo *cmdlineP) {
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENTRY */
-    OPTENT3(0, "transparent",      OPT_STRING, 
+    OPTENT3(0, "transparent",      OPT_STRING,
             &cmdlineP->transparent, &transSpec, 0);
-    OPTENT3(0, "depth",            OPT_UINT, 
+    OPTENT3(0, "depth",            OPT_UINT,
             &cmdlineP->depth,       &cmdlineP->depthSpec, 0);
-    OPTENT3(0, "maxdepth",         OPT_UINT, 
+    OPTENT3(0, "maxdepth",         OPT_UINT,
             &cmdlineP->maxdepth,    &cmdlineP->maxdepthSpec, 0);
-    OPTENT3(0, "scanline_compression", OPT_FLAG, 
+    OPTENT3(0, "scanline_compression", OPT_FLAG,
             NULL,                   &scanline_compression, 0);
-    OPTENT3(0, "rle_compression",  OPT_FLAG, 
+    OPTENT3(0, "rle_compression",  OPT_FLAG,
             NULL,                   &rle_compression, 0);
-    OPTENT3(0, "packbits_compression", OPT_FLAG, 
+    OPTENT3(0, "packbits_compression", OPT_FLAG,
             NULL,                   &packbits_compression, 0);
-    OPTENT3(0, "verbose",          OPT_FLAG, 
+    OPTENT3(0, "verbose",          OPT_FLAG,
             NULL,                   &cmdlineP->verbose, 0);
-    OPTENT3(0, "colormap",         OPT_FLAG, 
+    OPTENT3(0, "colormap",         OPT_FLAG,
             NULL,                   &cmdlineP->colormap, 0);
-    OPTENT3(0, "offset",           OPT_FLAG, 
+    OPTENT3(0, "offset",           OPT_FLAG,
             NULL,                   &cmdlineP->offset, 0);
-    OPTENT3(0, "density",          OPT_UINT, 
+    OPTENT3(0, "density",          OPT_UINT,
             &cmdlineP->density,     &densitySpec, 0);
-    OPTENT3(0, "withdummy",        OPT_FLAG, 
+    OPTENT3(0, "withdummy",        OPT_FLAG,
             NULL,                   &cmdlineP->withdummy, 0);
 
     opt.opt_table = option_def;
@@ -105,7 +105,7 @@ parseCommandLine(int argc, const char ** argv, struct CmdlineInfo *cmdlineP) {
         /* Uses and sets argc, argv, and some of *cmdline_p and others. */
 
     if (cmdlineP->depthSpec) {
-        if (cmdlineP->depth != 1 && cmdlineP->depth != 2 
+        if (cmdlineP->depth != 1 && cmdlineP->depth != 2
             && cmdlineP->depth != 4 && cmdlineP->depth != 8
             && cmdlineP->depth != 16)
             pm_error("invalid value for -depth: %u.  Valid values are "
@@ -113,14 +113,14 @@ parseCommandLine(int argc, const char ** argv, struct CmdlineInfo *cmdlineP) {
     }
 
     if (cmdlineP->maxdepthSpec) {
-        if (cmdlineP->maxdepth != 1 && cmdlineP->maxdepth != 2 
+        if (cmdlineP->maxdepth != 1 && cmdlineP->maxdepth != 2
             && cmdlineP->maxdepth != 4 && cmdlineP->maxdepth != 8
             && cmdlineP->maxdepth != 16)
             pm_error("invalid value for -maxdepth: %u.  Valid values are "
                      "1, 2, 4, 8, and 16", cmdlineP->maxdepth);
     }
 
-    if (cmdlineP->depthSpec && cmdlineP->maxdepthSpec && 
+    if (cmdlineP->depthSpec && cmdlineP->maxdepthSpec &&
         cmdlineP->depth > cmdlineP->maxdepth)
         pm_error("-depth value (%u) is greater than -maxdepth (%u) value.",
                  cmdlineP->depth, cmdlineP->maxdepth);
@@ -135,7 +135,7 @@ parseCommandLine(int argc, const char ** argv, struct CmdlineInfo *cmdlineP) {
             cmdlineP->density != PALM_DENSITY_TRIPLE &&
             cmdlineP->density != PALM_DENSITY_QUADRUPLE)
             pm_error("Invalid value for -density: %u.  Valid values are "
-                     "%u, %u, %u, %u and %u.", cmdlineP->density, 
+                     "%u, %u, %u, %u and %u.", cmdlineP->density,
                      PALM_DENSITY_LOW, PALM_DENSITY_ONEANDAHALF,
                      PALM_DENSITY_DOUBLE, PALM_DENSITY_TRIPLE,
                      PALM_DENSITY_QUADRUPLE);
@@ -163,11 +163,11 @@ parseCommandLine(int argc, const char ** argv, struct CmdlineInfo *cmdlineP) {
         else
             cmdlineP->compression = COMP_NONE;
     }
-        
+
     if (argc-1 > 1)
         pm_error("This program takes at most 1 argument: the file name.  "
                  "You specified %u", argc-1);
-    else if (argc-1 > 0) 
+    else if (argc-1 > 0)
         cmdlineP->inputFilespec = argv[1];
     else
         cmdlineP->inputFilespec = "-";
@@ -186,16 +186,16 @@ scaleSample(pixval const arg,
 
 
 static void
-determinePalmFormatPgm(xelval               const maxval, 
+determinePalmFormatPgm(xelval               const maxval,
                        bool                 const bppSpecified,
                        unsigned int         const bpp,
                        bool                 const maxBppSpecified,
-                       unsigned int         const maxBpp, 
+                       unsigned int         const maxBpp,
                        bool                 const wantCustomColormap,
                        enum CompressionType const compression,
                        bool                 const verbose,
                        unsigned int *       const bppP) {
-        
+
     /* We can usually handle this one, but may not have enough pixels.  So
        check.
     */
@@ -241,10 +241,10 @@ validateImageAgainstStandardColormap(const Colormap * const colormapP,
         unsigned int col;
 
         for (col = 0; col < cols; ++col) {
-            ColormapEntry const searchTarget = 
+            ColormapEntry const searchTarget =
                 palmcolor_mapEntryColorFmPixel(xels[row][col], maxval, 255);
 
-            ColormapEntry * const foundEntryP = 
+            ColormapEntry * const foundEntryP =
                 (bsearch(&searchTarget,
                          colormapP->color_entries, colormapP->ncolors,
                          sizeof(ColormapEntry), palmcolor_compare_colors));
@@ -261,21 +261,21 @@ validateImageAgainstStandardColormap(const Colormap * const colormapP,
 
 
 static void
-determinePalmFormatPpm(unsigned int         const cols, 
-                       unsigned int         const rows, 
-                       xelval               const maxval, 
+determinePalmFormatPpm(unsigned int         const cols,
+                       unsigned int         const rows,
+                       xelval               const maxval,
                        xel **               const xels,
                        bool                 const bppSpecified,
                        unsigned int         const bpp,
                        bool                 const maxBppSpecified,
-                       unsigned int         const maxBpp, 
+                       unsigned int         const maxBpp,
                        bool                 const wantCustomColormap,
                        enum CompressionType const compression,
                        bool                 const verbose,
-                       unsigned int *       const bppP, 
-                       bool *               const directColorP, 
+                       unsigned int *       const bppP,
+                       bool *               const directColorP,
                        Colormap **          const colormapPP) {
-            
+
     /* We don't attempt to identify PPM files that are actually
        monochrome.  So there are two options here: either 8-bit with a
        colormap, either the standard one or a custom one, or 16-bit direct
@@ -287,7 +287,7 @@ determinePalmFormatPpm(unsigned int         const cols,
        palmcolor8.map file that comes with Netpbm to avoid this).  We try
        for colormapped first, since it works on more PalmOS devices.
     */
-    if ((bppSpecified && bpp == 16) || 
+    if ((bppSpecified && bpp == 16) ||
         (!bppSpecified && maxBppSpecified && maxBpp == 16)) {
         /* we do the 16-bit direct color */
         *directColorP = TRUE;
@@ -296,7 +296,7 @@ determinePalmFormatPpm(unsigned int         const cols,
     } else if (!wantCustomColormap) {
         /* colormapped with the standard colormap */
         Colormap * colormapP;
-            
+
         if ((bppSpecified && bpp != 8) || (maxBppSpecified && maxBpp < 8))
             pm_error("Must use depth of 8 for color Palm Bitmap without "
                      "custom color table.");
@@ -311,7 +311,7 @@ determinePalmFormatPpm(unsigned int         const cols,
             pm_message("Output is color with default colormap at 8 bpp");
     } else {
         /* colormapped with a custom colormap */
-        *colormapPP = 
+        *colormapPP =
             palmcolor_build_custom_8bit_colormap(xels, rows, cols, maxval);
         for (*bppP = 1; (1 << *bppP) < (*colormapPP)->ncolors; *bppP *= 2);
         if (bppSpecified) {
@@ -337,7 +337,7 @@ determinePalmFormatPpm(unsigned int         const cols,
         *directColorP = FALSE;
         if (verbose)
             pm_message("Output is color with custom colormap "
-                       "with %u colors at %u bpp", 
+                       "with %u colors at %u bpp",
                        (*colormapPP)->ncolors, *bppP);
     }
 }
@@ -345,20 +345,20 @@ determinePalmFormatPpm(unsigned int         const cols,
 
 
 static void
-determinePalmFormat(unsigned int         const cols, 
-                    unsigned int         const rows, 
-                    xelval               const maxval, 
-                    int                  const format, 
+determinePalmFormat(unsigned int         const cols,
+                    unsigned int         const rows,
+                    xelval               const maxval,
+                    int                  const format,
                     xel **               const xels,
                     bool                 const bppSpecified,
                     unsigned int         const bpp,
                     bool                 const maxBppSpecified,
-                    unsigned int         const maxBpp, 
+                    unsigned int         const maxBpp,
                     bool                 const wantCustomColormap,
                     enum CompressionType const compression,
                     bool                 const verbose,
-                    unsigned int *       const bppP, 
-                    bool *               const directColorP, 
+                    unsigned int *       const bppP,
+                    bool *               const directColorP,
                     Colormap **          const colormapPP) {
 /*----------------------------------------------------------------------------
    Determine what kind of Palm output file to make.
@@ -414,9 +414,9 @@ determinePalmFormat(unsigned int         const cols,
 
 
 
-static const char * 
+static const char *
 formatName(int const format) {
-    
+
     const char * retval;
 
     switch(PNM_FORMAT_TYPE(format)) {
@@ -428,22 +428,22 @@ formatName(int const format) {
     return retval;
 }
 
-        
+
 
 static void
-findTransparentColor(const char *   const colorSpec, 
+findTransparentColor(const char *   const colorSpec,
                      pixval         const newMaxval,
-                     bool           const directColor, 
-                     pixval         const maxval, 
+                     bool           const directColor,
+                     pixval         const maxval,
                      Colormap *     const colormapP,
-                     xel *          const transcolorP, 
+                     xel *          const transcolorP,
                      unsigned int * const transindexP) {
 
     *transcolorP = ppm_parsecolor(colorSpec, maxval);
     if (!directColor) {
-        ColormapEntry const searchTarget = 
+        ColormapEntry const searchTarget =
             palmcolor_mapEntryColorFmPixel(*transcolorP, maxval, newMaxval);
-        ColormapEntry * const foundEntryP = 
+        ColormapEntry * const foundEntryP =
             (bsearch(&searchTarget,
                      colormapP->color_entries, colormapP->ncolors,
                      sizeof(ColormapEntry), palmcolor_compare_colors));
@@ -530,7 +530,7 @@ writeCommonHeader(unsigned int         const cols,
 
 
 
-static unsigned char 
+static unsigned char
 compressionFieldValue(enum CompressionType const compression) {
 
     unsigned char retval;
@@ -560,7 +560,7 @@ writeRemainingHeaderLow(unsigned int         const nextDepthOffset,
                         enum CompressionType const compression,
                         unsigned int         const bpp) {
 /*----------------------------------------------------------------------------
-   Write last 6 bytes of a low density Palm Bitmap header. 
+   Write last 6 bytes of a low density Palm Bitmap header.
 -----------------------------------------------------------------------------*/
     if (nextDepthOffset > USHRT_MAX)
         pm_error("Image too large for Palm Bitmap");
@@ -572,7 +572,7 @@ writeRemainingHeaderLow(unsigned int         const nextDepthOffset,
         fputc(transindex, stdout);    /* transparent index */
     } else
         fputc(0, stdout);    /* the DirectInfoType will hold this info */
-    
+
     fputc(compressionFieldValue(compression), stdout);
 
     pm_writebigshort(stdout, 0);  /* reserved by Palm */
@@ -590,7 +590,7 @@ writeRemainingHeaderHigh(unsigned int         const bpp,
                          unsigned int         const transindex,
                          unsigned int         const nextBitmapOffset) {
 /*----------------------------------------------------------------------------
-   Write last 16 bytes of a high density Palm Bitmap header. 
+   Write last 16 bytes of a high density Palm Bitmap header.
 -----------------------------------------------------------------------------*/
     if ((nextBitmapOffset >> 31) > 1)
         pm_error("Image too large for Palm Bitmap.  nextBitmapOffset "
@@ -648,7 +648,7 @@ writeDummy() {
     pm_writebiglong(stdout, 0x00);
     fputc(0xFF, stdout);               /* pixelSize */
     fputc(0x01, stdout);               /* version */
-    pm_writebigshort(stdout, 0x00); 
+    pm_writebigshort(stdout, 0x00);
     pm_writebiglong(stdout, 0x00);
 }
 
@@ -663,7 +663,7 @@ writeColormap(bool         const explicitColormap,
               xel          const transcolor,
               xelval       const maxval,
               unsigned int const version) {
-              
+
     /* if there's a colormap, write it out */
     if (explicitColormap) {
         unsigned int row;
@@ -681,11 +681,11 @@ writeColormap(bool         const explicitColormap,
         /* write the DirectInfoType (8 bytes) */
         if (bpp == 16) {
             fputc(5, stdout);   /* # of bits of red */
-            fputc(6, stdout);   /* # of bits of green */    
+            fputc(6, stdout);   /* # of bits of green */
             fputc(5, stdout);   /* # of bits of blue */
             fputc(0, stdout);   /* reserved by Palm */
         } else
-            pm_error("Don't know how to create %u bit DirectColor bitmaps.", 
+            pm_error("Don't know how to create %u bit DirectColor bitmaps.",
                      bpp);
         if (transparent) {
             fputc(0, stdout);
@@ -714,13 +714,13 @@ computeRawRowDirectColor(const xel *     const xelrow,
   'xelrow' is the image contents of row.  It is 'cols' columns wide and
   samples are based on maxval 'maxval'.
 
-  Put the output data at 'rowdata'. 
+  Put the output data at 'rowdata'.
 -----------------------------------------------------------------------------*/
     unsigned int col;
     unsigned char * outCursor;
-    
+
     for (col = 0, outCursor = &rowdata[0]; col < cols; ++col) {
-        unsigned int const color = 
+        unsigned int const color =
             (scaleSample(PPM_GETR(xelrow[col]), maxval, 31) << 11) |
             (scaleSample(PPM_GETG(xelrow[col]), maxval, 63) <<  5) |
             (scaleSample(PPM_GETB(xelrow[col]), maxval, 31) <<  0);
@@ -782,16 +782,16 @@ computeRawRowNonDirect(const xel *     const xelrow,
                 palmcolor_mapEntryColorFmPixel(xelrow[col], maxval, 255);
             ColormapEntry * const foundEntryP =
                 bsearch(&searchTarget,
-                        colormapP->color_entries, 
+                        colormapP->color_entries,
                         colormapP->ncolors,
-                        sizeof(ColormapEntry), 
+                        sizeof(ColormapEntry),
                         palmcolor_compare_colors);
             if (!foundEntryP) {
-                pm_error("INERNAL ERROR: "
+                pm_error("INTERNAL ERROR: "
                          "Color (%u,%u,%u) not found in colormap, "
                          "though it was supposedly there before",
-                         PPM_GETR(xelrow[col]), 
-                         PPM_GETG(xelrow[col]), 
+                         PPM_GETR(xelrow[col]),
+                         PPM_GETG(xelrow[col]),
                          PPM_GETB(xelrow[col]));
             }
             color = (*foundEntryP >> 24) & 0xFF;
@@ -816,27 +816,27 @@ computeRawRowNonDirect(const xel *     const xelrow,
 }
 
 
-struct seqBuffer {
+typedef struct {
 /*----------------------------------------------------------------------------
    A buffer to which one can write bytes sequentially.
 -----------------------------------------------------------------------------*/
     char * buffer;
     unsigned int allocatedSize;
     unsigned int occupiedSize;
-};
+} SeqBuffer;
 
 
 static void
-createBuffer(struct seqBuffer ** const bufferPP) {
+seqBuffer_create(SeqBuffer ** const bufferPP) {
 
-    struct seqBuffer * bufferP;
+    SeqBuffer * bufferP;
 
     MALLOCVAR_NOFAIL(bufferP);
 
     bufferP->allocatedSize = 4096;
     MALLOCARRAY(bufferP->buffer, bufferP->allocatedSize);
     if (bufferP == NULL)
-        pm_error("Unable to allocate %u bytes of buffer", 
+        pm_error("Unable to allocate %u bytes of buffer",
                  bufferP->allocatedSize);
     bufferP->occupiedSize = 0;
 
@@ -846,7 +846,7 @@ createBuffer(struct seqBuffer ** const bufferPP) {
 
 
 static void
-destroyBuffer(struct seqBuffer * const bufferP) {
+seqBuffer_destroy(SeqBuffer * const bufferP) {
 
     free(bufferP->buffer);
     free(bufferP);
@@ -855,8 +855,8 @@ destroyBuffer(struct seqBuffer * const bufferP) {
 
 
 static void
-addByteToBuffer(struct seqBuffer * const bufferP,
-                unsigned char      const newByte) {
+seqBuffer_addByte(SeqBuffer *   const bufferP,
+                  unsigned char const newByte) {
 /*-----------------------------------------------------------------------------
   Append one byte to buffer, expanding with realloc() whenever necessary.
 
@@ -866,7 +866,6 @@ addByteToBuffer(struct seqBuffer * const bufferP,
   compression can lead to an arithmetic overflow.
   Abort with error if an arithmetic overflow is detected during doubling.
 -----------------------------------------------------------------------------*/
-
     assert(bufferP->allocatedSize >= bufferP->occupiedSize);
 
     if (bufferP->allocatedSize == bufferP->occupiedSize) {
@@ -890,19 +889,19 @@ addByteToBuffer(struct seqBuffer * const bufferP,
 
 
 static unsigned int
-bufferLength(struct seqBuffer * const bufferP) {
+seqBuffer_length(SeqBuffer * const bufferP) {
     return bufferP->occupiedSize;
 }
 
 
 
 static void
-writeOutBuffer(struct seqBuffer * const bufferP,
-               FILE *             const fileP) {
+seqBuffer_writeOut(SeqBuffer * const bufferP,
+                   FILE *      const fileP) {
 
     size_t bytesWritten;
 
-    bytesWritten = fwrite(bufferP->buffer, sizeof(char), 
+    bytesWritten = fwrite(bufferP->buffer, sizeof(char),
                           bufferP->occupiedSize, fileP);
 
     if (bytesWritten != bufferP->occupiedSize)
@@ -914,19 +913,19 @@ writeOutBuffer(struct seqBuffer * const bufferP,
 static void
 copyRowToBuffer(const unsigned char * const rowdata,
                 unsigned int          const rowbytes,
-                struct seqBuffer *    const rasterBufferP) {
+                SeqBuffer *           const rasterBufferP) {
 
     unsigned int pos;
     for (pos = 0; pos < rowbytes; ++pos)
-        addByteToBuffer(rasterBufferP, rowdata[pos]);
-} 
+        seqBuffer_addByte(rasterBufferP, rowdata[pos]);
+}
 
 
 
 static void
 scanlineCompressAndBufferRow(const unsigned char * const rowdata,
                              unsigned int          const rowbytes,
-                             struct seqBuffer *    const rasterBufferP,
+                             SeqBuffer *           const rasterBufferP,
                              const unsigned char * const lastrow) {
 /*----------------------------------------------------------------------------
    Take the raw Palm Bitmap row 'rowdata', which is 'rowbytes'
@@ -945,27 +944,27 @@ scanlineCompressAndBufferRow(const unsigned char * const rowdata,
         unsigned char map;
             /* mask indicating which of the next 8 pixels are
                different from the previous row, and therefore present
-               in the file immediately following the map byte.  
+               in the file immediately following the map byte.
             */
         unsigned char differentPixels[8];
         unsigned char *outptr;
         unsigned char outbit;
-            
+
         for (outbit = 0, map = 0x00, outptr = differentPixels;
-             outbit < limit;  
+             outbit < limit;
              ++outbit) {
-            if (!lastrow 
+            if (!lastrow
                 || (lastrow[pos + outbit] != rowdata[pos + outbit])) {
                 map |= (1 << (7 - outbit));
                 *outptr++ = rowdata[pos + outbit];
             }
         }
 
-        addByteToBuffer(rasterBufferP, map);
+        seqBuffer_addByte(rasterBufferP, map);
         {
             unsigned int j;
             for (j = 0; j < (outptr - differentPixels); ++j)
-                addByteToBuffer(rasterBufferP, differentPixels[j]);
+                seqBuffer_addByte(rasterBufferP, differentPixels[j]);
         }
     }
 }
@@ -975,7 +974,7 @@ scanlineCompressAndBufferRow(const unsigned char * const rowdata,
 static void
 rleCompressAndBufferRow(const unsigned char * const rowdata,
                         unsigned int          const rowbytes,
-                        struct seqBuffer *    const rasterBufferP) {
+                        SeqBuffer *           const rasterBufferP) {
 /*----------------------------------------------------------------------------
    Take the raw Palm Bitmap row 'rowdata', which is 'rowbytes' bytes,
    and add the rle-compressed representation of it to the buffer with
@@ -984,19 +983,19 @@ rleCompressAndBufferRow(const unsigned char * const rowdata,
     unsigned int pos;
 
     /* we output a count of the number of bytes a value is
-       repeated, followed by that byte value 
+       repeated, followed by that byte value
     */
     pos = 0;
     while (pos < rowbytes) {
         unsigned int repeatcount;
-        for (repeatcount = 1;  
-             repeatcount < (rowbytes - pos) && repeatcount  < 255;  
-             ++repeatcount) 
+        for (repeatcount = 1;
+             repeatcount < (rowbytes - pos) && repeatcount  < 255;
+             ++repeatcount)
             if (rowdata[pos + repeatcount] != rowdata[pos])
                 break;
 
-        addByteToBuffer(rasterBufferP, repeatcount);
-        addByteToBuffer(rasterBufferP, rowdata[pos]);
+        seqBuffer_addByte(rasterBufferP, repeatcount);
+        seqBuffer_addByte(rasterBufferP, rowdata[pos]);
         pos += repeatcount;
     }
 }
@@ -1006,10 +1005,10 @@ rleCompressAndBufferRow(const unsigned char * const rowdata,
 static void
 packbitsCompressAndBufferRow(const unsigned char * const rowdata,
                              unsigned int          const rowbytes,
-                             struct seqBuffer *    const rasterBufferP) {
+                             SeqBuffer *           const rasterBufferP) {
 /*----------------------------------------------------------------------------
    Take the raw Palm Bitmap row 'rowdata', which is 'rowbytes' bytes, and
-   add the packbits-compressed representation of it to the buffer 
+   add the packbits-compressed representation of it to the buffer
    with handle 'rasterBufferP'.
 -----------------------------------------------------------------------------*/
     unsigned char * compressedData;
@@ -1021,7 +1020,7 @@ packbitsCompressAndBufferRow(const unsigned char * const rowdata,
                           rowbytes, &compressedDataCt);
 
     for (byteCt = 0; byteCt < compressedDataCt; ++byteCt)
-        addByteToBuffer(rasterBufferP, compressedData[byteCt]);
+        seqBuffer_addByte(rasterBufferP, compressedData[byteCt]);
 
     free(compressedData);
 }
@@ -1033,7 +1032,7 @@ bufferRowFromRawRowdata(const unsigned char *  const rowdata,
                         unsigned int           const rowbytes,
                         enum CompressionType   const compression,
                         const unsigned char *  const lastrow,
-                        struct seqBuffer *     const rasterBufferP) {
+                        SeqBuffer *            const rasterBufferP) {
 /*----------------------------------------------------------------------------
    Starting with a raw (uncompressed) Palm raster line, do the
    compression identified by 'compression' and add the compressed row
@@ -1049,7 +1048,7 @@ bufferRowFromRawRowdata(const unsigned char *  const rowdata,
         copyRowToBuffer(rowdata, rowbytes, rasterBufferP);
         break;
     case COMP_SCANLINE:
-        scanlineCompressAndBufferRow(rowdata, rowbytes, rasterBufferP, 
+        scanlineCompressAndBufferRow(rowdata, rowbytes, rasterBufferP,
                                      lastrow);
         break;
     case COMP_RLE:
@@ -1075,10 +1074,10 @@ bufferRow(const xel *          const xelrow,
           Colormap *           const colormapP,
           unsigned char *      const rowdata,
           unsigned char *      const lastrow,
-          struct seqBuffer *   const rasterBufferP) {
+          SeqBuffer *          const rasterBufferP) {
 /*----------------------------------------------------------------------------
    Add a row of the Palm Bitmap raster to buffer 'rasterBufferP'.
-   
+
    'xelrow' is the image contents of row.  It is 'cols' columns wide and
    samples are based on maxval 'maxval'.
 
@@ -1091,7 +1090,7 @@ bufferRow(const xel *          const xelrow,
 -----------------------------------------------------------------------------*/
     if (directColor)
         computeRawRowDirectColor(xelrow, cols, maxval, rowdata);
-    else 
+    else
         computeRawRowNonDirect(xelrow, cols, maxval, bpp, colormapP, newMaxval,
                                rowdata);
 
@@ -1101,7 +1100,7 @@ bufferRow(const xel *          const xelrow,
 
 
 
-static void 
+static void
 bufferRaster(xel **               const xels,
              unsigned int         const cols,
              unsigned int         const rows,
@@ -1112,14 +1111,14 @@ bufferRaster(xel **               const xels,
              enum CompressionType const compression,
              bool                 const directColor,
              Colormap *           const colormapP,
-             struct seqBuffer **  const rasterBufferPP) {
-    
+             SeqBuffer **         const rasterBufferPP) {
+
     unsigned char * rowdata;
     unsigned char * lastrow;
     unsigned int row;
 
-    createBuffer(rasterBufferPP);
-    
+    seqBuffer_create(rasterBufferPP);
+
     MALLOCARRAY_NOFAIL(rowdata, rowbytes);
     if (compression == COMP_SCANLINE)
         MALLOCARRAY_NOFAIL(lastrow, rowbytes);
@@ -1157,25 +1156,25 @@ computeOffsetStuff(bool                 const offsetWanted,
                    unsigned int *       const nextDepthOffsetP,
                    unsigned int *       const nextBitmapOffsetP,
                    unsigned int *       const padBytesRequiredP) {
-    
+
     if (offsetWanted) {
         /* Offset is measured in 4-byte words (double words in
            Intel/Microsoft terminology).  Account for header,
-           colormap, and raster size and round up 
+           colormap, and raster size and round up
         */
         unsigned int const headerSize = ((version < 3) ? 16 : 24);
         unsigned int const colormapSize =
             (colormapped ? (2 + colormapColorCount * 4) : 0);
         if (version < 3) {
-            unsigned int const directSize = 
-                (directColor && version < 3) ? 8 : 0; 
+            unsigned int const directSize =
+                (directColor && version < 3) ? 8 : 0;
             if (compression != COMP_NONE && sizePlusRasterSize > USHRT_MAX)
                 pm_error("Oversized compressed bitmap: %u bytes",
                          sizePlusRasterSize);
-            *padBytesRequiredP = 4 - (sizePlusRasterSize + headerSize + 
+            *padBytesRequiredP = 4 - (sizePlusRasterSize + headerSize +
                                       directSize + colormapSize) % 4;
-            *nextDepthOffsetP = 
-                (sizePlusRasterSize + headerSize + 
+            *nextDepthOffsetP =
+                (sizePlusRasterSize + headerSize +
                  directSize + colormapSize + *padBytesRequiredP) / 4;
         } else {
             if (compression != COMP_NONE && (sizePlusRasterSize >> 31) > 1)
@@ -1184,7 +1183,7 @@ computeOffsetStuff(bool                 const offsetWanted,
             /* Does version 3 need padding? Probably won't hurt */
             *padBytesRequiredP = 4 - (sizePlusRasterSize + headerSize +
                                       colormapSize) % 4;
-            *nextBitmapOffsetP = sizePlusRasterSize + headerSize + 
+            *nextBitmapOffsetP = sizePlusRasterSize + headerSize +
                 colormapSize + *padBytesRequiredP;
         }
     } else {
@@ -1204,7 +1203,7 @@ writeRasterSize(unsigned int const sizePlusRasterSize,
    Write to file 'fileP' a raster size field for a Palm Bitmap version
    'version' header, indicating 'sizePlusRasterSize' bytes.
 -----------------------------------------------------------------------------*/
-    if (version < 3) 
+    if (version < 3)
         pm_writebigshort(fileP, sizePlusRasterSize);
     else
         pm_writebiglong(fileP, sizePlusRasterSize);
@@ -1231,37 +1230,37 @@ writeBitmap(xel **               const xels,
             unsigned int         const version,
             unsigned int         const density,
             bool                 const withdummy) {
-    
+
     unsigned int sizePlusRasterSize;
     unsigned int nextDepthOffset;
     unsigned int nextBitmapOffset;
         /* Offset from the beginning of the image we write to the beginning
            of the next one, assuming user writes another one following this
            one.
-           nextDepthOffset is used in encodings 1, 2 and is in 4 byte words 
-           nextBitmapOffset is used in encoding 3, is in 4 bytes 
+           nextDepthOffset is used in encodings 1, 2 and is in 4 byte words
+           nextBitmapOffset is used in encoding 3, is in 4 bytes
         */
     unsigned int padBytesRequired;
         /* Number of bytes of padding we need to put after the image in
            order to align properly for User to add the next image to the
            stream.
         */
-    struct seqBuffer * rasterBufferP;
+    SeqBuffer * rasterBufferP;
 
-    writeCommonHeader(cols, rows, rowbytes, compression, colormapped, 
+    writeCommonHeader(cols, rows, rowbytes, compression, colormapped,
                       transparent, directColor, bpp, version);
-    
+
     bufferRaster(xels, cols, rows, maxval, rowbytes, bpp, newMaxval,
                  compression, directColor, colormapP, &rasterBufferP);
 
     /* rasterSize itself takes 2 or 4 bytes */
     if (version < 3)
-        sizePlusRasterSize = 2 + bufferLength(rasterBufferP);
+        sizePlusRasterSize = 2 + seqBuffer_length(rasterBufferP);
     else
-        sizePlusRasterSize = 4 + bufferLength(rasterBufferP);
-    
+        sizePlusRasterSize = 4 + seqBuffer_length(rasterBufferP);
+
     computeOffsetStuff(offsetWanted, version, directColor, compression,
-                       colormapped, colormapped ? colormapP->ncolors : 0, 
+                       colormapped, colormapped ? colormapP->ncolors : 0,
                        sizePlusRasterSize,
                        &nextDepthOffset, &nextBitmapOffset,
                        &padBytesRequired);
@@ -1273,15 +1272,15 @@ writeBitmap(xel **               const xels,
                                  maxval, transparent, transcolor,
                                  transindex, nextBitmapOffset);
 
-    writeColormap(colormapped, colormapP, directColor, bpp, 
+    writeColormap(colormapped, colormapP, directColor, bpp,
                   transparent, transcolor, maxval, version);
 
     if (compression != COMP_NONE)
         writeRasterSize(sizePlusRasterSize, version, stdout);
 
-    writeOutBuffer(rasterBufferP, stdout);
+    seqBuffer_writeOut(rasterBufferP, stdout);
 
-    destroyBuffer(rasterBufferP);
+    seqBuffer_destroy(rasterBufferP);
 
     {
         unsigned int i;
@@ -1291,11 +1290,11 @@ writeBitmap(xel **               const xels,
 
     if (withdummy)
         writeDummy();
-}        
+}
 
 
 
-int 
+int
 main( int argc, const char **argv ) {
     struct CmdlineInfo cmdline;
     unsigned int version;
@@ -1311,7 +1310,7 @@ main( int argc, const char **argv ) {
     bool directColor;
     unsigned int newMaxval;
     Colormap * colormapP;
-    
+
     pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
@@ -1322,9 +1321,9 @@ main( int argc, const char **argv ) {
     pm_close(ifP);
 
     if (cmdline.verbose)
-        pm_message("Input is %ux%u %s, maxval %u", 
+        pm_message("Input is %ux%u %s, maxval %u",
                    cols, rows, formatName(format), maxval);
-    
+
     determinePalmFormat(cols, rows, maxval, format, xels,
                         cmdline.depthSpec, cmdline.depth,
                         cmdline.maxdepthSpec, cmdline.maxdepth,
@@ -1333,23 +1332,23 @@ main( int argc, const char **argv ) {
 
     newMaxval = (1 << bpp) - 1;
 
-    if (cmdline.transparent) 
+    if (cmdline.transparent)
         findTransparentColor(cmdline.transparent, newMaxval, directColor,
                              maxval, colormapP, &transcolor, &transindex);
-    else 
+    else
         transindex = 0;
 
-    rowbytes = ((cols + (16 / bpp -1)) / (16 / bpp)) * 2;    
+    rowbytes = ((cols + (16 / bpp -1)) / (16 / bpp)) * 2;
         /* bytes per row - always a word boundary */
 
-    version = bitmapVersion(bpp, cmdline.colormap, !!cmdline.transparent, 
+    version = bitmapVersion(bpp, cmdline.colormap, !!cmdline.transparent,
                             cmdline.compression, cmdline.density);
 
     writeBitmap(xels, cols, rows, maxval,
                 rowbytes, bpp, newMaxval, cmdline.compression,
-                !!cmdline.transparent, directColor, cmdline.offset, 
+                !!cmdline.transparent, directColor, cmdline.offset,
                 cmdline.colormap, colormapP, transindex, transcolor,
                 version, cmdline.density, cmdline.withdummy);
-    
+
     return 0;
 }
diff --git a/converter/other/pnmtopng.c b/converter/other/pnmtopng.c
index cbbbc47d..2230d226 100644
--- a/converter/other/pnmtopng.c
+++ b/converter/other/pnmtopng.c
@@ -56,6 +56,7 @@
 #endif                               /*  2 for warnings (1 == error) */
 
 #include <assert.h>
+#include <stdbool.h>
 #include <string.h> /* strcat() */
 #include <limits.h>
 #include <png.h>
@@ -140,12 +141,6 @@ typedef struct _jmpbuf_wrapper {
   jmp_buf jmpbuf;
 } jmpbuf_wrapper;
 
-#ifndef TRUE
-#  define TRUE 1
-#endif
-#ifndef FALSE
-#  define FALSE 0
-#endif
 #ifndef NONE
 #  define NONE 0
 #endif
@@ -394,8 +389,8 @@ parseCommandLine(int argc, const char ** argv,
 
 
     opt.opt_table = option_def;
-    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
-    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
+    opt.short_allowed = false;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = false;  /* We have no parms that are negative numbers */
 
     pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
@@ -424,7 +419,7 @@ parseCommandLine(int argc, const char ** argv,
         cmdlineP->palette = NULL;
 
     if (filterSpec && (nofilter + sub + up + avg + paeth > 0))
-        pm_error("You may mot specify -filter with "
+        pm_error("You may not specify -filter with "
                  "-nofilter, -sub, -up, -avg, or -paeth");
 
     if (filterSpec) {
@@ -511,6 +506,8 @@ parseCommandLine(int argc, const char ** argv,
         cmdlineP->inputFileName = argv[1];
     else
         pm_error("Program takes at most one argument:  input file name");
+
+    free(option_def);
 }
 
 
@@ -671,7 +668,7 @@ lookupColorAlpha(coloralphahash_table const caht,
 
 
 /* The following variables belong to getChv() and freeChv() */
-static bool getChv_computed = FALSE;
+static bool getChv_computed = false;
 static colorhist_vector getChv_chv;
 
 
@@ -722,7 +719,7 @@ getChv(FILE *             const ifP,
             else
                 pm_message("Too many colors (more than %u) found", maxColors);
         }
-        getChv_computed = TRUE;
+        getChv_computed = true;
     }
     *chvP = getChv_chv;
     *colorsP = getChv_colors;
@@ -736,7 +733,7 @@ static void freeChv(void) {
         if (getChv_chv)
             ppm_freecolorhist(getChv_chv);
 
-    getChv_computed = FALSE;
+    getChv_computed = false;
 }
 
 
@@ -750,7 +747,7 @@ pgmBitsAreRepeated(unsigned int const repeatedSize,
                    xelval       const maxval,
                    int          const format) {
 /*----------------------------------------------------------------------------
-   Return TRUE iff all the samples in the image in file 'ifP',
+   Return true iff all the samples in the image in file 'ifP',
    described by 'cols', 'rows', 'maxval', and 'format', consist in the
    rightmost 'repeatedSize' * 2 bits of two identical sets of
    'repeatedSize' bits.
@@ -774,7 +771,7 @@ pgmBitsAreRepeated(unsigned int const repeatedSize,
 
     pm_seek2(ifP, &rasterPos, sizeof(rasterPos));
 
-    mayscale = TRUE;  /* initial assumption */
+    mayscale = true;  /* initial assumption */
 
     for (row = 0; row < rows && mayscale; ++row) {
         unsigned int col;
@@ -785,7 +782,7 @@ pgmBitsAreRepeated(unsigned int const repeatedSize,
             xelval const testbits1 = testbits2 & mask1;
                 /* The lower half of the bits of interest in the sample */
             if (((testbits1 << repeatedSize) | testbits1) != testbits2)
-                mayscale = FALSE;
+                mayscale = false;
         }
     }
     pnm_freerow(xelrow);
@@ -878,7 +875,7 @@ meaningful_bits_ppm(FILE *         const ifp,
     maxMeaningfulBits = pm_maxvaltobits(maxval);
 
     if (maxval == 65535) {
-        mayscale = TRUE;   /* initial assumption */
+        mayscale = true;   /* initial assumption */
         pm_seek2(ifp, &rasterPos, sizeof(rasterPos));
         for (row = 0; row < rows && mayscale; ++row) {
             unsigned int col;
@@ -888,7 +885,7 @@ meaningful_bits_ppm(FILE *         const ifp,
                 if ((PPM_GETR(p) & 0xff) * 0x101 != PPM_GETR(p) ||
                     (PPM_GETG(p) & 0xff) * 0x101 != PPM_GETG(p) ||
                     (PPM_GETB(p) & 0xff) * 0x101 != PPM_GETB(p))
-                    mayscale = FALSE;
+                    mayscale = false;
             }
         }
         if (mayscale)
@@ -902,7 +899,7 @@ meaningful_bits_ppm(FILE *         const ifp,
 
 
 static void
-tryTransparentColor(FILE *     const ifp,
+tryTransparentColor(FILE *     const ifP,
                     pm_filepos const rasterPos,
                     int        const cols,
                     int        const rows,
@@ -912,7 +909,14 @@ tryTransparentColor(FILE *     const ifp,
                     gray       const alphaMaxval,
                     pixel      const transcolor,
                     bool *     const singleColorIsTransP) {
+/*----------------------------------------------------------------------------
+   Find out if the transparent pixels identified by alpha mask 'alphaMask'
+   (whose maxval is 'alphaMaxval') are exactly the pixels of color
+   'transcolor'.  Return answer as *singleColorIsTransP.
 
+   The image we analyze is that on input stream *ifP, starting at position
+   'rasterPos', and we leave that stream positioned arbitrarily.
+-----------------------------------------------------------------------------*/
     int const pnmType = PNM_FORMAT_TYPE(format);
 
     xel * xelrow;
@@ -922,13 +926,13 @@ tryTransparentColor(FILE *     const ifp,
 
     xelrow = pnm_allocrow(cols);
 
-    pm_seek2(ifp, &rasterPos, sizeof(rasterPos));
+    pm_seek2(ifP, &rasterPos, sizeof(rasterPos));
 
-    singleColorIsTrans = TRUE;  /* initial assumption */
+    singleColorIsTrans = true;  /* initial assumption */
 
     for (row = 0; row < rows && singleColorIsTrans; ++row) {
         int col;
-        pnm_readpnmrow(ifp, xelrow, cols, maxval, format);
+        pnm_readpnmrow(ifP, xelrow, cols, maxval, format);
         for (col = 0 ; col < cols && singleColorIsTrans; ++col) {
             if (alphaMask[row][col] == 0) { /* transparent */
                 /* If we have a second transparent color, we're
@@ -936,16 +940,16 @@ tryTransparentColor(FILE *     const ifp,
                 */
                 if (pnmType == PPM_TYPE) {
                     if (!PPM_EQUAL(xelrow[col], transcolor))
-                        singleColorIsTrans = FALSE;
+                        singleColorIsTrans = false;
                 } else {
                     if (PNM_GET1(xelrow[col]) != PNM_GET1(transcolor))
-                        singleColorIsTrans = FALSE;
+                        singleColorIsTrans = false;
                 }
             } else if (alphaMask[row][col] != alphaMaxval) {
                 /* Here's an area of the mask that is translucent.  That
                    disqualified us.
                 */
-                singleColorIsTrans = FALSE;
+                singleColorIsTrans = false;
             } else {
                 /* Here's an area of the mask that is opaque.  If it's
                    the same color as our candidate transparent color,
@@ -953,10 +957,10 @@ tryTransparentColor(FILE *     const ifp,
                 */
                 if (pnmType == PPM_TYPE) {
                     if (PPM_EQUAL(xelrow[col], transcolor))
-                        singleColorIsTrans = FALSE;
+                        singleColorIsTrans = false;
                 } else {
                     if (PNM_GET1(xelrow[col]) == PNM_GET1(transcolor))
-                        singleColorIsTrans = FALSE;
+                        singleColorIsTrans = false;
                 }
             }
         }
@@ -990,8 +994,8 @@ analyzeAlpha(FILE *       const ifP,
   of a certain color fully transparent and every other pixel opaque,
   we can simply identify that color in the PNG.
 
-  We have to do this before any scaling occurs, since alpha is only
-  possible with 8 and 16-bit.
+  We have to do this before any scaling occurs, since alpha is possible
+  only with 8 and 16-bit.
 -----------------------------------------------------------------------------*/
     xel * xelrow;
     bool foundTransparentPixel;
@@ -1034,7 +1038,7 @@ analyzeAlpha(FILE *       const ifP,
             pnm_readpnmrow(ifP, xelrow, cols, maxval, format);
             for (col = 0; col < cols && !foundTransparentPixel; ++col) {
                 if (alphaMask[row][col] == 0) {
-                    foundTransparentPixel = TRUE;
+                    foundTransparentPixel = true;
                     transcolor = pnm_xeltopixel(xelrow[col], format);
                 }
             }
@@ -1115,16 +1119,16 @@ determineTransparency(struct cmdlineInfo const cmdline,
         if (alphaCanBeTransparencyIndex && !cmdline.force) {
             if (verbose)
                 pm_message("converting alpha mask to transparency index");
-            *alphaP       = FALSE;
+            *alphaP       = false;
             *transparentP = 2;
             *transColorP  = alphaTranscolor;
         } else if (allOpaque) {
             if (verbose)
                 pm_message("Skipping alpha because mask is all opaque");
-            *alphaP       = FALSE;
+            *alphaP       = false;
             *transparentP = -1;
         } else {
-            *alphaP       = TRUE;
+            *alphaP       = true;
             *transparentP = -1;
         }
         *alphaMaxvalP = alphaMaxval;
@@ -1134,17 +1138,17 @@ determineTransparency(struct cmdlineInfo const cmdline,
            use with trans[], which can have stuff in it if the user specified
            a transparent color.
         */
-        *alphaP       = FALSE;
+        *alphaP       = false;
         *alphaMaxvalP = 255;
 
         if (cmdline.transparent) {
             const char * transstring2;
             /* The -transparent value, but with possible leading '=' removed */
             if (cmdline.transparent[0] == '=') {
-                *transExactP = TRUE;
+                *transExactP = true;
                 transstring2 = &cmdline.transparent[1];
             } else {
-                *transExactP = FALSE;
+                *transExactP = false;
                 transstring2 = cmdline.transparent;
             }
             /* We do this funny PPM_DEPTH thing instead of just passing 'maxval'
@@ -1206,7 +1210,7 @@ hasColor(FILE *       const ifP,
             for (col = 0; col < cols && isGray; ++col) {
                     xel const p = xelrow[col];
                 if (PPM_GETR(p) != PPM_GETG(p) || PPM_GETG(p) != PPM_GETB(p))
-                    isGray = FALSE;
+                    isGray = false;
             }
         }
 
@@ -1335,10 +1339,10 @@ compute_nonalpha_palette(colorhist_vector const chv,
             int j;
             bool found;
 
-            found = FALSE;
+            found = false;
             for (j = 0; j < ordered_palette_size && !found; ++j) {
                 if (PNM_EQUAL(ordered_palette[j], chv[colorIndex].color))
-                    found = TRUE;
+                    found = true;
             }
             if (!found)
                 pm_error("failed to find color (%d, %d, %d), which is in the "
@@ -1636,7 +1640,7 @@ compute_alpha_palette(FILE *         const ifP,
    MAXPALETTEENTRIES elements.
 
    If there are more than MAXPALETTEENTRIES color/alpha pairs in the image,
-   don't return any palette information -- just return *tooBigP == TRUE.
+   don't return any palette information -- just return *tooBigP == true.
 -----------------------------------------------------------------------------*/
     colorhist_vector chv;
     unsigned int colors;
@@ -1714,9 +1718,9 @@ makeOneColorTransparentInPalette(xel            const transColor,
    can do a better job when the opaque entries are all last in the
    color/alpha palette).
 
-   If the specified color is not there and exact == TRUE, return
+   If the specified color is not there and exact == true, return
    without changing anything, but issue a warning message.  If it's
-   not there and exact == FALSE, just find the closest color.
+   not there and exact == false, just find the closest color.
 
    We assume every entry in the palette is opaque upon entry.
 
@@ -2369,7 +2373,8 @@ writeRaster(struct pngx *        const pngxP,
     /* max: 3 color channels, one alpha channel, 16-bit */
     MALLOCARRAY(line, cols * 8);
     if (line == NULL)
-        pm_error("out of memory allocating PNG row buffer");
+        pm_error("out of memory allocating PNG row buffer for %u columns",
+                 cols);
 
     for (pass = 0; pass < pngxP->numPassesRequired; ++pass) {
         unsigned int row;
@@ -2386,6 +2391,7 @@ writeRaster(struct pngx *        const pngxP,
             pngx_writeRow(pngxP, line);
         }
     }
+    free(line);
     pnm_freerow(xelrow);
 }
 
@@ -2837,9 +2843,9 @@ convertpnm(struct cmdlineInfo const cmdline,
         if (verbose)
             pm_message("Not using color map.  %s", noColormapReason);
         pm_strfree(noColormapReason);
-        colorMapped = FALSE;
+        colorMapped = false;
     } else
-        colorMapped = TRUE;
+        colorMapped = true;
 
     computeColorMapLookupTable(colorMapped, palettePnm, paletteSize,
                                transPnm, transSize, alpha, alphaMaxval,
diff --git a/converter/other/pnmtops.c b/converter/other/pnmtops.c
index a286bc1e..3ca158b5 100644
--- a/converter/other/pnmtops.c
+++ b/converter/other/pnmtops.c
@@ -9,7 +9,7 @@
 
          We use methods we learned from Dirk Krause's program Bmeps.
          Previous versions used raster encoding code based on Bmeps
-         code.  This program does not used any code from Bmeps.
+         code.  This program does not use any code from Bmeps.
 
       2) Use our own filters and redefine /readstring .  This is aboriginal
          Netpbm code, from when Postscript was young.  The filters are
@@ -125,8 +125,8 @@ static bool verbose;
 
 
 static void
-parseDpi(const char *   const dpiOpt, 
-         unsigned int * const dpiXP, 
+parseDpi(const char *   const dpiOpt,
+         unsigned int * const dpiXP,
          unsigned int * const dpiYP) {
 
     char *dpistr2;
@@ -253,9 +253,9 @@ parseCommandLine(int argc, const char ** argv,
     OPTENT3(0, "showpage",    OPT_FLAG,  NULL, &showpage,                0);
     OPTENT3(0, "verbose",     OPT_FLAG,  NULL, &cmdlineP->verbose,       0);
     OPTENT3(0, "debug",       OPT_FLAG,  NULL, &cmdlineP->debug,         0);
-    OPTENT3(0, "level",       OPT_UINT, &cmdlineP->level, 
+    OPTENT3(0, "level",       OPT_UINT, &cmdlineP->level,
             &cmdlineP->levelSpec,              0);
-    
+
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;
     opt.allowNegNum = FALSE;
@@ -293,7 +293,7 @@ parseCommandLine(int argc, const char ** argv,
 
     validateCompDimension(width, 72, "-width value");
     validateCompDimension(height, 72, "-height value");
-    
+
     cmdlineP->width  = width * 72;
     cmdlineP->height = height * 72;
 
@@ -318,7 +318,7 @@ parseCommandLine(int argc, const char ** argv,
     if (cmdlineP->bitspersampleSpec)
         validateBps_1_2_4_8_12(cmdlineP->bitspersample);
 
-    if (argc-1 == 0) 
+    if (argc-1 == 0)
         cmdlineP->inputFileName = "-";
     else if (argc-1 != 1)
         pm_error("Program takes zero or one argument (filename).  You "
@@ -326,7 +326,7 @@ parseCommandLine(int argc, const char ** argv,
     else
         cmdlineP->inputFileName = argv[1];
 
-    free(option_def); 
+    free(option_def);
 }
 
 
@@ -432,7 +432,7 @@ addToPidList(pid_t * const pidList,
 /*===========================================================================
   The output encoder
   ===========================================================================*/
-    
+
 enum OutputType {AsciiHex, Ascii85};
 
 typedef struct {
@@ -453,7 +453,7 @@ bytesPerRow (unsigned int const cols,
 -----------------------------------------------------------------------------*/
     unsigned int retval;
 
-    assert(bitsPerSample==1 || bitsPerSample==2 || bitsPerSample==4 || 
+    assert(bitsPerSample==1 || bitsPerSample==2 || bitsPerSample==4 ||
            bitsPerSample==8 || bitsPerSample==12);
 
     switch (bitsPerSample) {
@@ -519,7 +519,7 @@ typedef void FilterFn(FILE *          const ifP,
     /* This is a function that can be run in a separate process to do
        arbitrary modifications of the raster data stream.
     */
-       
+
 
 
 #ifndef NOFLATE
@@ -545,7 +545,7 @@ initZlib(z_stream * const strmP) {
 
 static FilterFn flateFilter;
 
-static void 
+static void
 flateFilter(FILE *          const ifP,
             FILE *          const ofP,
             OutputEncoder * const oeP) {
@@ -600,12 +600,12 @@ flateFilter(FILE *          const ifP,
     } while (flush != Z_FINISH);
 
     free(in);
-    free(out); 
+    free(out);
     deflateEnd(&strm);
     fclose(ifP);
     fclose(ofP);
 #else
-    assert(false);    /* filter is never used */ 
+    assert(false);    /* filter is never used */
 #endif
 }
 
@@ -687,7 +687,7 @@ asciiHexFilter(FILE *          const ifP,
             unsigned int i;
 
             for (i = 0; i < readCt; ++i) {
-                int const item = inbuff[i]; 
+                int const item = inbuff[i];
                 outbuff[i*2]   = hexits[item >> 4];
                 outbuff[i*2+1] = hexits[item & 15];
             }
@@ -736,7 +736,7 @@ ascii85Filter(FILE *          const ifP,
                 ++outcount;
                 count = 0;
             } else if (count == 4) {
-                outbuff[4] = value % 85 + 33;  value/=85; 
+                outbuff[4] = value % 85 + 33;  value/=85;
                 outbuff[3] = value % 85 + 33;  value/=85;
                 outbuff[2] = value % 85 + 33;  value/=85;
                 outbuff[1] = value % 85 + 33;
@@ -745,7 +745,7 @@ ascii85Filter(FILE *          const ifP,
                 writeFileChar(outbuff, count + 1, "ASCII 85 filter", ofP);
 
                 count = value = 0;
-                outcount += 5; 
+                outcount += 5;
             }
 
             if (outcount > 75) {
@@ -794,9 +794,9 @@ closeAllBut(int const saveFd0,
    'saveFd1', and 'saveFd2'.
 
    This is helpful because even if this process doesn't touch other file
-   desriptors, its very existence will keep the files open.
+   descriptors, its very existence will keep the files open.
 -----------------------------------------------------------------------------*/
-    
+
     /* Unix provides no good way to do this; we just assume file descriptors
        above 9 are not used in this program; Caller must ensure that is true.
     */
@@ -829,15 +829,15 @@ spawnFilter(FILE *          const ofP,
     pid_t rc;
 
     makePipe(pipeFd);
-    
+
     rc = fork();
 
     if (rc == (pid_t)-1)
-        pm_error("fork() of filter process failed.  errno=%d (%s)", 
+        pm_error("fork() of filter process failed.  errno=%d (%s)",
                  errno, strerror(errno));
     else if (rc == 0) {
         /* This is the child process */
- 
+
         FILE * ifP;
 
         ifP = fdopen(pipeFd[0], "r");
@@ -892,11 +892,11 @@ addFilter(const char *    const description,
     pid_t pid;
 
     spawnFilter(oldFeedFileP, filter, oeP, &newFeedFileP, &pid);
-            
+
     if (verbose)
         pm_message("%s filter spawned: pid %u",
                    description, (unsigned)pid);
-    
+
     if (debug) {
         int const outFd    = fileno(oldFeedFileP);
         int const supplyFd = fileno(newFeedFileP);
@@ -971,7 +971,7 @@ waitForChildren(const pid_t * const pidList) {
        signal is the default), the process' children do not become
        zombies.  Consequently, waitpid() always fails with ECHILD - but
        nonetheless waits for the child to exit.
-    
+
        We expect the process not to have the action for SIGCHLD set that
        way.
     */
@@ -1004,9 +1004,9 @@ waitForChildren(const pid_t * const pidList) {
 
 
 static void
-validateComputableBoundingBox(float const scols, 
+validateComputableBoundingBox(float const scols,
                               float const srows,
-                              float const llx, 
+                              float const llx,
                               float const lly) {
 
     float const bbWidth  = llx + scols + 0.5;
@@ -1036,22 +1036,22 @@ warnUserRescaling(float const scale) {
 
 
 static void
-computeImagePosition(int     const dpiX, 
-                     int     const dpiY, 
-                     int     const icols, 
+computeImagePosition(int     const dpiX,
+                     int     const dpiY,
+                     int     const icols,
                      int     const irows,
                      bool    const mustturn,
                      bool    const canturn,
                      bool    const center,
-                     int     const pagewid, 
-                     int     const pagehgt, 
+                     int     const pagewid,
+                     int     const pagehgt,
                      float   const requestedScale,
                      float   const imagewidth,
                      float   const imageheight,
                      bool    const equalpixels,
                      float * const scolsP,
                      float * const srowsP,
-                     float * const llxP, 
+                     float * const llxP,
                      float * const llyP,
                      bool *  const turnedP ) {
 /*----------------------------------------------------------------------------
@@ -1091,7 +1091,7 @@ computeImagePosition(int     const dpiX,
        rotated if applicable
     */
     bool shouldturn;  /* The image fits the page better if we turn it */
-    
+
     if (icols > irows && pagehgt > pagewid)
         shouldturn = TRUE;
     else if (irows > icols && pagewid > pagehgt)
@@ -1120,27 +1120,27 @@ computeImagePosition(int     const dpiX,
             scale = (float) imagewidth/cols;
         else
             scale = MIN((float)imagewidth/cols, (float)imageheight/rows);
-    
+
         *scolsP = cols*scale;
         *srowsP = rows*scale;
     } else {
         /* He didn't give us a bounding box for the image so figure
            out output image size from other inputs.
         */
-        const int devpixX = dpiX / 72.0 + 0.5;        
-        const int devpixY = dpiY / 72.0 + 0.5;        
+        const int devpixX = dpiX / 72.0 + 0.5;
+        const int devpixY = dpiY / 72.0 + 0.5;
         /* How many device pixels make up 1/72 inch, rounded to
            nearest integer */
         const float pixfacX = 72.0 / dpiX * devpixX;  /* 1, approx. */
         const float pixfacY = 72.0 / dpiY * devpixY;  /* 1, approx. */
         float scale;
 
-        scale = MIN(requestedScale, 
+        scale = MIN(requestedScale,
                     MIN((float)pagewid/cols, (float)pagehgt/rows));
 
         *scolsP = scale * cols * pixfacX;
         *srowsP = scale * rows * pixfacY;
-    
+
         if (scale != requestedScale)
             warnUserRescaling(scale);
 
@@ -1236,7 +1236,7 @@ defineReadstring(bool const rle) {
 static void
 setupReadstringNative(bool         const rle,
                       bool         const color,
-                      unsigned int const icols, 
+                      unsigned int const icols,
                       unsigned int const bitsPerSample) {
 /*----------------------------------------------------------------------------
   Write to Standard Output statements to define /readstring and also
@@ -1247,7 +1247,7 @@ setupReadstringNative(bool         const rle,
         /* Size of row buffer, padded up to byte boundary. */
 
     defineReadstring(rle);
-    
+
     if (color) {
         printf("/rpicstr %d string def\n", bytesPerRow);
         printf("/gpicstr %d string def\n", bytesPerRow);
@@ -1266,18 +1266,18 @@ putFilters(unsigned int const postscriptLevel,
            bool         const color) {
 
     assert(postscriptLevel > 1);
-    
+
     /* We say to decode flate, then rle, so Caller must ensure it encodes
-       rel, then flate.
+       rle, then flate.
     */
 
     if (ascii85)
         printf("/ASCII85Decode filter ");
-    else 
+    else
         printf("/ASCIIHexDecode filter ");
     if (flate)
         printf("/FlateDecode filter ");
-    if (rle) 
+    if (rle)
         printf("/RunLengthDecode filter ");
 }
 
@@ -1311,7 +1311,7 @@ putSetup(unsigned int const dictSize,
     if (dictSize > 0)
         /* inputf {r,g,b,}pictsr readstring readrlestring rlestring */
         printf("%u dict begin\n", dictSize);
-    
+
     if (!psFilter)
         setupReadstringNative(rle, color, icols, bitsPerSample);
 
@@ -1353,7 +1353,7 @@ putInitPsFilter(unsigned int const postscriptLevel,
     putFilters(postscriptLevel, rle, flate, ascii85, color);
 
     putImage(filterTrue, color);
-    
+
     printf(" } exec");
 }
 
@@ -1365,7 +1365,7 @@ putInitReadstringNative(bool const color) {
     bool const filterFalse = FALSE;
 
     putReadstringNative(color);
-    
+
     putImage(filterFalse, color);
 }
 
@@ -1373,18 +1373,18 @@ putInitReadstringNative(bool const color) {
 
 static void
 putInit(unsigned int const postscriptLevel,
-        char         const name[], 
-        int          const icols, 
-        int          const irows, 
-        float        const scols, 
+        char         const name[],
+        int          const icols,
+        int          const irows,
+        float        const scols,
         float        const srows,
-        float        const llx, 
+        float        const llx,
         float        const lly,
         int          const bitsPerSample,
-        int          const pagewid, 
+        int          const pagewid,
         int          const pagehgt,
-        bool         const color, 
-        bool         const turned, 
+        bool         const color,
+        bool         const turned,
         bool         const rle,
         bool         const flate,
         bool         const ascii85,
@@ -1438,7 +1438,7 @@ putInit(unsigned int const postscriptLevel,
 
 
 static void
-putEnd(bool         const showpage, 
+putEnd(bool         const showpage,
        bool         const psFilter,
        bool         const ascii85,
        unsigned int const dictSize,
@@ -1486,7 +1486,7 @@ validateBpsRequest(unsigned int const bitsPerSampleReq,
                  "-psfilter, the maximum is 8", bitsPerSampleReq);
 }
 
-    
+
 
 static unsigned int
 bpsFromInput(unsigned int const bitsRequiredByMaxval,
@@ -1553,7 +1553,7 @@ warnUserAboutReducedDepth(unsigned int const bitsGot,
 
 static void
 computeDepth(xelval         const inputMaxval,
-             unsigned int   const postscriptLevel, 
+             unsigned int   const postscriptLevel,
              bool           const psFilter,
              unsigned int   const bitsPerSampleReq,
              unsigned int * const bitsPerSampleP) {
@@ -1584,7 +1584,7 @@ computeDepth(xelval         const inputMaxval,
                    "%u bits per sample, so maxval = %u",
                    inputMaxval, *bitsPerSampleP, psMaxval);
     }
-}    
+}
 
 
 
@@ -1643,7 +1643,7 @@ ba_add(BitAccumulator * const baP,
 /*----------------------------------------------------------------------------
   Combine bit sequences that do not fit into a byte.
 
-  Used when bitsPerSample =1, 2, 4.  
+  Used when bitsPerSample =1, 2, 4.
   Logic also works for bitsPerSample = 8, 16.
 
   The accumulator, baP->value is unsigned int (usually 32 bits), but
@@ -1725,7 +1725,7 @@ flushOutput(BitAccumulator * const baP,
 
   convertRowNative and convertRowPsFilter are the general converters.
   They are quite similar, the differences being:
-  (1) Native output separates the color planes: 
+  (1) Native output separates the color planes:
   (RRR...RRR GGG...GGG BBB...BBB),
   whereas psFilter does not:
   (RGB RGB RGB RGB ......... RGB).
@@ -1765,10 +1765,10 @@ convertRowPbm(struct pam *     const pamP,
 
 
 static void
-convertRowNative(struct pam *     const pamP, 
-                 tuple *                tuplerow, 
+convertRowNative(struct pam *     const pamP,
+                 tuple *                tuplerow,
                  unsigned int     const bitsPerSample,
-                 FILE           * const fP) { 
+                 FILE           * const fP) {
 
     unsigned int const psMaxval = pm_bitstomaxval(bitsPerSample);
 
@@ -1795,7 +1795,7 @@ static void
 convertRowPsFilter(struct pam *     const pamP,
                    tuple *                tuplerow,
                    unsigned int     const bitsPerSample,
-                   FILE           * const fP) { 
+                   FILE           * const fP) {
 
     unsigned int const psMaxval = pm_bitstomaxval(bitsPerSample);
 
@@ -1828,7 +1828,7 @@ selectPostscriptLevel(bool           const levelIsGiven,
                       bool           const psFilter,
                       unsigned int * const postscriptLevelP) {
 
-    unsigned int const maxPermittedLevel = 
+    unsigned int const maxPermittedLevel =
         levelIsGiven ? levelGiven : UINT_MAX;
     unsigned int minPossibleLevel;
 
@@ -1877,7 +1877,7 @@ convertRaster(struct pam * const inpamP,
    Read the raster described by *inpamP, and write a bit stream of samples
    to *fP.  This stream has to be compressed and converted to text before it
    can be part of a Postscript program.
-   
+
    'psFilter' means to do the conversion using built in Postscript filters, as
    opposed to our own filters via /readstring.
 
@@ -1897,7 +1897,7 @@ convertRaster(struct pam * const inpamP,
     } else  {
         tuple *tuplerow;
         unsigned int row;
-        
+
         tuplerow = pnm_allocpamrow(inpamP);
 
         for (row = 0; row < inpamP->height; ++row) {
@@ -1920,31 +1920,31 @@ convertRaster(struct pam * const inpamP,
    pipe but this program's output, then we don't want it closed when the
    filter terminates because we'll need it to be open for the next image
    the program converts (with a whole new chain of filters).
-   
-   To prevent the progam output file from getting closed, we pass a
+
+   To prevent the program output file from getting closed, we pass a
    duplicate of it to spawnFilters() and keep the original open.
 */
 
 
 
 static void
-convertPage(FILE *       const ifP, 
-            int          const turnflag, 
-            int          const turnokflag, 
+convertPage(FILE *       const ifP,
+            int          const turnflag,
+            int          const turnokflag,
             bool         const psFilter,
-            bool         const rle, 
+            bool         const rle,
             bool         const flate,
             bool         const ascii85,
             bool         const setpage,
             bool         const showpage,
-            bool         const center, 
+            bool         const center,
             float        const scale,
-            int          const dpiX, 
-            int          const dpiY, 
-            int          const pagewid, 
+            int          const dpiX,
+            int          const dpiY,
+            int          const pagewid,
             int          const pagehgt,
-            int          const imagewidth, 
-            int          const imageheight, 
+            int          const imagewidth,
+            int          const imageheight,
             bool         const equalpixels,
             unsigned int const bitsPerSampleReq,
             char         const name[],
@@ -1952,7 +1952,7 @@ convertPage(FILE *       const ifP,
             bool         const vmreclaim,
             bool         const levelIsGiven,
             unsigned int const levelGiven) {
-    
+
     struct pam inpam;
     float scols, srows;
     float llx, lly;
@@ -1960,7 +1960,7 @@ convertPage(FILE *       const ifP,
     bool color;
     unsigned int postscriptLevel;
     unsigned int bitsPerSample;
-    unsigned int dictSize;  
+    unsigned int dictSize;
         /* Size of Postscript dictionary we should define */
     OutputEncoder oe;
     pid_t filterPidList[MAX_FILTER_CT + 1];
@@ -1974,19 +1974,19 @@ convertPage(FILE *       const ifP,
     pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
 
     validateCompDimension(inpam.width, 16, "Input image width");
-    
+
     if (!STRSEQ(inpam.tuple_type, PAM_PBM_TUPLETYPE) &&
         !STRSEQ(inpam.tuple_type, PAM_PGM_TUPLETYPE) &&
         !STRSEQ(inpam.tuple_type, PAM_PPM_TUPLETYPE))
         pm_error("Unrecognized tuple type %s.  This program accepts only "
-                 "PBM, PGM, PPM, and equivalent PAM input images", 
+                 "PBM, PGM, PPM, and equivalent PAM input images",
                  inpam.tuple_type);
 
     color = STRSEQ(inpam.tuple_type, PAM_PPM_TUPLETYPE);
-    
-    selectPostscriptLevel(levelIsGiven, levelGiven, color, 
+
+    selectPostscriptLevel(levelIsGiven, levelGiven, color,
                           dict, flate, ascii85, psFilter, &postscriptLevel);
-    
+
     if (color)
         pm_message("generating color Postscript program.");
 
@@ -1996,16 +1996,16 @@ convertPage(FILE *       const ifP,
     /* In positioning/scaling the image, we treat the input image as if
        it has a density of 72 pixels per inch.
     */
-    computeImagePosition(dpiX, dpiY, inpam.width, inpam.height, 
+    computeImagePosition(dpiX, dpiY, inpam.width, inpam.height,
                          turnflag, turnokflag, center,
                          pagewid, pagehgt, scale, imagewidth, imageheight,
                          equalpixels,
                          &scols, &srows, &llx, &lly, &turned);
 
     determineDictionaryRequirement(dict, psFilter, &dictSize);
-    
-    putInit(postscriptLevel, name, inpam.width, inpam.height, 
-            scols, srows, llx, lly, bitsPerSample, 
+
+    putInit(postscriptLevel, name, inpam.width, inpam.height,
+            scols, srows, llx, lly, bitsPerSample,
             pagewid, pagehgt, color,
             turned, rle, flate, ascii85, setpage, psFilter, dictSize);
 
@@ -2017,7 +2017,7 @@ convertPage(FILE *       const ifP,
         /* spawnFilters() closes this.  See FILE MANAGEMENT above */
 
     spawnFilters(filterChainOfP, &oe, &feedFileP, filterPidList);
- 
+
     convertRaster(&inpam, bitsPerSample, psFilter, feedFileP);
 
     fflush(feedFileP);
@@ -2081,17 +2081,17 @@ main(int argc, const char * argv[]) {
 
         eof = FALSE;  /* There is always at least one image */
         for (imageSeq = 0; !eof; ++imageSeq) {
-            convertPage(ifP, cmdline.mustturn, cmdline.canturn, 
+            convertPage(ifP, cmdline.mustturn, cmdline.canturn,
                         cmdline.psfilter,
-                        cmdline.rle, cmdline.flate, cmdline.ascii85, 
+                        cmdline.rle, cmdline.flate, cmdline.ascii85,
                         cmdline.setpage, cmdline.showpage,
                         cmdline.center, cmdline.scale,
                         cmdline.dpiX, cmdline.dpiY,
-                        cmdline.width, cmdline.height, 
-                        cmdline.imagewidth, cmdline.imageheight, 
+                        cmdline.width, cmdline.height,
+                        cmdline.imagewidth, cmdline.imageheight,
                         cmdline.equalpixels,
                         cmdline.bitspersampleSpec ? cmdline.bitspersample : 0,
-                        name, 
+                        name,
                         cmdline.dict, cmdline.vmreclaim,
                         cmdline.levelSpec, cmdline.level);
             pnm_nextimage(ifP, &eof);
@@ -2121,7 +2121,7 @@ main(int argc, const char * argv[]) {
 **  wrzl@gup.uni-linz.ac.at.
 **
 ** July 2011 afu
-** row convertors rewritten, fast PBM-only row convertor added,
+** row converters rewritten, fast PBM-only row converter added,
 ** rle compression slightly modified, flate compression added
 ** ascii85 output end added.
 **
diff --git a/converter/other/pnmtorle.c b/converter/other/pnmtorle.c
index 7c378246..17c9cfbc 100644
--- a/converter/other/pnmtorle.c
+++ b/converter/other/pnmtorle.c
@@ -1,7 +1,7 @@
 /*
  * This is derived from the file of the same name dated June 5, 1995,
  * copied from the Army High Performance Computing Research Center's
- * media-tools.tar.gz package, received from 
+ * media-tools.tar.gz package, received from
  * http://www.arc.umn.edu/gvl-software/media-tools.tar.gz on 2000.04.13.
  *
  * This software is copyrighted as noted below.  It may be freely copied,
@@ -29,75 +29,161 @@
  *              Minnesota Supercomputer Center, Inc.
  * Date:        March 30, 1994
  * Copyright (c) Minnesota Supercomputer Center, Inc.
- * 
- * 2000.04.13 adapted for Netpbm by Bryan Henderson.  Quieted compiler 
+ *
+ * 2000.04.13 adapted for Netpbm by Bryan Henderson.  Quieted compiler
  *            warnings.
  *
+ * 2022.03.06 revision by Akira F Urushibata
+ *            use shhopt instead of scanargs
+ *            proper handling of multiple image files with -h
+ *
  */
 /*-----------------------------------------------------
  * System includes.
  */
 #include <string.h>
 #include <stdio.h>
+#include <assert.h>
 #include "pnm.h"
 #include "mallocvar.h"
 #include "rle.h"
+#include "shhopt.h"
+#include "pm_c_util.h"
 
-#define VPRINTF if (verbose || header) fprintf
 
-typedef unsigned char U_CHAR;
-/*
- * Global variables.
- */
-static FILE    *fp;
-static rle_hdr hdr;
-static int  format;
-static int width, height;
-static int verbose = 0, header = 0, do_alpha = 0;
-static 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 * inFileName;
+    const char * outfile;
+    unsigned int verbose;
+    unsigned int header;
+    unsigned int alpha;
+};
+
+
+
+static void
+parseCommandLine(int argc, const 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 pm_optParseOptions3 on how to parse our options. */
+
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+    unsigned int outfileSpec;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "alpha",    OPT_FLAG,   NULL,  &cmdlineP->alpha,     0);
+    OPTENT3(0, "header",   OPT_FLAG,   NULL,  &cmdlineP->header,    0);
+    OPTENT3(0, "verbose",  OPT_FLAG,   NULL,  &cmdlineP->verbose,   0);
+    OPTENT3(0, "outfile",  OPT_STRING, &cmdlineP->outfile,
+                                              &outfileSpec,         0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = false;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = false;  /* We have no parms that are negative numbers */
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    free(option_def);
+
+    if (argc-1 == 0)
+        cmdlineP->inFileName = "-";
+    else if (argc-1 != 1) {
+        pm_error("Program takes zero or one argument (filename).  You "
+                 "specified %d", argc-1);
+    }
+    else
+        cmdlineP->inFileName = argv[1];
+
+    if (!outfileSpec)
+        cmdlineP->outfile = "-";
+}
+
+
+
+static void
+readPnmHeader(bool      const verbose,
+              bool      const wantAlpha,
+              FILE    * const ifP,
+              int     * const widthP,
+              int     * const heightP,
+              gray    * const maxvalP,
+              int     * const formatP) {
 /*-----------------------------------------------------------------------------
- *                                        Read the pnm image file header.
- */
-static void 
-read_pnm_header(void) {
+  Read the pnm image file header.
+---------------------------------------------------------------------------- */
+    int   width;
+    int   height;
+    gray  maxval;
+    int   format;
+    const char * type;
+
+    pnm_readpnminit(ifP, &width, &height, &maxval, &format);
 
-    pnm_readpnminit(fp, &width, &height, &maxval, &format);
     switch (format) {
     case PBM_FORMAT:
-        VPRINTF(stderr, "Image type: plain pbm format\n");
+        type="plain pbm";
         break;
     case RPBM_FORMAT:
-        VPRINTF(stderr, "Image type: raw pbm format\n");
+        type="raw pbm";
         break;
     case PGM_FORMAT:
-        VPRINTF(stderr, "Image type: plain pgm format\n");
+        type="plain pgm";
         break;
     case RPGM_FORMAT:
-        VPRINTF(stderr, "Image type: raw pgm format\n");
+        type="raw pgm";
         break;
     case PPM_FORMAT:
-        VPRINTF(stderr, "Image type: plain ppm format\n");
+        type="plain ppm";
         break;
     case RPPM_FORMAT:
-        VPRINTF(stderr, "Image type: raw ppm format\n");
+        type="raw ppm";
         break;
     }
-    VPRINTF(stderr, "Full image: %dx%d\n", width, height);
-    VPRINTF(stderr, "Maxval:     %d\n", maxval);
-    if (do_alpha)
-        VPRINTF(stderr, "Computing alpha channel...\n");
+    if (verbose) {
+        pm_message("Image type: %s format", type);
+        pm_message("Full image: %dx%d", width, height);
+        pm_message("Maxval:     %d", maxval);
+
+        if (wantAlpha)
+            pm_message("Computing alpha channel...");
+    }
+    *widthP  = width;
+    *heightP = height;
+    *maxvalP = maxval;
+    *formatP = format;
 }
 
 
 
-static void 
-write_rle_header(void) {
+static void
+writeRleHeader(bool         const wantAlpha,
+               int          const format,
+               unsigned int const width,
+               unsigned int const height,
+               rle_hdr *    const hdrP) {
+
+    rle_hdr hdr;
+
+    hdr = *hdrP;  /* initial value */
 
     hdr.xmin    = 0;
     hdr.xmax    = width-1;
     hdr.ymin    = 0;
     hdr.ymax    = height-1;
     hdr.background = 0;
+
     switch (format) {
     case PBM_FORMAT:
     case RPBM_FORMAT:
@@ -114,31 +200,44 @@ write_rle_header(void) {
         RLE_SET_BIT(hdr, RLE_BLUE);
         break;
     }
-    if (do_alpha) {
+    if (wantAlpha) {
         hdr.alpha = 1;
         RLE_SET_BIT(hdr, RLE_ALPHA);
     }
     rle_put_setup(&hdr);
+
+    *hdrP = hdr;
 }
 
 
 
-static void 
-write_rle_data(void) {
+static void
+writeRleData(bool         const verbose,
+             bool         const wantAlpha,
+             FILE      *  const ifP,
+             rle_hdr   *  const hdrP,
+             unsigned int const width,
+             unsigned int const height,
+             gray         const maxval,
+             int          const format) {
 
     unsigned int scan;
     xel * xelrow;
     rle_pixel *** scanlines;
 
     MALLOCARRAY(xelrow, width);
-    MALLOCARRAY(scanlines, height);
+    if (xelrow == NULL)
+        pm_error("Failed to allocate memory for row of %u pixels", width);
 
-    RLE_CHECK_ALLOC(hdr.cmd, scanlines, "scanline pointers");
+    MALLOCARRAY(scanlines, height);
+    if (scanlines == NULL)
+        pm_error("Failed to allocate memory for %u scanline pointers", height);
 
     for (scan = 0; scan < height; ++scan) {
         int rc;
-        rc = rle_row_alloc(&hdr, &scanlines[scan]);
-        RLE_CHECK_ALLOC(hdr.cmd, rc >= 0, "pixel memory");
+        rc = rle_row_alloc(hdrP, &scanlines[scan]);
+        if (rc < 0)
+            pm_error("Failed to allocate memory for a scanline");
     }
     /* Loop through the pnm files image window, read data and flip vertically.
      */
@@ -149,10 +248,10 @@ write_rle_data(void) {
         for (scan = 0; scan < height; ++scan) {
             rle_pixel ** const scanline = scanlines[height - scan - 1];
             unsigned int col;
-            pnm_readpnmrow(fp, xelrow, width, maxval, format);
+            pnm_readpnmrow(ifP, xelrow, width, maxval, format);
             for (col = 0; col < width; ++col) {
                 scanline[RLE_RED][col] = PNM_GET1(xelrow[col]) ? 255 : 0;
-                if (do_alpha)
+                if (wantAlpha)
                     scanline[RLE_ALPHA][col] = scanline[RLE_RED][col];
             }
         }
@@ -163,10 +262,10 @@ write_rle_data(void) {
         for (scan = 0; scan < height; ++scan) {
             rle_pixel ** const scanline = scanlines[height - scan - 1];
             unsigned int col;
-            pnm_readpnmrow(fp, xelrow, width, maxval, format);
+            pnm_readpnmrow(ifP, xelrow, width, maxval, format);
             for (col = 0; col < width; ++col) {
                 scanline[RLE_RED][col] = PNM_GET1(xelrow[col]);
-                if (do_alpha)
+                if (wantAlpha)
                     scanline[RLE_ALPHA][col] =
                         scanline[RLE_RED][col] ? 255 : 0;
             }
@@ -177,13 +276,16 @@ write_rle_data(void) {
         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);
+
+            pnm_readpnmrow(ifP, xelrow, width, maxval, format);
+
             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)
+                if (wantAlpha)
                     scanline[RLE_ALPHA][col] =
                         (scanline[RLE_RED][col] ||
                          scanline[RLE_GREEN][col] ||
@@ -194,25 +296,27 @@ write_rle_data(void) {
     }
     /* Write out data in URT order (bottom to top). */
     for (scan = 0; scan < height; ++scan)
-        rle_putrow(scanlines[scan], width, &hdr);
+        rle_putrow(scanlines[scan], width, hdrP);
 
     for (scan = 0; scan < height; ++scan)
-        rle_row_free(&hdr, scanlines[scan]);
+        rle_row_free(hdrP, scanlines[scan]);
     free(scanlines);
     free(xelrow);
 
-    VPRINTF(stderr, "Done -- write eof to RLE data.\n");
-    rle_puteof(&hdr);
+    if (verbose)
+        pm_message("Done -- write eof to RLE data.");
+
+    rle_puteof(hdrP);
 }
 
 
 
 static void
-skip_data(FILE      * const fp,
-          int         const width,
-          int         const height,
-          gray        const maxval,
-          int         const format) {
+skipData(FILE      *  const ifP,
+         unsigned int const width,
+         unsigned int const height,
+         gray         const maxval,
+         int          const format) {
 
     xel * xelrow;
     unsigned int scan;
@@ -221,8 +325,8 @@ skip_data(FILE      * const fp,
     if (xelrow == NULL)
         pm_error("Failed to allocate memory for row of %u pixels", width);
 
-    for(scan=0; scan < height; ++scan)
-        pnm_readpnmrow(fp, xelrow, width, maxval, format);
+    for (scan=0; scan < height; ++scan)
+        pnm_readpnmrow(ifP, xelrow, width, maxval, format);
 
     free(xelrow);
 }
@@ -230,57 +334,57 @@ skip_data(FILE      * const fp,
 
 
 int
-main(int argc, char **  argv) {
-
-    const char * pnmname;
-    const char * outname;
-    int oflag;
+main(int argc, char ** argv) {
+
+    struct CmdlineInfo cmdline;
+
+    FILE   * ifP;
+    rle_hdr hdr;
+    int  format;
+    int  width, height;
+    gray maxval;
+    bool verbose;
+    const char ** argvWork;
+    unsigned int i;
     int eof;
 
-    pnm_init(&argc, argv);
-
-    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\
-\t-a\tFake an alpha channel.  Alpha=0 when input=0, 255 otherwise.\n\
-\t-h\tPrint header of PNM file and exit.\n\
-\t-v\tVerbose mode.)",
-                  &verbose,
-                  &header,
-                  &do_alpha,
-                  &oflag, &outname,
-                  &pnmname))
-        exit(-1);
+    MALLOCARRAY_NOFAIL(argvWork, argc + 1);
+
+    for (i = 0; i < argc; ++i)  /* Make a copy of argv */
+        argvWork[i] = argv[i];
+
+    pm_proginit(&argc, argvWork);
+
+    parseCommandLine(argc, argvWork, &cmdline);
+
+    verbose = cmdline.verbose || cmdline.header;
 
     hdr = *rle_hdr_init(NULL);
-    rle_names(&hdr, cmd_name(argv), outname, 0);
+
+    rle_names(&hdr, "pnmtorle", cmdline.outfile, 0);
 
     /* Open the file. */
-    if (pnmname == NULL) {
-        fp = pm_openr("-");
-    } else {
-        fp = pm_openr(pnmname);
-    }
+    assert(cmdline.inFileName != NULL);
+    ifP = pm_openr(cmdline.inFileName);
 
-    hdr.rle_file = rle_open_f( hdr.cmd, outname, "wb" );
+    hdr.rle_file = rle_open_f(hdr.cmd, cmdline.outfile, "wb");
 
     for (eof = 0; !eof; ) {
-        read_pnm_header();
+        readPnmHeader(verbose, cmdline.alpha, ifP,
+                      &width, &height, &maxval, &format);
 
-        if (header)
-            skip_data(fp, width, height, maxval, format);
-        else {
+        if (cmdline.header) {
+            skipData(ifP, width, height, maxval, format);
+        } else {
             rle_addhist(argv, NULL, &hdr);
-            write_rle_header();
-            write_rle_data();
+            writeRleHeader(cmdline.alpha, format, width, height, &hdr);
+            writeRleData(verbose, cmdline.alpha, ifP, &hdr,
+                         width, height, maxval, format);
         }
-        pnm_nextimage(fp, &eof);
+        pnm_nextimage(ifP, &eof);
     }
-    pm_close(fp);
+
+    pm_close(ifP);
 
     return 0;
 }
diff --git a/converter/other/pnmtosir.c b/converter/other/pnmtosir.c
index 20bb6178..7b7650fe 100644
--- a/converter/other/pnmtosir.c
+++ b/converter/other/pnmtosir.c
@@ -20,16 +20,16 @@
 
 int
 main(int argc, const char * argv[]) {
-    
+
     FILE * ifP;
     xel ** xels;
     int rows, cols, format;
     unsigned int n;
     bool isGrayscale;
     xelval maxval;
-    unsigned short Header[16];
-    unsigned short LutHeader[16];
-    unsigned short Lut[2048];
+    unsigned short Header[10];
+    unsigned short LutHeader[5];
+    unsigned short Lut[1024];
 
     pm_proginit(&argc, argv);
 
@@ -43,9 +43,9 @@ main(int argc, const char * argv[]) {
     }  else {
         ifP = stdin;
     }
-    
+
     xels = pnm_readpnm(ifP, &cols, &rows, &maxval, &format);
-    
+
     /* Figure out the colormap. */
     switch (PNM_FORMAT_TYPE(format) ) {
     case PPM_TYPE:
@@ -93,15 +93,19 @@ main(int argc, const char * argv[]) {
         pm_writelittleshort(stdout,LutHeader[n]);
     for (n = 5; n < 256; ++n)
         pm_writelittleshort(stdout,0);
- 
-    for (n = 0; n < 3; ++n) {
+
+    for (n = 0; n < 256; ++n) {
         unsigned int m;
-        for (m = 0; m < 256; ++m)
-            Lut[m * 4 + n] = m << 8;
+        for (m = 0; m < 3; ++m)
+            Lut[n * 4 + m] = n << 8;
+
+        Lut[n * 4 + 3] = 0;
+            /* Clear to ensure repeatable output, suppress Valgrind error */
     }
+
     for (n = 0; n < 1024; ++n)
         pm_writelittleshort(stdout,Lut[n]);
- 
+
     /* Finally, write out the data. */
     switch (PNM_FORMAT_TYPE(format)) {
     case PPM_TYPE: {
@@ -110,13 +114,13 @@ main(int argc, const char * argv[]) {
             unsigned int col;
             for (col = 0; col < cols; ++col) {
                 unsigned char const ub =
-                    (char) (PPM_GETR(xels[row][col]) * (255 / maxval)); 
+                    (char) (PPM_GETR(xels[row][col]) * (255 / maxval));
                 fputc(ub, stdout);
             }
         }
         for (row = 0; row < rows; ++row) {
             unsigned int col;
-            for (col = 0; col < cols; ++col) {  
+            for (col = 0; col < cols; ++col) {
                 unsigned const char ub =
                     (char) (PPM_GETG(xels[row][col]) * (255 / maxval));
                 fputc(ub, stdout);
@@ -124,7 +128,7 @@ main(int argc, const char * argv[]) {
         }
         for (row = 0; row < rows; ++row) {
             unsigned int col;
-            for (col = 0; col < cols; ++col) {  
+            for (col = 0; col < cols; ++col) {
                 unsigned const char ub =
                     (char) (PPM_GETB(xels[row][col]) * (255 / maxval));
                 fputc(ub, stdout);
@@ -144,10 +148,11 @@ main(int argc, const char * argv[]) {
         }
     } break;
     }
-    
+
     pm_close(ifP);
 
     return 0;
 }
 
 
+
diff --git a/converter/other/pstopnm.c b/converter/other/pstopnm.c
index f5342655..25f2c429 100644
--- a/converter/other/pstopnm.c
+++ b/converter/other/pstopnm.c
@@ -442,7 +442,7 @@ languageDeclaration(char const inputFileName[]) {
 /*----------------------------------------------------------------------------
   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
-  a languages, just say it is Common Postscript).
+  a language, just say it is Common Postscript).
 -----------------------------------------------------------------------------*/
     enum PostscriptLanguage language;
 
@@ -909,6 +909,27 @@ execGhostscript(int               const inputPipeFd,
 
 
 static void
+copyFileStream(FILE * const ifP,
+               FILE * const ofP) {
+
+    bool eof;
+
+    for (eof = false; !eof; ) {
+        char buffer[4096];
+        size_t readCt;
+
+        readCt = fread(buffer, 1, sizeof(buffer), ifP);
+
+        if (readCt == 0)
+            eof = true;
+        else
+            fwrite(buffer, 1, readCt, ofP);
+    }
+}
+
+
+
+static void
 feedPsToGhostScript(const char *            const inputFileName,
                     struct Box              const borderedBox,
                     struct Dimensions       const imageDim,
@@ -927,7 +948,6 @@ feedPsToGhostScript(const char *            const inputFileName,
 -----------------------------------------------------------------------------*/
     FILE * pipeToGsP;  /* Pipe to Ghostscript's standard input */
     FILE * ifP;
-    bool eof;  /* End of file on input */
 
     pipeToGsP = fdopen(pipeToGhostscriptFd, "w");
     if (pipeToGsP == NULL)
@@ -947,8 +967,14 @@ feedPsToGhostScript(const char *            const inputFileName,
       The example given is a much fancier solution than we need
       here, I think, so I boiled it down a bit.  JM
     */
-    if (language == ENCAPSULATED_POSTSCRIPT)
-        fprintf(pipeToGsP, "\n/b4_Inc_state save def /showpage { } def\n");
+    if (language == ENCAPSULATED_POSTSCRIPT) {
+        const char * const defShowpageCmd =
+            "/b4_Inc_state save def /showpage { } def";
+        if (verbose)
+            pm_message("Defining showpage with '%s'", defShowpageCmd);
+
+        fprintf(pipeToGsP, "\n%s\n", defShowpageCmd);
+    }
 
     writePstrans(borderedBox, imageDim, orientation, pipeToGsP);
 
@@ -958,22 +984,19 @@ feedPsToGhostScript(const char *            const inputFileName,
     */
     signal(SIGPIPE, SIG_IGN);
 
-    eof = FALSE;
-    while (!eof) {
-        char buffer[4096];
-        size_t readCt;
+    copyFileStream(ifP, pipeToGsP);
 
-        readCt = fread(buffer, 1, sizeof(buffer), ifP);
-        if (readCt == 0)
-            eof = TRUE;
-        else
-            fwrite(buffer, 1, readCt, pipeToGsP);
-    }
     pm_close(ifP);
 
-    if (language == ENCAPSULATED_POSTSCRIPT)
-        fprintf(pipeToGsP, "\nb4_Inc_state restore showpage\n");
+    if (language == ENCAPSULATED_POSTSCRIPT) {
+        const char * const restoreShowpageCmd =
+            "b4_Inc_state restore showpage";
+
+        if (verbose)
+            pm_message("Restoring showpage with '%s'", restoreShowpageCmd);
 
+        fprintf(pipeToGsP, "\n%s\n", restoreShowpageCmd);
+    }
     fclose(pipeToGsP);
 }
 
diff --git a/converter/other/pstopnm.csh b/converter/other/pstopnm.csh
index adde3e6f..22e3306d 100755
--- a/converter/other/pstopnm.csh
+++ b/converter/other/pstopnm.csh
@@ -5,7 +5,7 @@
 #	pstopnm will create as many files as the number of pages in 
 #	the Postscript document.  The name of the files will be 
 #	psfile001.ppm, psfile002.ppm, etc.
-#	The ouput files will contain the area inside the BoundingBox.
+#	The output files will contain the area inside the BoundingBox.
 #	If BoundingBox parameters are not found in the PostScript
 #	document, default values are used.
 #
diff --git a/converter/other/qoi.h b/converter/other/qoi.h
new file mode 100644
index 00000000..52ee95e2
--- /dev/null
+++ b/converter/other/qoi.h
@@ -0,0 +1,101 @@
+#ifndef QOI_H_INCLUDED
+#define QOI_H_INCLUDED
+/*
+
+QOI - The "Quite OK Image" format for fast, lossless image compression
+
+Dominic Szablewski - https://phoboslab.org
+
+
+-- LICENSE: The MIT License(MIT)
+
+Copyright(c) 2021 Dominic Szablewski
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files(the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions :
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+*/
+
+
+typedef enum {
+    QOI_SRGB = 0,
+    QOI_LINEAR = 1
+} qoi_Colorspace;
+
+
+typedef struct {
+    unsigned int   width;
+    unsigned int   height;
+    unsigned int   channelCt;
+    qoi_Colorspace colorspace;
+} qoi_Desc;
+
+
+
+#define QOI_OP_INDEX  0x00 /* 00xxxxxx */
+#define QOI_OP_DIFF   0x40 /* 01xxxxxx */
+#define QOI_OP_LUMA   0x80 /* 10xxxxxx */
+#define QOI_OP_RUN    0xc0 /* 11xxxxxx */
+#define QOI_OP_RGB    0xfe /* 11111110 */
+#define QOI_OP_RGBA   0xff /* 11111111 */
+
+#define QOI_MASK_2    0xc0 /* 11000000 */
+
+#define QOI_HEADER_SIZE 14
+
+/* 2GB is the max file size that this implementation can safely handle. We
+   guard against anything larger than that, assuming the worst case with 5
+   bytes per pixel, rounded down to a nice clean value. 400 million pixels
+   ought to be enough for anybody.
+ */
+#define QOI_PIXELS_MAX 400000000
+
+static unsigned int const qoi_pixels_max = (unsigned int) QOI_PIXELS_MAX;
+
+#define QOI_MAXVAL 255
+
+#define QOI_INDEX_SIZE 64
+
+
+typedef union {
+    struct { unsigned char r, g, b, a; } rgba;
+    unsigned int v;
+} qoi_Rgba;
+
+static __inline__ unsigned int
+qoi_colorHash(qoi_Rgba const x) {
+
+    return
+        (x.rgba.r*3 + x.rgba.g*5 + x.rgba.b*7 + x.rgba.a*11) % QOI_INDEX_SIZE;
+}
+
+static __inline__ void
+qoi_clearQoiIndex(qoi_Rgba * index) {
+
+    memset(index, 0, QOI_INDEX_SIZE * sizeof(qoi_Rgba));
+
+}
+
+#define QOI_MAGIC_SIZE 4
+
+static char const qoi_magic[QOI_MAGIC_SIZE + 1] = {'q','o','i','f','\0'};
+
+#define QOI_PADDING_SIZE 8
+
+static unsigned char const qoi_padding[QOI_PADDING_SIZE] = {0,0,0,0,0,0,0,1};
+
+
+#endif
diff --git a/converter/other/qoitopam.c b/converter/other/qoitopam.c
new file mode 100644
index 00000000..af6817b7
--- /dev/null
+++ b/converter/other/qoitopam.c
@@ -0,0 +1,323 @@
+/*
+  qoitopam -  Converts from a QOI - The "Quite OK Image" format file to PAM
+
+  This program is part of Netpbm.
+
+  ---------------------------------------------------------------------
+
+
+  QOI - The "Quite OK Image" format for fast, lossless image compression
+
+  Decoder by Dominic Szablewski - https://phoboslab.org
+
+  -- LICENSE: The MIT License(MIT)
+
+  Copyright(c) 2021 Dominic Szablewski
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files(the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions :
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+
+  For more information on the format visit: https//qoiformat.org/ .
+
+  Modifications for Netpbm & PAM write routines by Akira F. Urushibata.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "pm.h"
+#include "pam.h"
+#include "mallocvar.h"
+#include "nstring.h"
+#include "shhopt.h"
+
+#include "qoi.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;  /* '-' if stdin */
+};
+
+
+
+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 pm_optParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+
+    MALLOCARRAY(option_def, 100);
+
+    OPTENTINIT;
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (argc-1 < 1)
+        cmdlineP->inputFileName = "-";
+    else if (argc-1 == 1)
+        cmdlineP->inputFileName = argv[1];
+    else
+        pm_error("Program takes at most one argument: input file name.  "
+            "you specified %d", argc-1);
+}
+
+
+
+static void
+readAndValidateMagic(FILE * const ifP){
+
+    char magicBuff[QOI_MAGIC_SIZE];
+    size_t charsReadCt;
+
+    charsReadCt = fread(magicBuff, 1, QOI_MAGIC_SIZE, ifP);
+
+    if (charsReadCt == 0)
+        pm_error("Input file is empty.");
+    else if (charsReadCt < QOI_MAGIC_SIZE || !MEMSEQ(&magicBuff, &qoi_magic)) {
+        assert(QOI_MAGIC_SIZE == 4);
+        pm_error("Invalid QOI image: does not start with magic number "
+                 "'%c%c%c%c'",
+                 qoi_magic[0], qoi_magic[1], qoi_magic[2], qoi_magic[3]);
+    }
+}
+
+
+/* The following two functions are from lib/pmfileio.c */
+
+static void
+abortWithReadError(FILE * const ifP) {
+
+    if (feof(ifP))
+        pm_error("Unexpected end of input file");
+    else
+        pm_error("Error (not EOF) reading file.");
+}
+
+
+
+static unsigned char
+getcNofail(FILE * const ifP) {
+
+    int c;
+
+    c = getc(ifP);
+
+    if (c == EOF)
+        abortWithReadError(ifP);
+
+    return (unsigned char) c;
+}
+
+
+
+static void
+decodeQoiHeader(FILE *     const ifP,
+                qoi_Desc * const qoiDescP) {
+
+    unsigned long int width, height;
+
+    readAndValidateMagic(ifP);
+
+    pm_readbiglongu(ifP, &width);
+    if (width == 0)
+        pm_error("Invalid QOI image: width is zero");
+    else
+        qoiDescP->width = width;
+
+    pm_readbiglongu(ifP, &height);
+    if (height == 0)
+        pm_error("Invalid QOI image: height is zero");
+    else if (height > QOI_PIXELS_MAX / width)
+        pm_error ("Invalid QOI image: %u x %u is more than %u pixels",
+                  (unsigned int) width, (unsigned int) height, QOI_PIXELS_MAX);
+    else
+        qoiDescP->height = height;
+
+    qoiDescP->channelCt = getcNofail(ifP);
+    if (qoiDescP->channelCt != 3 && qoiDescP->channelCt != 4)
+        pm_error("Invalid QOI image: channel count is %u.  "
+                 "Only 3 and 4 are valid", qoiDescP->channelCt);
+
+    qoiDescP->colorspace = getcNofail(ifP);
+    if (qoiDescP->colorspace != QOI_SRGB && qoiDescP->colorspace != QOI_LINEAR)
+        pm_error("Invalid QOI image: colorspace code is %u.  "
+                 "Only %u (SRGB) and %u (LINEAR) are valid",
+                 qoiDescP->colorspace, QOI_SRGB, QOI_LINEAR);
+}
+
+
+
+static void
+qoiDecode(FILE *       const ifP,
+          qoi_Desc *   const qoiDescP,
+          struct pam * const outpamP) {
+
+    qoi_Rgba index[QOI_INDEX_SIZE];
+    unsigned int row;
+    qoi_Rgba px;
+    unsigned int run;
+    tuple * tuplerow;
+
+    assert(qoiDescP);
+    tuplerow = pnm_allocpamrow(outpamP);
+
+    qoi_clearQoiIndex(index);
+    px.rgba.r = px.rgba.g = px.rgba.b = 0;
+    px.rgba.a = 255;
+
+    for (row = 0, run = 0; row < outpamP->height; ++row) {
+        unsigned int col;
+
+        for (col = 0; col < outpamP->width; ++col) {
+            if (run > 0) {
+                 --run;
+            } else {
+                unsigned char const b1 = getcNofail(ifP);
+
+                if (b1 == QOI_OP_RGB) {
+                    px.rgba.r = getcNofail(ifP);
+                    px.rgba.g = getcNofail(ifP);
+                    px.rgba.b = getcNofail(ifP);
+                } else if (b1 == QOI_OP_RGBA) {
+                    px.rgba.r = getcNofail(ifP);
+                    px.rgba.g = getcNofail(ifP);
+                    px.rgba.b = getcNofail(ifP);
+                    px.rgba.a = getcNofail(ifP);
+                } else if ((b1 & QOI_MASK_2) == QOI_OP_INDEX) {
+                  /* Official spec says 2 or more consecutive instances of
+                     QOI_OP_INDEX are not allowed, but we don't check */
+                    px = index[b1];
+                } else if ((b1 & QOI_MASK_2) == QOI_OP_DIFF) {
+                    px.rgba.r += ((b1 >> 4) & 0x03) - 2;
+                    px.rgba.g += ((b1 >> 2) & 0x03) - 2;
+                    px.rgba.b += ( b1       & 0x03) - 2;
+                } else if ((b1 & QOI_MASK_2) == QOI_OP_LUMA) {
+                    unsigned char const b2 = getcNofail(ifP);
+                    unsigned char const vg = (b1 & 0x3f) - 32;
+                    px.rgba.r += vg - 8 + ((b2 >> 4) & 0x0f);
+                    px.rgba.g += vg;
+                    px.rgba.b += vg - 8 +  (b2       & 0x0f);
+                } else if ((b1 & QOI_MASK_2) == QOI_OP_RUN) {
+                    run = (b1 & 0x3f);
+                }
+                /* register pixel in hash lookup array */
+                index[qoi_colorHash(px)] = px;
+            }
+            tuplerow[col][PAM_RED_PLANE] = px.rgba.r;
+            tuplerow[col][PAM_GRN_PLANE] = px.rgba.g;
+            tuplerow[col][PAM_BLU_PLANE] = px.rgba.b;
+            if (qoiDescP->channelCt == 4)
+                tuplerow[col][PAM_TRN_PLANE] = px.rgba.a;
+        }
+        pnm_writepamrow(outpamP, tuplerow);
+    }
+    if (run > 0)
+        pm_error("Invalid QOI image: %u (or more) extra pixels "
+                 "beyond end of image.", run);
+
+    pnm_freepamrow(tuplerow);
+}
+
+
+
+static void
+readAndValidatePadding(FILE * const ifP){
+
+    unsigned char padBuff[QOI_PADDING_SIZE];
+    size_t charsReadCt;
+
+    charsReadCt = fread(padBuff, 1, QOI_PADDING_SIZE, ifP);
+
+    if(charsReadCt < QOI_PADDING_SIZE) {
+        pm_error("Invalid QOI image.  Error reading final 8-byte padding.  "
+                 "Premature end of file.");
+    } else if (!MEMSEQ(&padBuff, &qoi_padding))
+        pm_error("Invalid QOI image.  Final 8-byte padding incorrect.");
+    else if (fgetc(ifP) != EOF)
+        pm_error("Invalid QOI image.  "
+                 "Extraneous bytes after final 8-byte padding.");
+}
+
+
+
+int
+main(int argc, const char **argv) {
+
+    struct CmdlineInfo cmdline;
+    qoi_Desc qoiDesc;
+    struct pam outpam;
+    FILE * ifP;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    outpam.size        = sizeof(struct pam);
+    outpam.len         = PAM_STRUCT_SIZE(tuple_type);
+    outpam.maxval      = QOI_MAXVAL;
+    outpam.plainformat = 0;
+
+    decodeQoiHeader(ifP, &qoiDesc);
+
+    outpam.depth  = qoiDesc.channelCt == 3 ? 3 : 4;
+    outpam.width  = qoiDesc.width;
+    outpam.height = qoiDesc.height;
+    outpam.format = PAM_FORMAT;
+    outpam.file   = stdout;
+
+    if (qoiDesc.channelCt == 3)
+        strcpy(outpam.tuple_type, PAM_PPM_TUPLETYPE);
+    else
+        strcpy(outpam.tuple_type, PAM_PPM_ALPHA_TUPLETYPE);
+
+    pnm_writepaminit(&outpam);
+    qoiDecode(ifP, &qoiDesc, &outpam);
+
+    readAndValidatePadding(ifP);
+
+    return 0;
+}
+
+
diff --git a/converter/other/rlatopam.c b/converter/other/rlatopam.c
index 703c4820..2c694bd4 100644
--- a/converter/other/rlatopam.c
+++ b/converter/other/rlatopam.c
@@ -85,9 +85,9 @@ read_header(FILE *   const ifP,
 
     rlahdr hdr;
     size_t bytesRead;
-    
+
     fseek (ifP, 0, SEEK_SET);
-    
+
     /* Here we have a hack.  The bytes in the file are almost in the
        same format as the compiler stores 'hdr' in memory.  The only
        difference is that the compiler may store the integer values
@@ -185,7 +185,7 @@ decode(unsigned char * const input,
     x = xFile;
     bytes = 0;
     useX = 0;
-    
+
     while (x > 0) {
         int count;
 
@@ -246,7 +246,7 @@ decode_row(FILE *          const ifP,
     for (chan = 0; chan < outpam.depth; ++chan) {
         unsigned short length;
         size_t bytesRead;
-        
+
         pm_readbigshortu(ifP, &length);
         if (length > width * 4)
             pm_error("Line too long - row %u, channel %u", row, chan);
@@ -266,7 +266,7 @@ decode_row(FILE *          const ifP,
             decode(newpos, rb + chan * 2 + 1, width, width,
                    outpam.depth * 2);
         } else
-            decode(read_buffer, rb + chan, width, width, outpam.depth); 
+            decode(read_buffer, rb + chan, width, width, outpam.depth);
     }
 }
 
@@ -280,7 +280,7 @@ getHeaderInfo(FILE *         const ifP,
               bool *         const hasMatteP,
               unsigned int * const chanBitsP,
               short *        const storageType) {
-    
+
     rlahdr hdr;
     int width, height;
 
@@ -350,7 +350,7 @@ readAndWriteRaster(FILE *             const ifP,
     /* Hold one row of all image planes */
     rowBuffer = calloc(1, width * outpamP->depth * 4);
     if (rowBuffer == NULL)
-        pm_error("Unable to allocate memor for row buffer.");
+        pm_error("Unable to allocate memory for row buffer.");
 
     tuplerow = pnm_allocpamrow(outpamP);
 
@@ -403,7 +403,7 @@ main(int    argc,
     outpam.height = height;
     outpam.width  = width;
     outpam.depth  = numChan + (has_matte ? 1 : 0);
-    outpam.maxval = (1 << (chanBits > 16 ? 
+    outpam.maxval = (1 << (chanBits > 16 ?
                            (9 + (chanBits - 1) % 8)
                                 /* Take top 2 of 3 or 4 bytes */
                            : chanBits)) - 1;
@@ -427,8 +427,11 @@ main(int    argc,
     readAndWriteRaster(ifP, &outpam);
 
     destroyOffsetArray(offsets);
-    
+
     pm_close(ifP);
 
-    return 0; 
+    return 0;
 }
+
+
+
diff --git a/converter/other/rletopnm.c b/converter/other/rletopnm.c
index 018456c8..97f271dc 100644
--- a/converter/other/rletopnm.c
+++ b/converter/other/rletopnm.c
@@ -1,7 +1,7 @@
 /*
  * This is derived from the file of the same name dated June 5, 1995,
  * copied from the Army High Performance Computing Research Center's
- * media-tools.tar.gz package, received from 
+ * media-tools.tar.gz package, received from
  * http://www.arc.umn.edu/gvl-software/media-tools.tar.gz on 2000.04.13.
  *
  * This software is copyrighted as noted below.  It may be freely copied,
@@ -29,8 +29,8 @@
  *              Minnesota Supercomputer Center, Inc.
  * Date:        March 30, 1994
  * Copyright (c) Minnesota Supercomputer Center 1994
- * 
- * 2000.04.13 adapted for Netpbm by Bryan Henderson.  Quieted compiler 
+ *
+ * 2000.04.13 adapted for Netpbm by Bryan Henderson.  Quieted compiler
  *            warnings.  Added --alpha option.  Accept input on stdin
  *
  */
@@ -105,11 +105,11 @@ parseCommandLine(int argc, char ** argv,
     MALLOCARRAY(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENT3 */
-    OPTENT3('h', "headerdump", OPT_FLAG,   
+    OPTENT3('h', "headerdump", OPT_FLAG,
             NULL,                      &cmdlineP->headerdump,     0);
-    OPTENT3('v', "verbose",    OPT_FLAG,   
+    OPTENT3('v', "verbose",    OPT_FLAG,
             NULL,                      &cmdlineP->verbose,        0);
-    OPTENT3(0,   "alphaout",   OPT_STRING, 
+    OPTENT3(0,   "alphaout",   OPT_STRING,
             &cmdlineP->alphaout, &alphaoutSpec,                   0);
 
     opt.opt_table = option_def;
@@ -127,16 +127,16 @@ parseCommandLine(int argc, char ** argv,
     else if (argc - 1 == 1) {
         if (streq(argv[1], "-"))
             cmdlineP->inputFilename = NULL;  /* he wants stdin */
-        else 
+        else
             cmdlineP->inputFilename = strdup(argv[1]);
-    } else 
+    } else
         pm_error("Too many arguments.  The only argument accepted "
                  "is the input file specification");
 
-    if (cmdlineP->alphaout && 
+    if (cmdlineP->alphaout &&
         streq(cmdlineP->alphaout, "-"))
         cmdlineP->alphaStdout = TRUE;
-    else 
+    else
         cmdlineP->alphaStdout = FALSE;
 }
 
@@ -144,7 +144,7 @@ parseCommandLine(int argc, char ** argv,
 
 static void
 reportRleGetSetupError(int const rleGetSetupRc) {
-    
+
     switch (rleGetSetupRc) {
     case -1:
         pm_error("According to the URT library, the input is not "
@@ -168,7 +168,7 @@ reportRleGetSetupError(int const rleGetSetupRc) {
 
 
 
-static void 
+static void
 readRleHeader(FILE * const ifP,
               bool   const headerDump) {
 
@@ -256,7 +256,7 @@ readRleHeader(FILE * const ifP,
 
 
 
-static void 
+static void
 writePpmRaster(FILE * const imageoutFileP,
                FILE * const alphaFileP) {
 
@@ -264,7 +264,7 @@ writePpmRaster(FILE * const imageoutFileP,
     pixval r, g, b;
     pixel *pixelrow;
     gray *alpharow;
-   
+
     int scan;
     int x;
     /*
@@ -274,11 +274,15 @@ writePpmRaster(FILE * const imageoutFileP,
     alpharow = pgm_allocrow(width);
 
     MALLOCARRAY(scanlines, height);
-    RLE_CHECK_ALLOC( hdr.cmd, scanlines, "scanline pointers" );
+    if (!scanlines)
+        pm_error("Failed to allocate memory for %u scanline pointers", height);
 
-    for ( scan = 0; scan < height; scan++ )
-        RLE_CHECK_ALLOC( hdr.cmd, (rle_row_alloc(&hdr, &scanlines[scan]) >= 0),
-                         "pixel memory" );
+    for (scan = 0; scan < height; ++scan) {
+        int rc;
+        rc = rle_row_alloc(&hdr, &scanlines[scan]);
+        if (rc < 0)
+            pm_error("Failed to allocate memory for a scanline");
+    }
     /*
      * Loop through those scan lines.
      */
@@ -295,7 +299,7 @@ writePpmRaster(FILE * const imageoutFileP,
                 PPM_ASSIGN(pixelrow[x], r, g, b);
                 if (hdr.alpha)
                     alpharow[x] = scanline[-1][x];
-                else 
+                else
                     alpharow[x] = 0;
             }
             break;
@@ -305,7 +309,7 @@ writePpmRaster(FILE * const imageoutFileP,
                 g = colormap[scanline[1][x]+256]>>8;
                 b = colormap[scanline[2][x]+512]>>8;
                 PPM_ASSIGN(pixelrow[x], r, g, b);
-                if (hdr.alpha) 
+                if (hdr.alpha)
                     alpharow[x] = colormap[scanline[-1][x]];
                 else
                     alpharow[x] = 0;
@@ -329,7 +333,7 @@ writePpmRaster(FILE * const imageoutFileP,
                 g = colormap[scanline[0][x]+256]>>8;
                 b = colormap[scanline[0][x]+512]>>8;
                 PPM_ASSIGN(pixelrow[x], r, g, b);
-                if (hdr.alpha) 
+                if (hdr.alpha)
                     alpharow[x] = colormap[scanline[-1][x]];
                 else
                     alpharow[x] = 0;
@@ -341,7 +345,7 @@ writePpmRaster(FILE * const imageoutFileP,
         /*
          * Write the scan line.
          */
-        if (imageoutFileP) 
+        if (imageoutFileP)
             ppm_writeppmrow(imageoutFileP, pixelrow, width, RLE_MAXVAL, 0);
         if (alphaFileP)
             pgm_writepgmrow(alphaFileP, alpharow, width, RLE_MAXVAL, 0);
@@ -358,7 +362,7 @@ writePpmRaster(FILE * const imageoutFileP,
 
 
 
-static void 
+static void
 writePgmRaster(FILE * const imageoutFileP,
                FILE * const alphaFileP) {
 /*----------------------------------------------------------------------------
@@ -375,11 +379,15 @@ writePgmRaster(FILE * const imageoutFileP,
     alpharow = pgm_allocrow(width);
 
     MALLOCARRAY(scanlines, height);
-    RLE_CHECK_ALLOC( hdr.cmd, scanlines, "scanline pointers" );
+    if (!scanlines)
+        pm_error("Failed to allocate memory for %u scanline pointers", height);
 
-    for (scan = 0; scan < height; ++scan)
-        RLE_CHECK_ALLOC(hdr.cmd, (rle_row_alloc(&hdr, &scanlines[scan]) >= 0),
-                        "pixel memory" );
+    for (scan = 0; scan < height; ++scan) {
+        int rc;
+        rc = rle_row_alloc(&hdr, &scanlines[scan]);
+        if (rc < 0)
+            pm_error("Failed to allocate memory for a scanline");
+    }
     /*
      * Loop through those scan lines.
      */
@@ -391,12 +399,12 @@ writePgmRaster(FILE * const imageoutFileP,
         scanline = scanlines[scan];
         for (x = 0; x < width; ++x) {
             pixelrow[x] = scanline[0][x];
-            if (hdr.alpha) 
+            if (hdr.alpha)
                 alpharow[x] = scanline[1][x];
             else
                 alpharow[x] = 0;
         }
-        if (imageoutFileP) 
+        if (imageoutFileP)
             pgm_writepgmrow(imageoutFileP, pixelrow, width, RLE_MAXVAL, 0);
         if (alphaFileP)
             pgm_writepgmrow(alphaFileP, alpharow, width, RLE_MAXVAL, 0);
@@ -428,20 +436,20 @@ main(int argc, char ** argv) {
 
     fname = NULL;  /* initial value */
 
-    if (cmdline.inputFilename != NULL ) 
+    if (cmdline.inputFilename != NULL )
         ifP = pm_openr(cmdline.inputFilename);
     else
         ifP = stdin;
 
     if (cmdline.alphaStdout)
         alphaFileP = stdout;
-    else if (cmdline.alphaout == NULL) 
+    else if (cmdline.alphaout == NULL)
         alphaFileP = NULL;
     else {
         alphaFileP = pm_openw(cmdline.alphaout);
     }
 
-    if (cmdline.alphaStdout) 
+    if (cmdline.alphaStdout)
         imageoutFileP = NULL;
     else
         imageoutFileP = stdout;
@@ -461,7 +469,7 @@ main(int argc, char ** argv) {
     if (cmdline.headerdump)
         exit(0);
 
-    /* 
+    /*
      * Write the alpha file header
      */
     if (alphaFileP)
@@ -486,9 +494,9 @@ main(int argc, char ** argv) {
         writePpmRaster(imageoutFileP, alphaFileP);
         break;
     }
-   
+
     pm_close(ifP);
-    if (imageoutFileP) 
+    if (imageoutFileP)
         pm_close(imageoutFileP);
     if (alphaFileP)
         pm_close(alphaFileP);
diff --git a/converter/other/sunicontopnm.c b/converter/other/sunicontopnm.c
index db26663e..93ddc0ab 100644
--- a/converter/other/sunicontopnm.c
+++ b/converter/other/sunicontopnm.c
@@ -30,9 +30,9 @@
 
 
 static void
-ReadIconFileHeader(FILE * const file, 
-                   int *  const widthP, 
-                   int *  const heightP, 
+ReadIconFileHeader(FILE * const file,
+                   int *  const widthP,
+                   int *  const heightP,
                    int *  const depthP,
                    int *  const bitsPerItemP) {
 
@@ -51,7 +51,7 @@ ReadIconFileHeader(FILE * const file,
                 ch == ' ')
             ;
         for (i = 0;
-             ch != '=' && ch != ',' && ch != '\n' && ch != '\t' && 
+             ch != '=' && ch != ',' && ch != '\n' && ch != '\t' &&
                  ch != ' ' && (i < (sizeof(variable) - 1));
              ++i) {
             variable[i] = ch;
@@ -84,7 +84,7 @@ ReadIconFileHeader(FILE * const file,
         } else if (streq(variable, "Valid_bits_per_item")) {
             if (value != 16 && value !=32)
                 pm_error("invalid Valid_bits_per_item");
-            *bitsPerItemP = value; 
+            *bitsPerItemP = value;
             ++fieldCt;
         }
     }
@@ -165,7 +165,7 @@ main(int argc, const char ** argv) {
                 else
                     grayrow[colChar] = data;
             } else
-                pm_error("error scanning bits item %u" , colChar);
+                pm_error("error scanning bits item %u", colChar);
         }
 
         /* output row */
diff --git a/converter/other/tifftopnm.c b/converter/other/tifftopnm.c
index c1e7af85..0c301a4a 100644
--- a/converter/other/tifftopnm.c
+++ b/converter/other/tifftopnm.c
@@ -24,16 +24,16 @@
 /* Design note:
 
    We have two different ways of converting from Tiff, as provided by the
-   Tiff library:  
+   Tiff library:
 
    1) decode the entire image into memory at once, using
       TIFFRGBAImageGet(), then convert to PNM and output row by row.
-   
+
    2) read, convert, and output one row at a time using TIFFReadScanline().
 
    (1) is preferable because the Tiff library does more of the work, which
-   means it understands more of the Tiff format possibilities now and in 
-   the future.  Also, some compressed TIFF formats don't allow you to 
+   means it understands more of the Tiff format possibilities now and in
+   the future.  Also, some compressed TIFF formats don't allow you to
    extract an individual row.
 
    (2) uses far less memory, and because our code does more of the work,
@@ -117,17 +117,17 @@ parseCommandLine(int argc, const char ** const argv,
     opt.allowNegNum = FALSE;
 
     option_def_index = 0;   /* incremented by OPTENT3 */
-    OPTENT3(0, "verbose", 
+    OPTENT3(0, "verbose",
             OPT_FLAG,   NULL, &cmdlineP->verbose,              0);
-    OPTENT3(0, "respectfillorder", 
+    OPTENT3(0, "respectfillorder",
             OPT_FLAG,   NULL, &cmdlineP->respectfillorder,     0);
-    OPTENT3(0,   "byrow",   
+    OPTENT3(0,   "byrow",
             OPT_FLAG,   NULL, &cmdlineP->byrow,                0);
-    OPTENT3(0,   "orientraw",   
+    OPTENT3(0,   "orientraw",
             OPT_FLAG,   NULL, &cmdlineP->orientraw,            0);
-    OPTENT3('h', "headerdump", 
+    OPTENT3('h', "headerdump",
             OPT_FLAG,   NULL, &cmdlineP->headerdump,           0);
-    OPTENT3(0,   "alphaout",   
+    OPTENT3(0,   "alphaout",
             OPT_STRING, &cmdlineP->alphaFilename, &alphaSpec,  0);
 
     pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
@@ -136,7 +136,7 @@ parseCommandLine(int argc, const char ** const argv,
         cmdlineP->inputFilename = strdup("-");  /* he wants stdin */
     else if (argc - 1 == 1)
         cmdlineP->inputFilename = strdup(argv[1]);
-    else 
+    else
         pm_error("Too many arguments.  The only argument accepted "
                  "is the input file name");
 
@@ -309,11 +309,11 @@ validatePlanarConfig(unsigned short const planarconfig,
     case PLANARCONFIG_CONTIG:
         break;
     case PLANARCONFIG_SEPARATE:
-        if (photomet != PHOTOMETRIC_RGB && 
+        if (photomet != PHOTOMETRIC_RGB &&
             photomet != PHOTOMETRIC_SEPARATED)
             pm_error("This program can handle separate planes only "
                      "with RGB (PHOTOMETRIC tag = %u) or SEPARATED "
-                     "(PHOTOMETRIC tag = %u) data.  The input Tiff file " 
+                     "(PHOTOMETRIC tag = %u) data.  The input Tiff file "
                      "has PHOTOMETRIC tag = %hu.",
                      PHOTOMETRIC_RGB, PHOTOMETRIC_SEPARATED,
                      photomet);
@@ -351,7 +351,7 @@ dumpHeader(const struct tiffDirInfo * const headerP) {
 
 
 
-static void 
+static void
 readDirectory(TIFF *               const tiffP,
               bool                 const headerdump,
               struct tiffDirInfo * const headerP) {
@@ -409,11 +409,11 @@ readDirectory(TIFF *               const tiffP,
 
 
 static void
-readscanline(TIFF *          const tif, 
+readscanline(TIFF *          const tif,
              unsigned char * const scanbuf,
-             int             const row, 
+             int             const row,
              int             const plane,
-             unsigned int    const cols, 
+             unsigned int    const cols,
              unsigned short  const bps,
              unsigned short  const spp,
              unsigned short  const fillorder,
@@ -433,7 +433,7 @@ readscanline(TIFF *          const tif,
 
     /* 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 
+       input to TIFFWriteScanline.  The man page for that doesn't say
        anything either, but the source code for Pamtotiff contains a
        specification.
     */
@@ -446,7 +446,7 @@ readscanline(TIFF *          const tif,
                   row, plane);
     else if (bps == 8) {
         unsigned int sample;
-        for (sample = 0; sample < cols * spp; ++sample) 
+        for (sample = 0; sample < cols * spp; ++sample)
             samplebuf[sample] = scanbuf[sample];
     } else if (bps < 8) {
         /* Note that in this format, samples do not span bytes.  Rather,
@@ -458,26 +458,26 @@ readscanline(TIFF *          const tif,
         unsigned int bitsleft;
         unsigned char * inP;
 
-        for (sample = 0, bitsleft = 8, inP = scanbuf; 
-             sample < cols * spp; 
+        for (sample = 0, bitsleft = 8, inP = scanbuf;
+             sample < cols * spp;
              ++sample) {
             if (bitsleft == 0) {
-                ++inP; 
+                ++inP;
                 bitsleft = 8;
-            } 
+            }
             switch (fillorder) {
             case FILLORDER_MSB2LSB:
-                samplebuf[sample] = (*inP >> (bitsleft-bps)) & bpsmask; 
+                samplebuf[sample] = (*inP >> (bitsleft-bps)) & bpsmask;
                 break;
             case FILLORDER_LSB2MSB:
                 samplebuf[sample] = (*inP >> (8-bitsleft)) & bpsmask;
                 break;
             default:
-                pm_error("Internal error: invalid value for fillorder: %u", 
+                pm_error("Internal error: invalid value for fillorder: %u",
                          fillorder);
             }
             assert(bitsleft >= bps);
-            bitsleft -= bps; 
+            bitsleft -= bps;
             if (bitsleft < bps)
                 /* Don't count dregs at end of byte */
                 bitsleft = 0;
@@ -490,7 +490,7 @@ readscanline(TIFF *          const tif,
            none of our concern).  The pre-9.17 code also presumed that
            the TIFF "FILLORDER" tag determined the order in which the
            bytes of each sample appear in a TIFF file, which is
-           contrary to the TIFF spec.  
+           contrary to the TIFF spec.
         */
         const uint16 * const scanbuf16 = (const uint16 *) scanbuf;
         unsigned int sample;
@@ -500,10 +500,10 @@ readscanline(TIFF *          const tif,
     } else if (bps == 32) {
         const uint32 * const scanbuf32 = (const uint32 *) scanbuf;
         unsigned int sample;
-        
+
         for (sample = 0; sample < cols * spp; ++sample)
             samplebuf[sample] = scanbuf32[sample];
-    } else 
+    } else
         pm_error("Internal error: invalid bits per sample passed to "
                  "readscanline()");
 }
@@ -528,7 +528,7 @@ pick_cmyk_pixel(unsigned int const samplebuf[],
     unsigned int const y = samplebuf[sampleCursor + 2];
     unsigned int const k = samplebuf[sampleCursor + 3];
 
-    /* The CMYK->RGB formula used by TIFFRGBAImageGet() in the TIFF 
+    /* The CMYK->RGB formula used by TIFFRGBAImageGet() in the TIFF
        library is the following, (with some apparent confusion with
        the names of the yellow and magenta pigments being reversed).
 
@@ -539,9 +539,9 @@ pick_cmyk_pixel(unsigned int const samplebuf[],
        We used that too before Netpbm 10.21 (March 2004).
 
        Now we use the inverse of what Pnmtotiffcmyk has always used, which
-       makes sense as follows:  A microliter of black ink is simply a 
+       makes sense as follows:  A microliter of black ink is simply a
        substitute for a microliter each of cyan, magenta, and yellow ink.
-       Yellow ink removes blue light from what the white paper reflects.  
+       Yellow ink removes blue light from what the white paper reflects.
     */
 
     *redP = 255 - MIN(255, c + k);
@@ -552,16 +552,16 @@ pick_cmyk_pixel(unsigned int const samplebuf[],
 
 
 static void
-computeFillorder(unsigned short   const fillorderTag, 
-                 unsigned short * const fillorderP, 
+computeFillorder(unsigned short   const fillorderTag,
+                 unsigned short * const fillorderP,
                  bool             const respectfillorder) {
 
     if (respectfillorder) {
-        if (fillorderTag != FILLORDER_MSB2LSB && 
+        if (fillorderTag != FILLORDER_MSB2LSB &&
             fillorderTag != FILLORDER_LSB2MSB)
             pm_error("Invalid value in Tiff input for the FILLORDER tag: %u.  "
                      "Valid values are %u and %u.  Try omitting the "
-                     "-respectfillorder option.", 
+                     "-respectfillorder option.",
                      fillorderTag, FILLORDER_MSB2LSB, FILLORDER_LSB2MSB);
         else
             *fillorderP = fillorderTag;
@@ -577,12 +577,12 @@ computeFillorder(unsigned short   const fillorderTag,
 
 
 static void
-analyzeImageType(TIFF *             const tiffP, 
-                 unsigned short     const bps, 
-                 unsigned short     const spp, 
+analyzeImageType(TIFF *             const tiffP,
+                 unsigned short     const bps,
+                 unsigned short     const spp,
                  unsigned short     const photomet,
-                 xelval *           const maxvalP, 
-                 int *              const formatP, 
+                 xelval *           const maxvalP,
+                 int *              const formatP,
                  xel *              const colormap,
                  bool               const headerdump,
                  struct CmdlineInfo const cmdline) {
@@ -604,13 +604,13 @@ analyzeImageType(TIFF *             const tiffP,
         *maxvalP = pm_bitstomaxval(MIN(bps, 16));
 
         if (headerdump)
-            pm_message("grayscale image, (min=%s) output maxval %u ", 
-                       photomet == PHOTOMETRIC_MINISBLACK ? 
+            pm_message("grayscale image, (min=%s) output maxval %u ",
+                       photomet == PHOTOMETRIC_MINISBLACK ?
                        "black" : "white",
                        *maxvalP
                 );
         break;
-            
+
     case PHOTOMETRIC_PALETTE: {
         int fldPresent;
         int i;
@@ -627,7 +627,7 @@ analyzeImageType(TIFF *             const tiffP,
                      "We understand only 1.", spp);
 
         fldPresent = TIFFGetField(
-            tiffP, TIFFTAG_COLORMAP, 
+            tiffP, TIFFTAG_COLORMAP,
             &redcolormap, &greencolormap, &bluecolormap);
 
         if (!fldPresent)
@@ -662,7 +662,7 @@ analyzeImageType(TIFF *             const tiffP,
         if (fldPresent && inkset != INKSET_CMYK)
             pm_error("This color separation file uses an inkset (%d) "
                      "we can't handle.  We handle only CMYK.", inkset);
-        if (spp != 4) 
+        if (spp != 4)
             pm_error("This CMYK color separation file is %d samples per "
                      "pixel.  "
                      "We need 4 samples, though: C, M, Y, and K.  ",
@@ -673,7 +673,7 @@ analyzeImageType(TIFF *             const tiffP,
         *maxvalP = (1 << bps) - 1;
     }
         break;
-            
+
     case PHOTOMETRIC_RGB:
         if (headerdump)
             pm_message("RGB truecolor");
@@ -704,7 +704,7 @@ analyzeImageType(TIFF *             const tiffP,
 
     case PHOTOMETRIC_LOGLUV:
         pm_error("don't know how to handle PHOTOMETRIC_LOGLUV");
-            
+
     default:
         pm_error("unknown photometric: %d", photomet);
     }
@@ -778,7 +778,7 @@ 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,
+   to change a raster from orientation 'tiffOrientation' to Row 0 top,
    Column 0 left.
 -----------------------------------------------------------------------------*/
     switch (tiffOrientation) {
@@ -829,7 +829,7 @@ spawnWithInputPipe(const char *  const shellCmd,
 
                 *pidP   = childPid;
                 *pipePP = fdopen(fd[PIPE_WRITE], "w");
-                
+
                 if (*pipePP == NULL)
                     pm_asprintf(errorP,"Unable to create stream from pipe.  "
                                 "fdopen() fails with errno=%d (%s)",
@@ -858,7 +858,7 @@ spawnWithInputPipe(const char *  const shellCmd,
     }
 }
 
-                  
+
 
 static void
 createFlipProcess(FILE *         const outFileP,
@@ -964,7 +964,7 @@ setupFlipper(pnmOut *       const pnmOutP,
             pnmOutP->flipping = FALSE;
             *flipOkP   = FALSE;
             *noflipOkP = TRUE;
-        } else {            
+        } else {
             if (flipIfNeeded) {
                 if (verbose)
                     pm_message("Transforming raster with Pamflip");
@@ -979,7 +979,7 @@ setupFlipper(pnmOut *       const pnmOutP,
                                       verbose,
                                       &pnmOutP->imagePipeP,
                                       &pnmOutP->imageFlipPid);
-                
+
                 /* The stream will flip it, so Caller must not: */
                 pnmOutP->flipping = TRUE;
                 *flipOkP   = FALSE;
@@ -1081,22 +1081,22 @@ pnmOut_init(FILE *         const imageoutFileP,
     } else {
         pnmOutP->inCols = pnmOutP->outCols;  /* Caller will flip */
         pnmOutP->inRows = pnmOutP->outRows;
-    }    
+    }
     if (pnmOutP->flipping) {
-        if (pnmOutP->imagePipeP != NULL) 
+        if (pnmOutP->imagePipeP != NULL)
             pnm_writepnminit(pnmOutP->imagePipeP,
                              pnmOutP->inCols, pnmOutP->inRows,
                              pnmOutP->maxval, pnmOutP->format, 0);
-        if (pnmOutP->alphaPipeP != NULL) 
+        if (pnmOutP->alphaPipeP != NULL)
             pgm_writepgminit(pnmOutP->alphaPipeP,
                              pnmOutP->inCols, pnmOutP->inRows,
                              pnmOutP->alphaMaxval, 0);
     } else {
-        if (imageoutFileP != NULL) 
+        if (imageoutFileP != NULL)
             pnm_writepnminit(pnmOutP->imageoutFileP,
                              pnmOutP->outCols, pnmOutP->outRows,
                              pnmOutP->maxval, pnmOutP->format, 0);
-        if (alphaFileP != NULL) 
+        if (alphaFileP != NULL)
             pgm_writepgminit(pnmOutP->alphaFileP,
                              pnmOutP->outCols, pnmOutP->outRows,
                              pnmOutP->alphaMaxval, 0);
@@ -1149,19 +1149,19 @@ pnmOut_writeRow(pnmOut *     const pnmOutP,
     assert(cols == pnmOutP->inCols);
 
     if (pnmOutP->flipping) {
-        if (pnmOutP->imagePipeP != NULL) 
+        if (pnmOutP->imagePipeP != NULL)
             pnm_writepnmrow(pnmOutP->imagePipeP, (xel *)imageRow,
                             pnmOutP->inCols, pnmOutP->maxval,
                             pnmOutP->format, 0);
-        if (pnmOutP->alphaPipeP != NULL) 
+        if (pnmOutP->alphaPipeP != NULL)
             pgm_writepgmrow(pnmOutP->alphaPipeP, alphaRow,
                             pnmOutP->inCols, pnmOutP->alphaMaxval, 0);
     } else {
-        if (pnmOutP->imageoutFileP != NULL) 
+        if (pnmOutP->imageoutFileP != NULL)
             pnm_writepnmrow(pnmOutP->imageoutFileP, (xel *)imageRow,
                             pnmOutP->outCols, pnmOutP->maxval,
                             pnmOutP->format, 0);
-        if (pnmOutP->alphaFileP != NULL) 
+        if (pnmOutP->alphaFileP != NULL)
             pgm_writepgmrow(pnmOutP->alphaFileP, alphaRow,
                             pnmOutP->outCols, pnmOutP->alphaMaxval, 0);
     }
@@ -1170,12 +1170,12 @@ pnmOut_writeRow(pnmOut *     const pnmOutP,
 
 
 static void
-convertRow(unsigned int   const samplebuf[], 
-           xel *          const xelrow, 
+convertRow(unsigned int   const samplebuf[],
+           xel *          const xelrow,
            gray *         const alpharow,
-           int            const cols, 
-           xelval         const maxval, 
-           unsigned short const photomet, 
+           int            const cols,
+           xelval         const maxval,
+           unsigned short const photomet,
            unsigned short const spp,
            xel            const colormap[]) {
 /*----------------------------------------------------------------------------
@@ -1191,7 +1191,7 @@ convertRow(unsigned int   const samplebuf[],
         }
     }
     break;
-    
+
     case PHOTOMETRIC_MINISWHITE: {
         int col;
         for (col = 0; col < cols; ++col) {
@@ -1220,7 +1220,7 @@ convertRow(unsigned int   const samplebuf[],
         for (col = 0, sample = 0; col < cols; ++col, sample+=spp) {
             xelval r, g, b;
             pick_cmyk_pixel(samplebuf, sample, &r, &b, &g);
-            
+
             PPM_ASSIGN(xelrow[col], r, g, b);
             alpharow[col] = 0;
         }
@@ -1238,7 +1238,7 @@ convertRow(unsigned int   const samplebuf[],
                 alpharow[col] = 0;
         }
         break;
-    }       
+    }
     default:
         pm_error("internal error:  unknown photometric in the picking "
                  "routine: %d", photomet);
@@ -1257,7 +1257,7 @@ scale32to16(unsigned int * const samplebuf,
 -----------------------------------------------------------------------------*/
     unsigned int i;
     for (i = 0; i < cols * spp; ++i)
-        samplebuf[i] >>= 16; 
+        samplebuf[i] >>= 16;
 }
 
 
@@ -1288,39 +1288,39 @@ convertMultiPlaneRow(TIFF *          const tif,
         unsigned int col;
 
         /* First, clear the buffer so we can add red, green,
-           and blue one at a time.  
+           and blue one at a time.
         */
-        for (col = 0; col < cols; ++col) 
+        for (col = 0; col < cols; ++col)
             PPM_ASSIGN(xelrow[col], 0, 0, 0);
 
         /* Read the reds */
-        readscanline(tif, scanbuf, row, 0, cols, bps, spp, fillorder, 
+        readscanline(tif, scanbuf, row, 0, cols, bps, spp, fillorder,
                      samplebuf);
         if (bps == 32)
             scale32to16(samplebuf, cols, spp);
-        for (col = 0; col < cols; ++col) 
+        for (col = 0; col < cols; ++col)
             PPM_PUTR(xelrow[col], samplebuf[col]);
-                
+
         /* Next the greens */
         readscanline(tif, scanbuf, row, 1, cols, bps, spp, fillorder,
                      samplebuf);
         if (bps == 32)
             scale32to16(samplebuf, cols, spp);
-        for (col = 0; col < cols; ++col) 
+        for (col = 0; col < cols; ++col)
             PPM_PUTG( xelrow[col], samplebuf[col] );
-            
+
         /* And finally the blues */
         readscanline(tif, scanbuf, row, 2, cols, bps, spp, fillorder,
                      samplebuf);
         if (bps == 32)
             scale32to16(samplebuf, cols, spp);
-        for (col = 0; col < cols; ++col) 
+        for (col = 0; col < cols; ++col)
             PPM_PUTB(xelrow[col], samplebuf[col]);
 
         /* Could there be an alpha plane?  (We assume no.  But if so,
-           here is where to read it) 
+           here is where to read it)
         */
-        for (col = 0; col < cols; ++col) 
+        for (col = 0; col < cols; ++col)
             alpharow[col] = 0;
     }
 }
@@ -1329,11 +1329,11 @@ convertMultiPlaneRow(TIFF *          const tif,
 
 static void
 convertRasterByRows(pnmOut *       const pnmOutP,
-                    unsigned int   const cols, 
+                    unsigned int   const cols,
                     unsigned int   const rows,
                     xelval         const maxval,
                     TIFF *         const tif,
-                    unsigned short const photomet, 
+                    unsigned short const photomet,
                     unsigned short const planarconfig,
                     unsigned short const bps,
                     unsigned short const spp,
@@ -1341,7 +1341,7 @@ convertRasterByRows(pnmOut *       const pnmOutP,
                     xel            const colormap[],
                     bool           const verbose) {
 /*----------------------------------------------------------------------------
-   With the TIFF header all processed (and relevant information from it in 
+   With the TIFF header all processed (and relevant information from it in
    our arguments), write out the TIFF raster to the Netpbm output files
    as described by *pnmOutP.
 
@@ -1357,10 +1357,10 @@ convertRasterByRows(pnmOut *       const pnmOutP,
            represented as single array element, so it's easy to work with.
         */
     xel * xelrow;
-        /* The ppm-format row of the image row we are presently converting */
+        /* The ppm-format row of the image row we are currently converting */
     gray * alpharow;
-        /* The pgm-format row representing the alpha values for the image 
-           row we are presently converting.
+        /* The pgm-format row representing the alpha values for the image
+           row we are currently converting.
         */
 
     unsigned int row;
@@ -1383,13 +1383,13 @@ convertRasterByRows(pnmOut *       const pnmOutP,
         /* Read one row of samples into samplebuf[] */
 
         if (planarconfig == PLANARCONFIG_CONTIG) {
-            readscanline(tif, scanbuf, row, 0, cols, bps, spp, fillorder, 
+            readscanline(tif, scanbuf, row, 0, cols, bps, spp, fillorder,
                          samplebuf);
             if (bps == 32)
                 scale32to16(samplebuf, cols, spp);
-            convertRow(samplebuf, xelrow, alpharow, cols, maxval, 
+            convertRow(samplebuf, xelrow, alpharow, cols, maxval,
                        photomet, spp, colormap);
-        } else 
+        } else
             convertMultiPlaneRow(tif, xelrow, alpharow, cols, maxval, row,
                                  photomet, bps, spp, fillorder,
                                  scanbuf, samplebuf);
@@ -1401,7 +1401,7 @@ convertRasterByRows(pnmOut *       const pnmOutP,
 
     free(samplebuf);
     free(scanbuf);
-}    
+}
 
 
 
@@ -1416,7 +1416,7 @@ warnBrokenTiffLibrary(TIFF * const tiffP) {
    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.
@@ -1452,8 +1452,8 @@ warnBrokenTiffLibrary(TIFF * const tiffP) {
 
 
 
-static void 
-convertTiffRaster(uint32 *        const raster, 
+static void
+convertTiffRaster(uint32 *        const raster,
                   unsigned int    const cols,
                   unsigned int    const rows,
                   xelval          const maxval,
@@ -1465,11 +1465,11 @@ convertTiffRaster(uint32 *        const raster,
 -----------------------------------------------------------------------------*/
     xel * xelrow;
         /* The ppm-format row of the image row we are
-           presently converting 
+           currently converting
         */
     gray * alpharow;
         /* The pgm-format row representing the alpha values
-           for the image row we are presently converting.  
+           for the image row we are currently converting.
         */
     unsigned int row;
 
@@ -1477,35 +1477,35 @@ convertTiffRaster(uint32 *        const raster,
     alpharow = pgm_allocrow(cols);
 
     for (row = 0; row < rows; ++row) {
-        uint32 * rp;  
-            /* Address of pixel in 'raster' we are presently converting */
+        uint32 * rp;
+            /* Address of pixel in 'raster' we are currently converting */
         unsigned int col;
 
         /* Start at beginning of row: */
         rp = raster + (rows - row - 1) * cols;
-    
+
         for (col = 0; col < cols; ++col) {
             uint32 const tiffPixel = *rp++;
-                    
-            PPM_ASSIGN(xelrow[col], 
-                       TIFFGetR(tiffPixel) * maxval / 255, 
-                       TIFFGetG(tiffPixel) * maxval / 255, 
+
+            PPM_ASSIGN(xelrow[col],
+                       TIFFGetR(tiffPixel) * maxval / 255,
+                       TIFFGetG(tiffPixel) * maxval / 255,
                        TIFFGetB(tiffPixel) * maxval / 255);
             alpharow[col] = TIFFGetA(tiffPixel) * maxval / 255 ;
         }
         pnmOut_writeRow(pnmOutP, cols, xelrow, alpharow);
     }
-    
+
     pgm_freerow(alpharow);
     pnm_freerow(xelrow);
-}    
+}
 
 
 
 enum convertDisp {CONV_DONE,
                   CONV_OOM,
                   CONV_UNABLE,
-                  CONV_FAILED, 
+                  CONV_FAILED,
                   CONV_NOTATTEMPTED};
 
 
@@ -1524,7 +1524,7 @@ convertRasterIntoProvidedMemory(pnmOut *           const pnmOutP,
     TIFFRGBAImage img;
     char emsg[1024];
     int ok;
-                
+
     ok = TIFFRGBAImageBegin(&img, tif, stopOnErrorFalse, emsg);
     if (!ok) {
         pm_message("%s", emsg);
@@ -1540,7 +1540,7 @@ convertRasterIntoProvidedMemory(pnmOut *           const pnmOutP,
             *statusP = CONV_DONE;
             convertTiffRaster(raster, cols, rows, maxval, pnmOutP);
         }
-    } 
+    }
 }
 
 
@@ -1584,7 +1584,7 @@ convertRasterInMemory(pnmOut *           const pnmOutP,
         unsigned int cols, rows;  /* Dimensions of output image */
         getTiffDimensions(tif, &cols, &rows);
 
-        if (rows == 0 || cols == 0) 
+        if (rows == 0 || cols == 0)
             *statusP = CONV_DONE;
         else {
             if (cols > UINT_MAX/rows) {
@@ -1608,7 +1608,7 @@ convertRasterInMemory(pnmOut *           const pnmOutP,
                     convertRasterIntoProvidedMemory(
                         pnmOutP, cols, rows, maxval, tif, verbose,
                         raster, statusP);
-                    
+
                     free(raster);
                 }
             }
@@ -1653,7 +1653,7 @@ convertRaster(pnmOut *           const pnmOutP,
                          "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,
@@ -1681,7 +1681,7 @@ convertImage(TIFF *             const tifP,
 
     computeFillorder(tiffDir.fillorder, &fillorder, cmdline.respectfillorder);
 
-    analyzeImageType(tifP, tiffDir.bps, tiffDir.spp, tiffDir.photomet, 
+    analyzeImageType(tifP, tiffDir.bps, tiffDir.spp, tiffDir.photomet,
                      &maxval, &format, colormap, cmdline.headerdump, cmdline);
 
     reportOutputFormat(format);
@@ -1704,7 +1704,7 @@ convertImage(TIFF *             const tifP,
 
 static void
 convertIt(TIFF *             const tifP,
-          FILE *             const alphaFile, 
+          FILE *             const alphaFile,
           FILE *             const imageoutFile,
           struct CmdlineInfo const cmdline) {
 
@@ -1744,19 +1744,19 @@ main(int argc, const char * argv[]) {
 
     if (cmdline.alphaStdout)
         alphaFile = stdout;
-    else if (cmdline.alphaFilename == NULL) 
+    else if (cmdline.alphaFilename == NULL)
         alphaFile = NULL;
     else
         alphaFile = pm_openw(cmdline.alphaFilename);
 
-    if (cmdline.alphaStdout) 
+    if (cmdline.alphaStdout)
         imageoutFile = NULL;
     else
         imageoutFile = stdout;
 
     convertIt(tiffP, alphaFile, imageoutFile, cmdline);
 
-    if (imageoutFile != NULL) 
+    if (imageoutFile != NULL)
         pm_close( imageoutFile );
     if (alphaFile != NULL)
         pm_close( alphaFile );
@@ -1770,3 +1770,6 @@ main(int argc, const char * argv[]) {
     */
     return 0;
 }
+
+
+
diff --git a/converter/other/winicon.h b/converter/other/winicon.h
index 9ede01f5..e5c4aa89 100644
--- a/converter/other/winicon.h
+++ b/converter/other/winicon.h
@@ -65,8 +65,7 @@ typedef enum {
 
 } BiCompression;
 
-/*  PNG image structures  */
-#define PNG_HEADER { 0x89, 'P', 'N', 'G', '\r', '\n', 0x1A /* ^Z */, '\n' }
+#define PNG_SIGNATURE { 0x89, 'P', 'N', 'G', '\r', '\n', 0x1A /* ^Z */, '\n' }
 
 struct PngIhdr {
     uint32_t length;              /* 13 */
diff --git a/converter/other/winicontopam.c b/converter/other/winicontopam.c
index 69ce7f05..bb39bf60 100644
--- a/converter/other/winicontopam.c
+++ b/converter/other/winicontopam.c
@@ -1,3 +1,25 @@
+/*=============================================================================
+                             winicontopam
+===============================================================================
+  Convert from Windows icon format to PAM
+=============================================================================*/
+
+/*
+  Here are some references for the Windows icon format:
+
+  ICO (file format) - Wikipedia
+  https://en.wikipedia.org/wiki/ICO_(file_format)
+
+  ICO - Just Solve the File Format Problem
+  http://fileformats.archiveteam.org/wiki/ICO
+  (Has links to example icon file collections)
+
+  GFF Format Summary: Microsoft Windows Cursor and Icon
+  https://web.archive.org/web/20050421161512/http:/www.oreilly.com/www/centers/gff/formats/miccur/index.htm
+
+
+*/
+
 #include <assert.h>
 #include <stdio.h>
 #include <string.h>
@@ -25,7 +47,7 @@ static bool verbose;
 
 
 struct CmdlineInfo {
-    
+
     const char * inputFileName;
     unsigned int allimages;
     unsigned int imageSpec;
@@ -78,13 +100,13 @@ parseCommandLine(int argc, const char **argv,
             pm_error("Too many arguments.  The only possible "
                      "non-option argument is the input file name");
     }
-        
+
     free(option_def);
 }
 
 
 
-static unsigned char const pngHeader[] = PNG_HEADER;
+static unsigned char const pngSignature[] = PNG_SIGNATURE;
 
 
 
@@ -93,7 +115,7 @@ struct File {
     FILE *       fileP;
     const char * name;
     pm_filepos   pos;
-    
+
 };
 
 
@@ -122,7 +144,7 @@ static uint32_t
 u32_le(const unsigned char * const buf,
        size_t                const offset) {
 
-    return 
+    return
         ((uint32_t)buf[offset + 0] <<  0) +
         ((uint32_t)buf[offset + 1] <<  8) +
         ((uint32_t)buf[offset + 2] << 16) +
@@ -135,7 +157,7 @@ static uint32_t
 s32_le(const unsigned char * const buf,
        size_t                const offset) {
 
-    return 
+    return
         ((uint32_t)buf[offset + 0] <<  0) +
         ((uint32_t)buf[offset + 1] <<  8) +
         ((uint32_t)buf[offset + 2] << 16) +
@@ -156,8 +178,8 @@ u8_be(const unsigned char * const buf,
 static uint32_t
 u32_be(const unsigned char * const buf,
        size_t                const offset) {
-    
-    return 
+
+    return
         ((uint32_t)buf[offset + 0] << 24) +
         ((uint32_t)buf[offset + 1] << 16) +
         ((uint32_t)buf[offset + 2] <<  8) +
@@ -225,7 +247,7 @@ dumpIconDir(const struct IconDir * const dirP) {
     }
 }
 
-            
+
 
 static struct IconDir *
 readIconDir(struct File * const fP,
@@ -246,7 +268,7 @@ readIconDir(struct File * const fP,
     MALLOCVAR(dirP);
 
     if (dirP == NULL)
-        pm_error("Could't allocate memory for Icon directory");
+        pm_error("Couldn't allocate memory for Icon directory");
 
     MALLOCARRAY(dirP->entries, head.count);
 
@@ -271,7 +293,7 @@ readIconDir(struct File * const fP,
 
         pm_readcharu(fP->fileP, &heightField);
         dirEntryP->height = (heightField == 0 ? 256 : heightField);
-        
+
         pm_readcharu(fP->fileP, &dirEntryP->color_count);
 
         pm_readcharu(fP->fileP, &dirEntryP->zero);
@@ -290,7 +312,7 @@ readIconDir(struct File * const fP,
     }
 
     /* The following is paranoia code only:
-     
+
        I've never seen a windows icon file in the wild with having the entries
        in the directory stored in a different order than the images
        themselves.  However, the file format allows for it ...
@@ -301,7 +323,7 @@ readIconDir(struct File * const fP,
         pm_message("%s icon directory (%u image%s):",
                    fP->name,
                    dirP->count, dirP->count == 1 ? "" : "s");
-        
+
         for (imageIndex = 0; imageIndex < dirP->count; ++imageIndex) {
             const struct IconDirEntry * const dirEntryP =
                 &dirP->entries[imageIndex];
@@ -355,7 +377,7 @@ readImage(struct File *         const fP,
 
     /*  Don't try to read an image that is smaller than the
         BITMAPINFOHEADER of BMP images (40 bytes).
-     
+
         PNG compressed images can't be smaller than that either, as the
         PNG header plus the mandantory IHDR and IEND chunks already take
         8 + 25 + 12 = 35 bytes, and there is to be a IDAT chunk too.
@@ -369,7 +391,7 @@ readImage(struct File *         const fP,
                  dirEntryP->index);
 
     /* The following is paranoia code only:
-     
+
        I've never seen a windows icon file in the wild with gaps between
        the images, but the file format allows for it, and Microsoft
        expects the user to fseek() to the start of each image.
@@ -472,11 +494,11 @@ readXorPalette(struct BitmapInfoHeader * const hdrP,
     uint32_t    bytesPerRow;
     const unsigned char * bitmapCursor;
     uint32_t sizeRemaining;
-  
+
     uint8_t (*getIdx) (const unsigned char * bitmap,
                        uint32_t rowOffset,
                        int16_t col);
-  
+
     if (hdrP->compression_method != BI_RGB)
         pm_error("image %2u: invalid compression method %u.",
                  index, hdrP->compression_method);
@@ -518,7 +540,7 @@ readXorPalette(struct BitmapInfoHeader * const hdrP,
     if (sizeRemaining < paletteSize)
         pm_error("image %2u: "
                  "reading palette: image truncated.", index);
-    
+
     palette = (const PaletteEntry *) bitmapCursor;
 
     if (needHeaderDump)
@@ -562,7 +584,7 @@ readXorPalette(struct BitmapInfoHeader * const hdrP,
 
                 /*  The palette is an array of little-endian 32-bit values,
                     where the RGB value is encoded as follows:
-                 
+
                     red:   bits 2^16..2^23
                     green: bits 2^8 ..2^15
                     blue:  bits 2^0 ..2^7
@@ -591,7 +613,10 @@ readXorBitfields(struct BitmapInfoHeader * const hdrP,
                  uint16_t                  const index,
                  bool *                    const haveAlphaP,
                  uint32_t *                const bytesConsumedP) {
-
+/*----------------------------------------------------------------------------
+   Return as *haveAlphaP whether the Xor mask indicates the pixels are
+   anything but fully opaque.
+-----------------------------------------------------------------------------*/
     uint32_t   bitfields[4];
     uint8_t    shift    [4];
     sample     maxval   [4];
@@ -758,12 +783,21 @@ readXorBitfields(struct BitmapInfoHeader * const hdrP,
     bytesConsumed += truncatedXorSize;
 
     /*  A fully transparent alpha channel (all zero) in XOR mask is
-        defined to be void by Microsoft, and a fully opaque alpha
-        channel (all maxval) is trivial and will be dropped.
+        defined to be void by Microsoft.
     */
+    if (verbose) {
+        if (allTransparent)
+            pm_message("image %2u: All pixels are nominally coded in the "
+                       "transparency map as fully transparent, "
+                       "which is defined by the format to mean they "
+                       "are all opaque", index);
+        if (allOpaque)
+            pm_message("image %2u: All pixels are fully opaque "
+                       "in the transparency map", index);
+    }
     *haveAlphaP = !allTransparent && !allOpaque;
 
-    if (!allTransparent && verbose) {
+    if (!allTransparent && ! allOpaque && verbose) {
         unsigned int i;
         unsigned int c;
 
@@ -787,7 +821,16 @@ readAnd(struct BitmapInfoHeader * const hdrP,
         uint16_t                  const index,
         unsigned int              const plane,
         sample                    const maxval) {
+/*----------------------------------------------------------------------------
+  Fill in plane 'plane' of the tuple array 'tuples' according to the and
+  mask of a Windows icon.  Where the and mask for a pixel is 1, set the
+  plane to 'maxval'; where it is zero, set it to zero.
+
+  'bitmap' is the and mask, in a format describe dby *hdrP.
 
+  'index' is the position of the icon in question in the Windows icon file --
+  the first image in the file is 0, second is 1, etc.
+-----------------------------------------------------------------------------*/
     int16_t  row;
     uint32_t bytesConsumed;
     uint32_t bytesPerRow;
@@ -823,7 +866,7 @@ readAnd(struct BitmapInfoHeader * const hdrP,
 
         if (offset + bytesPerRow <= sizeRemaining) {
             unsigned int col;
-            
+
             for (col = 0; col < hdrP->bm_width; ++col) {
                 tuples[row][col][plane] =
                     ((u8_le(bitmap, offset + col/8)
@@ -916,7 +959,13 @@ readXorMask(struct BitmapInfoHeader * const hdrP,
             uint32_t *                const bytesConsumedP) {
 /*----------------------------------------------------------------------------
    Read the so-called XOR mask (for non-monochrome images, this is the
-   color pixmap)
+   color pixmap, which may include transparency).
+
+   Return the pixels as 'tuples', an array whose width and height are
+   given by *hdrP and depth is 4.
+
+   Return as *haveAlphaP whether the Xor mask indicates the pixels are
+   anything but fully opaque.
 -----------------------------------------------------------------------------*/
     /*  preset the PAM with fully opaque black (just in case the image
         is truncated and not all pixels are filled in below).
@@ -952,7 +1001,7 @@ reportImage(unsigned int            const imageIndex,
             struct BitmapInfoHeader const hdr,
             bool                    const haveAlpha) {
 
-    const char * const style = 
+    const char * const style =
         haveAlpha ? "RGB +alpha" :
         hdr.bits_per_pixel < 16 ? "RGB/palette" :
         "RGB"
@@ -973,7 +1022,7 @@ convertBmp(const unsigned char * const image,
            struct IconDirEntry * const dirEntryP,
            bool                  const needHeaderDump,
            bool                  const wantAndMaskPlane) {
-    
+
     struct BitmapInfoHeader hdr;
     uint32_t                offset;
     bool                    haveAlpha;
@@ -1024,7 +1073,7 @@ convertBmp(const unsigned char * const image,
 
     tuples = pnm_allocpamarray(&outpam);
 
-    readXorMask(&hdr, &image[offset], 
+    readXorMask(&hdr, &image[offset],
                 dirEntryP->size - offset,
                 tuples, dirEntryP->index, needHeaderDump,
                 &haveAlpha, &xorByteCt);
@@ -1032,9 +1081,9 @@ convertBmp(const unsigned char * const image,
     offset += xorByteCt;
 
     {
-        /* If there is no alpha channel in XOR mask, store the AND mask to
-           the transparency plane.  Else, here are two transparency
-           maps. If requested, store the AND mask to a fifth PAM plane
+        /* If there is no alpha channel in the XOR mask, use the AND mask as
+           the transparency plane.  Else, there are two transparency
+           maps. If requested, return the AND mask as a fifth PAM plane.
         */
         bool haveAnd;
         unsigned int andPlane;
@@ -1070,18 +1119,18 @@ convertBmp(const unsigned char * const image,
 static void
 reportPngInfo(const unsigned char * const image,
               struct IconDirEntry * const dirEntryP) {
-    
+
     struct PngIhdr ihdr;
 
-    ihdr.length      = u32_be (image, sizeof(pngHeader)  +0);
-    ihdr.signature   = u32_xx (image, sizeof(pngHeader)  +4);
-    ihdr.width       = u32_be (image, sizeof(pngHeader)  +8);
-    ihdr.height      = u32_be (image, sizeof(pngHeader) +12);
-    ihdr.bit_depth   = u8_be  (image, sizeof(pngHeader) +16);
-    ihdr.color_type  = u8_be  (image, sizeof(pngHeader) +17);
-    ihdr.compression = u8_be  (image, sizeof(pngHeader) +18);
-    ihdr.filter      = u8_be  (image, sizeof(pngHeader) +19);
-    ihdr.interlace   = u8_be  (image, sizeof(pngHeader) +20);
+    ihdr.length      = u32_be (image, sizeof(pngSignature)  +0);
+    ihdr.signature   = u32_xx (image, sizeof(pngSignature)  +4);
+    ihdr.width       = u32_be (image, sizeof(pngSignature)  +8);
+    ihdr.height      = u32_be (image, sizeof(pngSignature) +12);
+    ihdr.bit_depth   = u8_be  (image, sizeof(pngSignature) +16);
+    ihdr.color_type  = u8_be  (image, sizeof(pngSignature) +17);
+    ihdr.compression = u8_be  (image, sizeof(pngSignature) +18);
+    ihdr.filter      = u8_be  (image, sizeof(pngSignature) +19);
+    ihdr.interlace   = u8_be  (image, sizeof(pngSignature) +20);
 
     if ((ihdr.length != 13)
         || ihdr.signature != *(uint32_t*)"IHDR") {
@@ -1148,14 +1197,16 @@ convertPng(const unsigned char * const image,
            FILE *                const ofP,
            struct IconDirEntry * const dirEntryP) {
 
-    struct bufferDesc imageBuffer;
+    pm_bufferDesc imageBuffer;
 
     reportPngInfo(image, dirEntryP);
 
-    imageBuffer.size = dirEntryP->size;
-    imageBuffer.buffer = (unsigned char *)image;
+    imageBuffer.size              = dirEntryP->size;
+    imageBuffer.buffer            = (unsigned char *)image;
+    imageBuffer.bytesTransferredP = NULL;
+
+    fflush(stdout);
 
-    fflush (stdout);
     pm_system_lp("pngtopam", pm_feed_from_memory, &imageBuffer,
                  NULL /* stdout accepter */, NULL,
                  "pngtopam", "-alphapam", NULL);
@@ -1174,7 +1225,7 @@ bestImage(struct IconDir * const dirP) {
     bestPixelCt = 0;  /* initial value */
     bestColorCt = 0;  /* initial value */
     best        = 0;  /* initial value */
-    
+
     for (imageIndex = 0; dirP->count > imageIndex; ++imageIndex) {
         struct IconDirEntry * const dirEntryP = &dirP->entries[imageIndex];
 
@@ -1183,7 +1234,7 @@ bestImage(struct IconDir * const dirP) {
         uint32_t colorCt;
 
         /*  32-bit icons have 24 bit color information only.
-         
+
             Since NT 5.1 (aka WinXP), it is allowed to place 8-bit
             transparency information in the remaining bits (to check,
             you have to read all these bits in the image!), so I prefer
@@ -1222,7 +1273,7 @@ convertImage(struct File *         const icoP,
 
     image = readImage(icoP, dirEntryP);
 
-    if (MEMEQ(image, pngHeader, sizeof (pngHeader)))
+    if (memeq(image, pngSignature, sizeof (pngSignature)))
         convertPng(image, ofP, dirEntryP);
     else
         convertBmp(image, ofP, dirEntryP, needHeaderDump, wantAndMaskPlane);
@@ -1273,7 +1324,7 @@ main (int argc, const char *argv []) {
         convertImage(&ico, &dirP->entries[bestImage(dirP)], stdout,
                      cmdline.headerdump, cmdline.andmasks);
     }
-    
+
     freeIconDir(dirP);
 
     if (ico.fileP != stdin)
diff --git a/converter/other/xwdtopnm.c b/converter/other/xwdtopnm.c
index df3c7375..4eb16def 100644
--- a/converter/other/xwdtopnm.c
+++ b/converter/other/xwdtopnm.c
@@ -70,14 +70,14 @@ static unsigned int pixel_count = 0;
 static int
 zero_bits(const unsigned long mask) {
 /*----------------------------------------------------------------------------
-   Return the number of consective zero bits at the least significant end
+   Return the number of consecutive zero bits at the least significant end
    of the binary representation of 'mask'.  E.g. if mask == 0x00fff800,
    we would return 11.
 -----------------------------------------------------------------------------*/
     int i;
     unsigned long shifted_mask;
 
-    for (i=0, shifted_mask = mask; 
+    for (i=0, shifted_mask = mask;
          i < sizeof(mask)*8 && (shifted_mask & 0x00000001) == 0;
          i++, shifted_mask >>= 1 );
     return(i);
@@ -122,9 +122,9 @@ parseCommandLine(int argc, char ** argv,
     else if (argc - 1 == 1) {
         if (streq(argv[1], "-"))
             cmdlineP->inputFilename = NULL;  /* he wants stdin */
-        else 
+        else
             cmdlineP->inputFilename = strdup(argv[1]);
-    } else 
+    } else
         pm_error("Too many arguments.  The only argument accepted\n"
                  "is the input file specification");
 }
@@ -132,17 +132,17 @@ parseCommandLine(int argc, char ** argv,
 
 
 static void
-processX10Header(X10WDFileHeader *  const h10P, 
+processX10Header(X10WDFileHeader *  const h10P,
                  FILE *             const file,
-                 int *              const colsP, 
-                 int *              const rowsP, 
-                 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, 
+                 int *              const colsP,
+                 int *              const rowsP,
+                 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,
                  struct compMask *  const compMaskP,
                  enum byteorder *   const byte_orderP,
                  enum byteorder *   const bit_orderP) {
@@ -214,7 +214,7 @@ processX10Header(X10WDFileHeader *  const h10P,
             (((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;
@@ -314,8 +314,8 @@ dumpX11Cmap(unsigned int       const nColors,
 
     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, 
+        pm_message("Color %u r/g/b = %u/%u/%u", i,
+                   x11colors[i].red, x11colors[i].green,
                    x11colors[i].blue);
 }
 
@@ -323,11 +323,11 @@ dumpX11Cmap(unsigned int       const nColors,
 
 static void
 readX11Colormap(FILE *       const file,
-                unsigned int const nColors, 
+                unsigned int const nColors,
                 bool         const byteSwap,
                 bool         const cmapDump,
                 X11XColor**  const x11colorsP) {
-                
+
     X11XColor * x11colors;
     int rc;
 
@@ -362,7 +362,7 @@ colormapAllGray(const X11XColor* const x11colors,
     bool grayscale;
 
     grayscale = TRUE;  /* initial assumption */
-    for (i = 0; i < ncolors; ++i) 
+    for (i = 0; i < ncolors; ++i)
         if (x11colors[i].red != x11colors[i].green ||
             x11colors[i].green != x11colors[i].blue )
             grayscale = FALSE;
@@ -383,7 +383,7 @@ dumpX11Header(X11WDFileHeader * const h11P) {
     X11WDFileHeader * h11FixedP;
 
     fixH11ByteOrder(h11P, &h11FixedP);
- 
+
     switch(h11FixedP->pixmap_format) {
     case XYBitmap: formatDesc = "XY bit map"; break;
     case XYPixmap: formatDesc = "XY pix map"; break;
@@ -421,12 +421,12 @@ dumpX11Header(X11WDFileHeader * const h11P) {
     pm_message("X offset: %u", h11FixedP->xoffset);
     pm_message("byte order: %s (%u)", byteOrderDesc, h11FixedP->byte_order);
     pm_message("bitmap unit: %u", h11FixedP->bitmap_unit);
-    pm_message("bit order: %s (%u)", 
+    pm_message("bit order: %s (%u)",
                bitOrderDesc, h11FixedP->bitmap_bit_order);
     pm_message("bitmap pad: %u", h11FixedP->bitmap_pad);
     pm_message("bits per pixel: %u", h11FixedP->bits_per_pixel);
     pm_message("bytes per line: %u", h11FixedP->bytes_per_line);
-    pm_message("visual class: %s (%u)", 
+    pm_message("visual class: %s (%u)",
                visualClassDesc, h11FixedP->visual_class);
     pm_message("red mask:   %08x", h11FixedP->red_mask);
     pm_message("green mask: %08x", h11FixedP->green_mask);
@@ -517,18 +517,18 @@ computeComponentMasks(X11WDFileHeader * const h11P,
 
 
 static void
-processX11Header(X11WDFileHeader *  const h11P, 
+processX11Header(X11WDFileHeader *  const h11P,
                  FILE *             const fileP,
                  bool               const cmapDump,
-                 int *              const colsP, 
-                 int *              const rowsP, 
-                 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, 
+                 int *              const colsP,
+                 int *              const rowsP,
+                 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,
                  struct compMask *  const compMaskP,
                  enum byteorder *   const byte_orderP,
                  enum byteorder *   const bit_orderP) {
@@ -538,21 +538,21 @@ processX11Header(X11WDFileHeader *  const h11P,
     bool grayscale;
     bool const byte_swap = (h11P->file_version != X11WD_FILE_VERSION);
     X11WDFileHeader * h11FixedP;
- 
+
     fixH11ByteOrder(h11P, &h11FixedP);
 
     if (byte_swap && verbose)
         pm_message("Header is different endianness from this machine.");
-    
+
     for (i = 0; i < h11FixedP->header_size - sizeof(*h11FixedP); ++i)
         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_depth > 32)
+        pm_error( "can't handle X11 pixmap_depth > 32");
+    if (h11FixedP->bits_per_rgb > 32)
+        pm_error("can't handle X11 bits_per_rgb > 32");
     if (h11FixedP->pixmap_format != ZPixmap && h11FixedP->pixmap_depth != 1)
         pm_error("can't handle X11 pixmap_format %d with depth != 1",
                  h11FixedP->pixmap_format);
@@ -593,6 +593,9 @@ processX11Header(X11WDFileHeader *  const h11P,
         *formatP = PPM_TYPE;
 
         /* See discussion above about this maxval */
+        if (h11FixedP->bits_per_rgb > 16)
+            pm_error("Invalid bits_per_rgb for TrueColor image: %u. "
+                     "Maximum possible is 16", h11FixedP->bits_per_rgb);
         *maxvalP = pm_bitstomaxval(h11FixedP->bits_per_rgb);
     } else if (*visualclassP == StaticGray && h11FixedP->bits_per_pixel == 1) {
         *formatP = PBM_TYPE;
@@ -649,7 +652,7 @@ processX11Header(X11WDFileHeader *  const h11P,
        from a truecolor 32 bit window on a Hummingbird Exceed X server
        on Win32, and it had bitmap_unit = 8 and bitmap_pad = 32.
 
-       But Björn Eriksson in October 2003 had an xwd file from a 24
+       But Bjorn Eriksson in October 2003 had an xwd file from a 24
        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.
 
@@ -687,21 +690,21 @@ processX11Header(X11WDFileHeader *  const h11P,
     computeComponentMasks(h11FixedP, compMaskP);
 
     free(h11FixedP);
-} 
+}
 
 
 
 static void
-getinit(FILE *             const ifP, 
-        int *              const colsP, 
-        int *              const rowsP, 
-        unsigned int *     const padrightP, 
-        xelval *           const maxvalP, 
-        enum visualclass * const visualclassP, 
-        int *              const formatP, 
+getinit(FILE *             const ifP,
+        int *              const colsP,
+        int *              const rowsP,
+        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, 
+        int *              const bits_per_pixelP,
+        int *              const bits_per_itemP,
         struct compMask *  const compMaskP,
         enum byteorder *   const byte_orderP,
         enum byteorder *   const bit_orderP,
@@ -729,13 +732,13 @@ getinit(FILE *             const ifP,
     if ( sizeof(*h10P) > sizeof(*h11P) )
         pm_error("ARGH!  On this machine, X10 headers are larger than "
                  "X11 headers!\n    You will have to re-write xwdtopnm." );
-    
+
     /* We read an X10 header's worth of data from the file, then look
        at it to see if it looks like an X10 header.  If so we process
        the X10 header.  If not, but it looks like the beginning of an
        X11 header, we read more bytes so we have an X11 header's worth
        of data, then process the X11 header.  Otherwise, we raise an
-       error.  
+       error.
     */
 
     rc = fread(&header[0], sizeof(*h10P), 1, ifP);
@@ -744,23 +747,23 @@ getinit(FILE *             const ifP,
 
     if (h10P->file_version == X10WD_FILE_VERSION ||
         pm_bs_long(h10P->file_version) == X10WD_FILE_VERSION) {
-        
+
         if (verbose)
             pm_message("Input is X10");
-        processX10Header(h10P, ifP, colsP, rowsP, padrightP, maxvalP, 
-                         visualclassP, formatP, 
-                         colorsP, bits_per_pixelP, bits_per_itemP, 
+        processX10Header(h10P, ifP, colsP, rowsP, padrightP, maxvalP,
+                         visualclassP, formatP,
+                         colorsP, bits_per_pixelP, bits_per_itemP,
                          compMaskP, byte_orderP, bit_orderP);
     } else if (h11P->file_version == X11WD_FILE_VERSION ||
                pm_bs_long(h11P->file_version) == X11WD_FILE_VERSION) {
-        
+
         int rc;
 
         if (verbose)
             pm_message("Input is X11");
 
         /* Read the balance of the X11 header */
-        rc = fread(&header[sizeof(*h10P)], 
+        rc = fread(&header[sizeof(*h10P)],
                    sizeof(*h11P) - sizeof(*h10P), 1, ifP);
         if (rc != 1)
             pm_error("couldn't read end of X11 XWD file header");
@@ -769,9 +772,9 @@ getinit(FILE *             const ifP,
             dumpX11Header(h11P);
 
         processX11Header(h11P, ifP, cmapDump,
-                         colsP, rowsP, padrightP, maxvalP, 
-                         visualclassP, formatP, 
-                         colorsP, bits_per_pixelP, bits_per_itemP, 
+                         colsP, rowsP, padrightP, maxvalP,
+                         visualclassP, formatP,
+                         colorsP, bits_per_pixelP, bits_per_itemP,
                          compMaskP, byte_orderP, bit_orderP);
     } else
         pm_error("unknown XWD file version: %u", h11P->file_version);
@@ -786,7 +789,7 @@ getinit(FILE *             const ifP,
 
 #define DEBUG_PIXEL_2 \
     if (pixel_count < 4) \
-        pm_message("item: %.8lx", row_controlP->item.l); 
+        pm_message("item: %.8lx", row_controlP->item.l);
 
 
 #define DEBUG_PIXEL_3 \
@@ -876,10 +879,10 @@ static void
 pixelReader_init(pixelReader *  const pixelReaderP,
                  FILE *         const fileP,
                  int            const bitsPerPixel,
-                 int            const bitsPerItem, 
+                 int            const bitsPerItem,
                  enum byteorder const byteOrder,
                  enum byteorder const bitOrder) {
-    
+
     pixelReaderP->fileP           = fileP;
     pixelReaderP->bitsPerPixel    = bitsPerPixel;
     pixelReaderP->bitsPerItem     = bitsPerItem;
@@ -887,7 +890,7 @@ pixelReader_init(pixelReader *  const pixelReaderP,
     pixelReaderP->bitOrder        = bitOrder;
 
     pixelReaderP->nBitsLeft       = 0;
-}    
+}
 
 
 
@@ -950,10 +953,10 @@ readItem(pixelReader * const rdrP) {
         rdrP->nBitsLeft = 16;
     }
         break;
-        
+
     case 32: {
         long item32;
-        
+
         switch (rdrP->byteOrder) {
         case MSBFirst:
             pm_readbiglong(rdrP->fileP, &item32);
@@ -979,7 +982,7 @@ static unsigned long const lsbmask[] = {
    of a bit string.
 -----------------------------------------------------------------------------*/
     0x00000000,
-    0x00000001, 0x00000003, 0x00000007, 0x0000000f, 
+    0x00000001, 0x00000003, 0x00000007, 0x0000000f,
     0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
     0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
     0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
@@ -999,10 +1002,10 @@ pixelReader_getbits(pixelReader * const rdrP,
 -----------------------------------------------------------------------------*/
     unsigned long pixel;
         /* Accumulator for the value we ultimately return.  We shift in
-           bits from the right end.  The number of bits presently in the
+           bits from the right end.  The number of bits currently in the
            accumulator is rdrP->bitsPerPixel - nBitsStillNeeded .
         */
-    
+
     unsigned int nBitsStillNeeded;
         /* How many bits we still need to add to 'pixel',
            as we build it up to the
@@ -1030,7 +1033,7 @@ pixelReader_getbits(pixelReader * const rdrP,
                 /* The actual bits we take, in the 'nBitsToTake' low bits */
 
             assert(nBitsToTake <= 32);
-            
+
             if (rdrP->bitOrder == MSBFirst) {
                 unsigned int const nBitsToLeave =
                     rdrP->nBitsLeft - nBitsToTake;
@@ -1039,7 +1042,7 @@ pixelReader_getbits(pixelReader * const rdrP,
             } else {
                 bitsToTake = rdrP->itemBuffer & bitsToTakeMask;
                 rdrP->itemBuffer >>= nBitsToTake;
-            }                
+            }
             /* Shift the bits into the right end of the accumulator */
             pixel <<= nBitsToTake;
             pixel |= bitsToTake;
@@ -1064,7 +1067,7 @@ pixelReader_getpix(pixelReader * const rdrP) {
 
    We return an integer.  It's the integer that the pixel represents as
    pure binary cipher, with the first bit the most significant bit.
-   
+
    The basic unit of storage in the input file is an "item."  An item
    can be 1, 2, or 4 bytes, and 'bits_per_item' tells us which.  Each
    item can have its bytes stored in forward or reverse order, and
@@ -1103,18 +1106,18 @@ pixelReader_getpix(pixelReader * const rdrP) {
 
 
 static void
-reportInfo(int              const cols, 
-           int              const rows, 
-           unsigned int     const padright, 
-           xelval           const maxval, 
+reportInfo(int              const cols,
+           int              const rows,
+           unsigned int     const padright,
+           xelval           const maxval,
            enum visualclass const visualclass,
-           int              const format, 
+           int              const format,
            int              const bits_per_pixel,
-           int              const bits_per_item, 
+           int              const bits_per_item,
            struct compMask  const compMask,
-           enum byteorder   const byte_order, 
+           enum byteorder   const byte_order,
            enum byteorder   const bit_order) {
-    
+
     const char *visualclass_name;
     const char *byte_order_name;
     const char *bit_order_name;
@@ -1140,7 +1143,7 @@ reportInfo(int              const cols,
     pm_message("%d rows of %d columns with maxval %d",
                rows, cols, maxval);
     pm_message("padright=%u bits.  visualclass = %s.  format=%d (%c%c)",
-               padright, visualclass_name, 
+               padright, visualclass_name,
                format, format/256, format%256);
     pm_message("bits_per_pixel=%d; bits_per_item=%d",
                bits_per_pixel, bits_per_item);
@@ -1174,12 +1177,12 @@ warn16Bit(xelval const maxval) {
 
 
 
-static void 
+static void
 convertRowSimpleIndex(pixelReader *  const pixelReaderP,
                       int            const cols,
                       const xel *    const colors,
                       xel *          const xelrow) {
-    
+
     unsigned int col;
     for (col = 0; col < cols; ++col)
         xelrow[col] = colors[pixelReader_getpix(pixelReaderP)];
@@ -1193,7 +1196,7 @@ convertRowDirect(pixelReader *   const pixelReaderP,
                  const xel *     const colors,
                  struct compMask const compMask,
                  xel *           const xelrow) {
-        
+
     unsigned int col;
 
     for (col = 0; col < cols; ++col) {
@@ -1204,11 +1207,11 @@ convertRowDirect(pixelReader *   const pixelReaderP,
         unsigned int red_index, grn_index, blu_index;
             /* These are indices into the color map, unpacked from 'pixel'.
              */
-            
+
         pixel = pixelReader_getpix(pixelReaderP);
 
         red_index = (pixel & compMask.red) >> zero_bits(compMask.red);
-        grn_index = (pixel & compMask.grn) >> zero_bits(compMask.grn); 
+        grn_index = (pixel & compMask.grn) >> zero_bits(compMask.grn);
         blu_index = (pixel & compMask.blu) >> zero_bits(compMask.blu);
 
         PPM_ASSIGN(xelrow[col],
@@ -1263,12 +1266,12 @@ convertRowTrueColor(pixelReader *   const pixelReaderP,
 static void
 convertRow(pixelReader *    const pixelReaderP,
            FILE *           const ofP,
-           unsigned int     const padright, 
-           int              const cols, 
+           unsigned int     const padright,
+           int              const cols,
            xelval           const maxval,
-           int              const format, 
+           int              const format,
            struct compMask  const compMask,
-           const xel*       const colors, 
+           const xel*       const colors,
            enum visualclass const visualclass) {
 /*----------------------------------------------------------------------------
    Read a row from the XWD pixel input stream 'pixelReaderP' and write
@@ -1290,20 +1293,20 @@ convertRow(pixelReader *    const pixelReaderP,
     case PseudoColor:
         convertRowSimpleIndex(pixelReaderP, cols, colors, xelrow);
         break;
-    case DirectColor: 
+    case DirectColor:
         convertRowDirect(pixelReaderP, cols, colors, compMask, xelrow);
-        
+
         break;
-    case TrueColor: 
+    case TrueColor:
         convertRowTrueColor(pixelReaderP, cols, maxval, colors,
                             compMask, xelrow);
         break;
-            
+
     default:
         pm_error("unknown visual class");
     }
     pixelReader_getbits(pixelReaderP, padright);
-    
+
     pnm_writepnmrow(ofP, xelrow, cols, maxval, format, 0);
     pnm_freerow(xelrow);
 }
@@ -1321,11 +1324,11 @@ reportOutputType(int const format) {
     case PGM_TYPE:
         pm_message("writing PGM file");
     break;
-    
+
     case PPM_TYPE:
         pm_message("writing PPM file");
     break;
-    
+
     default:
         pm_error("shouldn't happen");
     }
@@ -1358,19 +1361,19 @@ main(int argc, char *argv[]) {
     debug = cmdline.debug;
     verbose = cmdline.verbose;
 
-    if (cmdline.inputFilename != NULL) 
+    if (cmdline.inputFilename != NULL)
         ifP = pm_openr(cmdline.inputFilename);
     else
         ifP = stdin;
 
-    getinit(ifP, &cols, &rows, &padright, &maxval, &visualclass, &format, 
-            &colors, &bitsPerPixel, &bitsPerItem, 
+    getinit(ifP, &cols, &rows, &padright, &maxval, &visualclass, &format,
+            &colors, &bitsPerPixel, &bitsPerItem,
             &compMask, &byteOrder, &bitOrder,
             cmdline.headerdump, cmdline.cmapdump);
 
     warn16Bit(maxval);
-    
-    if (verbose) 
+
+    if (verbose)
         reportInfo(cols, rows, padright, maxval, visualclass,
                    format, bitsPerPixel, bitsPerItem, compMask,
                    byteOrder, bitOrder);
@@ -1389,17 +1392,17 @@ main(int argc, char *argv[]) {
     }
 
     pixelReader_term(&pixelReader);
-    
+
     pm_close(ifP);
     pm_close(stdout);
-    
+
     return 0;
 }
 
 
 
 /*
-   This used to be the way we parsed a direct/true color pixel.  I'm 
+   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.
 
    There doesn't seem to be any reason to do this hard-coded stuff when
@@ -1411,7 +1414,7 @@ main(int argc, char *argv[]) {
    this whole switch thing.  -Bryan 00.03.01
 
    switch (bits_per_pixel) {
-                
+
    case 16:
        PPM_ASSIGN( *xP,
                    ( ( ul & red_mask )   >> 0    ),
diff --git a/converter/other/yuy2topam.c b/converter/other/yuy2topam.c
index 40ab98b3..49f284ac 100644
--- a/converter/other/yuy2topam.c
+++ b/converter/other/yuy2topam.c
@@ -31,12 +31,12 @@ struct CmdlineInfo {
 
 
 
-static void 
-parseCommandLine(int argc, const char ** argv, 
+static void
+parseCommandLine(int argc, const 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.  
+   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.
@@ -84,7 +84,7 @@ parseCommandLine(int argc, const char ** argv,
         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);
diff --git a/converter/pbm/atktopbm.c b/converter/pbm/atktopbm.c
index 807e4f4a..57782d91 100644
--- a/converter/pbm/atktopbm.c
+++ b/converter/pbm/atktopbm.c
@@ -44,7 +44,7 @@
 #define dataobject_OBJECTCREATIONFAILED 4
 #define dataobject_BADFORMAT 5
 
-/* ReadRow(file, row, length) 
+/* ReadRow(file, row, length)
 ** Reads from 'file' the encoding of bytes to fill in 'row'.  Row will be
 ** truncated or padded (with WHITE) to exactly 'length' bytes.
 **
@@ -52,7 +52,7 @@
 **      '|'     correct end of line
 **      '\0'    if the length was satisfied (before a terminator)
 **      EOF     if the file ended
-**      '\'  '{'    other recognized ends. 
+**      '\'  '{'    other recognized ends.
 ** The '|' is the expected end and pads the row with WHITE.
 ** The '\' and '{' are error conditions and may indicate the
 ** beginning of some other portion of the data stream.
@@ -76,11 +76,11 @@ ReadRow(FILE *          const file,
   'file' is where to get them from.
   'row' is where to put bytes.
   'length' is how many bytes in row must be filled.
-  
+
   Return the delimiter that marks the end of the row, or EOF if EOF marks
   the end of the row, or NUL in some cases.
 -----------------------------------------------------------------------------*/
-    /* Each input character is processed by the central loop.  There are 
+    /* Each input character is processed by the central loop.  There are
     ** some input codes which require two or three characters for
     ** completion; these are handled by advancing the state machine.
     ** Errors are not processed; instead the state machine is reset
@@ -98,7 +98,7 @@ ReadRow(FILE *          const file,
         RepeatAndDigit
             /* have seen repeat code and its first following digit */
     };
-    
+
     enum StateCode InputState;  /* current state */
     int c;     /* the current input character */
     long repeatcount;  /* current repeat value */
@@ -106,8 +106,8 @@ ReadRow(FILE *          const file,
     long pendinghex;    /* the first of a pair of hex characters */
     int lengthRemaining;
     unsigned char * cursor;
-    
-    /* We cannot exit when length becomes zero because we need to check 
+
+    /* We cannot exit when length becomes zero because we need to check
     ** to see if a row ending character follows.  Thus length is checked
     ** only when we get a data generating byte.  If length then is
     ** zero, we ungetc the byte.
@@ -148,7 +148,7 @@ ReadRow(FILE *          const file,
             while (lengthRemaining-- > 0)
                 *cursor++ = WHITEBYTE;
             return c;
-    
+
         CASE1(0x21):
         CASE6(0x22):
         CASE8(0x28):
@@ -227,9 +227,9 @@ ReadRow(FILE *          const file,
             break;
 
         store:
-            /* generate byte(s) into the output row 
+            /* generate byte(s) into the output row
                Use repeatcount, depending on state.  */
-            if (lengthRemaining < repeatcount) 
+            if (lengthRemaining < repeatcount)
                 /* reduce repeat count if it would exceed
                    available space */
                 repeatcount = lengthRemaining;
@@ -269,7 +269,7 @@ ReadATKRaster(FILE * const ifP) {
         pm_error ("input file not Andrew raster object");
 
     fscanf(ifP, " %d ", &version);
-    if (version < 2) 
+    if (version < 2)
         pm_error ("version too old to parse");
 
     {
@@ -277,8 +277,8 @@ ReadATKRaster(FILE * const ifP) {
         long xscale, yscale;
         long xoffset, yoffset, subwidth, subheight;
         /* ignore all these features: */
-        fscanf(ifP, " %u %ld %ld %ld %ld %ld %ld",  
-               &options, &xscale, &yscale, &xoffset, 
+        fscanf(ifP, " %u %ld %ld %ld %ld %ld %ld",
+               &options, &xscale, &yscale, &xoffset,
                &yoffset, &subwidth, &subheight);
     }
     /* scan to end of line in case this is actually something beyond V2 */
@@ -291,8 +291,12 @@ ReadATKRaster(FILE * const ifP) {
 
     fscanf(ifP, " %d %d %d ", &objectid, &width, &height);
 
-    if (width < 1 || height < 1 || width > 1000000 || height > 1000000) 
+    if (width < 1 || height < 1 || width > 1000000 || height > 1000000)
         pm_error("bad width or height");
+        /* Note: Whether these values are upper limits set by the author of
+           the original version of this program, or come from the official
+           file format specification is unknown.
+        */
 
     pbm_writepbminit(stdout, width, height, 0);
     bitrow = pbm_allocrow_packed(width);
@@ -302,7 +306,7 @@ ReadATKRaster(FILE * const ifP) {
         long const nextChar = ReadRow(ifP, bitrow, rowlen);
 
         switch (nextChar) {
-        case '|': 
+        case '|':
             pbm_writepbmrow_packed(stdout, bitrow, width, 0);
             break;
         case EOF:
diff --git a/converter/pbm/escp2topbm.c b/converter/pbm/escp2topbm.c
index 8acd13d6..de3ea931 100644
--- a/converter/pbm/escp2topbm.c
+++ b/converter/pbm/escp2topbm.c
@@ -104,7 +104,7 @@ readChar(FILE * const ifP) {
 
 
 
-static void       
+static void
 readStripeHeader(unsigned int * const widthThisStripeP,
                  unsigned int * const rowsThisStripeP,
                  unsigned int * const compressionP,
@@ -120,7 +120,7 @@ readStripeHeader(unsigned int * const widthThisStripeP,
     compression     = stripeHeader[0];
     /* verticalResolution   = stripeHeader[1]; */
     /* horizontalResolution = stripeHeader[2]; */
-    rowsThisStripe  = stripeHeader[3];  
+    rowsThisStripe  = stripeHeader[3];
     widthThisStripe = stripeHeader[5] * 256 + stripeHeader[4];
 
     if (widthThisStripe == 0 || rowsThisStripe == 0)
@@ -143,7 +143,7 @@ readStripeHeader(unsigned int * const widthThisStripeP,
 
 /* RLE decoder */
 static void
-decEpsonRLE(unsigned int    const blockSize, 
+decEpsonRLE(unsigned int    const blockSize,
             unsigned char * const outBuffer,
             FILE *          const ifP) {
 
@@ -174,7 +174,7 @@ decEpsonRLE(unsigned int    const blockSize,
             unsigned int i;
 
             for (i = 0; i < runLength; ++i)
-                outBuffer[dpos + i] = repeatChar;  
+                outBuffer[dpos + i] = repeatChar;
             dpos += runLength;
         }
     }
@@ -191,7 +191,7 @@ processStripeRaster(unsigned char ** const bitarray,
                     unsigned int     const compression,
                     FILE *           const ifP,
                     unsigned int *   const rowIdxP) {
-         
+
     unsigned int const initialRowIdx = *rowIdxP;
     unsigned int const widthInBytes = pbm_packed_bytes(width);
     unsigned int const blockSize = rowsThisStripe * widthInBytes;
@@ -237,7 +237,7 @@ expandBitarray(unsigned char *** const bitarrayP,
     if (*bitarraySizeP > heightMax)
         pm_error("Error: Image too tall");
     else
-        REALLOCARRAY_NOFAIL(*bitarrayP, *bitarraySizeP); 
+        REALLOCARRAY_NOFAIL(*bitarrayP, *bitarraySizeP);
 }
 
 
@@ -253,7 +253,7 @@ writePbmImage(unsigned char ** const bitarray,
         pm_error("No image");
 
     pbm_writepbminit(stdout, width, height, 0);
- 
+
     for (row = 0; row < height; ++row) {
         pbm_cleanrowend_packed(bitarray[row], width);
         pbm_writepbmrow_packed(stdout, bitarray[row], width, 0);
@@ -309,7 +309,7 @@ main(int          argc,
                 unsigned int compression;
                 unsigned int rowsThisStripe;
                 unsigned int widthThisStripe;
-            
+
                 readStripeHeader(&widthThisStripe, &rowsThisStripe,
                                  &compression, ifP);
 
@@ -320,7 +320,7 @@ main(int          argc,
                     /* The official Epson manual says valid values are 1, 8,
                        24 but we just print a warning message and continue if
                        other values are detected.
-                    */ 
+                    */
                     pm_message("Abnormal data block height value: %u "
                                "(ignoring)",
                                rowsThisStripe);
diff --git a/converter/pbm/g3topbm.c b/converter/pbm/g3topbm.c
index 5d98fcb2..5db507a3 100644
--- a/converter/pbm/g3topbm.c
+++ b/converter/pbm/g3topbm.c
@@ -552,12 +552,11 @@ readFaxRow(struct BitStream * const bitStreamP,
                 curcode = (curcode << 1) | bit;
                 ++curlen;
 
-		if (curlen > 11 && curcode == 0x00) {
-		    if (++fillbits > MAXFILLBITS)
-                pm_error("Encountered %u consecutive fill bits.  "
-                       "Aborting", fillbits);
-		}
-		else if (curlen - fillbits > 13) {
+                if (curlen > 11 && curcode == 0x00) {
+                    if (++fillbits > MAXFILLBITS)
+                        pm_error("Encountered %u consecutive fill bits.  "
+                                 "Aborting", fillbits);
+                } else if (curlen - fillbits > 13) {
                     formatBadCodeException(exceptionP, col, curlen, curcode);
                     done = TRUE;
                 } else if (curcode != 0) {
diff --git a/converter/pbm/mdatopbm.c b/converter/pbm/mdatopbm.c
index d8e06572..461b3f80 100644
--- a/converter/pbm/mdatopbm.c
+++ b/converter/pbm/mdatopbm.c
@@ -36,7 +36,7 @@ static bit **data;          /* PBM image */
 static mdbyte *mdrow;           /* MDA row after decompression (MD3 only) */
 static int bInvert = 0;     /* Invert image? */
 static int bScale  = 0;     /* Scale image? */
-static int bAscii  = 0;     /* Ouput ASCII PBM? */
+static int bAscii  = 0;     /* Output ASCII PBM? */
 static int nInRows, nInCols;        /* Height, width of input (rows x bytes) */
 static int nOutCols, nOutRows;      /* Height, width of output (rows x bytes) */
 
diff --git a/converter/pbm/mgrtopbm.c b/converter/pbm/mgrtopbm.c
index 712e3be9..e0a88883 100644
--- a/converter/pbm/mgrtopbm.c
+++ b/converter/pbm/mgrtopbm.c
@@ -58,12 +58,12 @@ interpHdrHeight(struct b_header const head,
 
 
 static void
-readMgrHeader(FILE *          const ifP, 
-              unsigned int *  const colsP, 
-              unsigned int *  const rowsP, 
-              unsigned int *  const depthP, 
+readMgrHeader(FILE *          const ifP,
+              unsigned int *  const colsP,
+              unsigned int *  const rowsP,
+              unsigned int *  const depthP,
               unsigned int *  const padrightP ) {
-    
+
     struct b_header head;
     unsigned int pad;
     size_t bytesRead;
@@ -73,10 +73,10 @@ readMgrHeader(FILE *          const ifP,
         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') { 
+    if (head.magic[0] == 'y' && head.magic[1] == 'z') {
         /* new style bitmap */
         size_t bytesRead;
-        bytesRead = fread(&head.depth, 
+        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.  "
@@ -84,11 +84,11 @@ readMgrHeader(FILE *          const ifP,
                      errno, strerror(errno));
         *depthP = (int) head.depth - ' ';
         pad = 8;
-    } else if (head.magic[0] == 'x' && head.magic[1] == 'z') { 
+    } else if (head.magic[0] == 'x' && head.magic[1] == 'z') {
         /* old style bitmap with 32-bit padding */
         *depthP = 1;
         pad = 32;
-    } else if (head.magic[0] == 'z' && head.magic[1] == 'z') { 
+    } else if (head.magic[0] == 'z' && head.magic[1] == 'z') {
         /* old style bitmap with 16-bit padding */
         *depthP = 1;
         pad = 16;
@@ -104,8 +104,8 @@ readMgrHeader(FILE *          const ifP,
 
     interpHdrWidth (head, colsP);
     interpHdrHeight(head, rowsP);
-    
-    *padrightP = ( ( *colsP + pad - 1 ) / pad ) * pad - *colsP;
+
+    *padrightP = ((*colsP + pad - 1) / pad) * pad - *colsP;
 }
 
 
@@ -131,7 +131,7 @@ main(int    argc,
         inputFileName = argv[1];
     else
         inputFileName = "-";
-    
+
     ifP = pm_openr(inputFileName);
 
     readMgrHeader(ifP, &cols, &rows, &depth, &padright);
@@ -141,7 +141,7 @@ main(int    argc,
     pbm_writepbminit(stdout, cols, rows, 0);
 
     bitrow = pbm_allocrow_packed(cols + padright);
-    
+
     itemCount = (cols + padright ) / 8;
 
     for (row = 0; row < rows; ++row) {
@@ -166,9 +166,9 @@ main(int    argc,
    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 .
-  
+
 */
 
 
diff --git a/converter/pbm/pbmtoatk.c b/converter/pbm/pbmtoatk.c
index ea5b7abe..5f2b625c 100644
--- a/converter/pbm/pbmtoatk.c
+++ b/converter/pbm/pbmtoatk.c
@@ -22,8 +22,8 @@
 
 
 static void
-write_atk_bytes(FILE *        const file, 
-                unsigned char const curbyte, 
+write_atk_bytes(FILE *        const file,
+                unsigned char const curbyte,
                 unsigned int  const startcount) {
 
     /* codes for data stream */
@@ -37,7 +37,7 @@ write_atk_bytes(FILE *        const file,
     #define BLACKBYTE 0xFF
 
     /* WriteRow table for conversion of a byte value to two character
-       hex representation 
+       hex representation
     */
 
     static unsigned char hex[16] = {
@@ -82,10 +82,10 @@ write_atk_bytes(FILE *        const file,
 
 
 static void
-process_atk_byte(int *           const pcurcount, 
-                 unsigned char * const pcurbyte, 
-                 FILE *          const file, 
-                 unsigned char   const newbyte, 
+process_atk_byte(int *           const pcurcount,
+                 unsigned char * const pcurbyte,
+                 FILE *          const file,
+                 unsigned char   const newbyte,
                  int             const eolflag) {
 
     int curcount;
@@ -93,7 +93,7 @@ process_atk_byte(int *           const pcurcount,
 
     curcount = *pcurcount;  /* initial value */
     curbyte  = *pcurbyte;  /* initial value */
-    
+
     if (curcount < 1) {
         *pcurbyte = curbyte = newbyte;
         *pcurcount = curcount = 1;
@@ -139,6 +139,17 @@ main(int argc, const char ** argv) {
     }
 
     pbm_readpbminit(ifP, &cols, &rows, &format);
+    /* Note: atktopbm imposes limits: cols <= 1000000 rows <= 1000000
+       Whether these values are defined in the official file format
+       specification is unknown.  We issue warning messages when large
+       values are encountered.
+     */
+
+    if (cols > 1000000)
+        pm_message("Proceeding with extremely large width value: %u", cols);
+    if (rows > 1000000)
+        pm_message("Proceeding with extremely large height value: %u", rows);
+
     bitrow = pbm_allocrow_packed(cols);
 
     printf("\\begindata{raster,%d}\n", 1);
@@ -152,7 +163,7 @@ main(int argc, const char ** argv) {
 
         pbm_readpbmrow_packed(ifP, bitrow, cols, format);
         pbm_cleanrowend_packed(bitrow, cols);
-        
+
         for (i = 0, curbyte = 0, curcount = 0; i < byteCt; ++i) {
             process_atk_byte(&curcount, &curbyte, stdout,
                              bitrow[i],
@@ -162,7 +173,7 @@ main(int argc, const char ** argv) {
 
     pbm_freerow_packed(bitrow);
     pm_close(ifP);
-    
+
     printf("\\enddata{raster, %d}\n", 1);
 
     return 0;
diff --git a/converter/pbm/pbmtoescp2.c b/converter/pbm/pbmtoescp2.c
index 6f284f3c..942ecec9 100644
--- a/converter/pbm/pbmtoescp2.c
+++ b/converter/pbm/pbmtoescp2.c
@@ -18,6 +18,7 @@
 *
 *  ESC/P Reference Manual (1997)
 *  ftp://download.epson-europe.com/pub/download/182/epson18162eu.zip
+*  See Part 1 "ESC ." Print Raster Graphics
 */
 
 #include <string.h>
@@ -28,7 +29,7 @@
 #include "runlength.h"
 #include "pbm.h"
 
-
+#define MAXCOLS (127 * 256 + 255)  /* Limit in official Epson manual */
 
 static char const esc = 033;
 
@@ -57,19 +58,19 @@ parseCommandLine(int argc, const char ** argv,
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;
     opt.allowNegNum = FALSE;
-    OPTENT3(0, "compress",     OPT_UINT,    &cmdlineP->compress,    
+    OPTENT3(0, "compress",     OPT_UINT,    &cmdlineP->compress,
             &compressSpec,    0);
-    OPTENT3(0, "resolution",   OPT_UINT,    &cmdlineP->resolution,  
+    OPTENT3(0, "resolution",   OPT_UINT,    &cmdlineP->resolution,
             &resolutionSpec,  0);
-    OPTENT3(0, "stripeheight", OPT_UINT,    &cmdlineP->stripeHeight,  
+    OPTENT3(0, "stripeheight", OPT_UINT,    &cmdlineP->stripeHeight,
             &stripeHeightSpec, 0);
-    OPTENT3(0, "raw",          OPT_FLAG,    NULL,  
+    OPTENT3(0, "raw",          OPT_FLAG,    NULL,
             &rawSpec,    0);
-    OPTENT3(0, "formfeed",     OPT_FLAG,    NULL,  
+    OPTENT3(0, "formfeed",     OPT_FLAG,    NULL,
             &formfeedSpec,    0);
-    
+
     pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
-    
+
     if (argc-1 > 1)
         pm_error("Too many arguments: %d.  "
                  "Only argument is the filename", argc-1);
@@ -155,7 +156,7 @@ main(int argc, const char * argv[]) {
     unsigned char * bitrow[256];
     unsigned char * compressedData;
     struct CmdlineInfo cmdline;
-    
+
     pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
@@ -164,7 +165,7 @@ main(int argc, const char * argv[]) {
 
     pbm_readpbminit(ifP, &cols, &rows, &format);
 
-    if (cols / 256 > 127)  /* Limit in official Epson manual */
+    if (cols > MAXCOLS)
         pm_error("Image width is too large");
 
     outColByteCt = pbm_packed_bytes(cols);
@@ -229,7 +230,7 @@ main(int argc, const char * argv[]) {
         }
     }
 
-    free(inBuff); 
+    free(inBuff);
     free(compressedData);
     pm_close(ifP);
 
diff --git a/converter/pbm/pbmtogem.c b/converter/pbm/pbmtogem.c
index 9eab0416..4fd30e92 100644
--- a/converter/pbm/pbmtogem.c
+++ b/converter/pbm/pbmtogem.c
@@ -26,7 +26,7 @@
 *  changed header length to count words to conform with Atari ST documentation
 *  removed rounding of the imagewidth to the next word boundary
 *  removed arbitrary limit to imagewidth
-*  changed pattern length to 1 to simplify locating of compressable parts
+*  changed pattern length to 1 to simplify locating of compressible parts
 *       in real world images
 *  add solid run and pattern run compression
 *
diff --git a/converter/pbm/pbmtogo.c b/converter/pbm/pbmtogo.c
index 23b2ee9a..4f84f391 100644
--- a/converter/pbm/pbmtogo.c
+++ b/converter/pbm/pbmtogo.c
@@ -1,29 +1,29 @@
 /* pbmtogo.c - read a PBM image and produce a GraphOn terminal raster file
-**      
+**
 **      Rev 1.1 was based on pbmtolj.c
 **
 **      Bo Thide', Swedish Institute of Space Physics, bt@irfu.se
-**                                 
+**
 **
 ** $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.
- * 
+ *
  * Revision 1.4  89/11/24  14:56:04  14:56:04  root (Bo Thide)
  * Fixed the command line parsing since pbmtogo now always uses 2D
  * compression.  Added a few comments to the source.
- * 
+ *
  * Revision 1.3  89/11/24  13:43:43  13:43:43  root (Bo Thide)
  * Added capability for > 63 repeated bytes and > 62 repeated lines in
  * the 2D compression scheme.
- * 
+ *
  * Revision 1.2  89/11/15  01:04:47  01:04:47  root (Bo Thide)
  * First version that works reasonably well with GraphOn 2D runlength
  * encoding/compression.
- * 
+ *
  * Revision 1.1  89/11/02  23:25:25  23:25:25  root (Bo Thide)
  * Initial revision
- * 
+ *
 **
 ** Copyright (C) 1988, 1989 by Jef Poskanzer, Michael Haberler, and Bo Thide'.
 **
@@ -44,10 +44,10 @@
 
 #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 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;
@@ -167,7 +167,7 @@ main(int           argc,
       buffer[i] = oldscanline[i] = 0;
     putinit();
 
-    /* Start donwloading screen raster */
+    /* Start downloading screen raster */
     printf("\033P0;1;0;4;1;%d;%d;1!R1/", rows, rucols);
 
     linerepeat = 63; /*  63 means "Start new picture" */
@@ -183,32 +183,32 @@ main(int           argc,
           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++)
           diff[i] = oldscanline[i]^newscanline[i];
-        
+
         /*
          ** If the difference map is different from current internal buffer,
-         ** encode the difference and put it in the output buffer. 
+         ** encode the difference and put it in the output buffer.
          ** Else, increase the counter for the current buffer by one.
          */
-        
+
         if ((memcmp(buffer, diff, bytesperrow) != 0) || (row == 0)) {
-            /*    
+            /*
              **Since the data in the buffer has changed, send the
              **scan line repeat count to cause the old line(s) to
              **be plotted on the screen, copy the new data into
-             **the internal buffer, and reset the counters.  
+             **the internal buffer, and reset the counters.
              */
-              
+
             putchar(linerepeat);
             for (i = 0; i < bytesperrow; ++i)
               buffer[i] = diff[i];
             nbyte = 0;          /* Internal buffer byte counter */
             nout = 0;           /* Output buffer byte counter */
-              
-            /* Run length encode the new internal buffr (= difference map) */
+
+            /* Run length encode the new internal buffer (= difference map) */
             while (TRUE) {
                 ucount = 0;     /* Unique items counter */
                 do              /* Find unique patterns */
@@ -217,16 +217,16 @@ main(int           argc,
                       ucount++;
                   } while (nbyte < bytesperrow && (olditem != buffer[nbyte])
                            && (ucount < MIN(bytesperrow, MAX_REPEAT)));
-                  
+
                 if ((ucount != MAX_REPEAT) && (nbyte != bytesperrow)) {
                     /* Back up to the last truly unique pattern */
                     ucount--;
                     nbyte--;
                 }
 
-                if (ucount > 0) { 
+                if (ucount > 0) {
                     /* Output the unique patterns */
-                    outbuffer[nout++] = 
+                    outbuffer[nout++] =
                       (ucount-1) | PLOT_ARBITRARY_DATA_MASK;
                     for (i = nbyte-ucount; i < nbyte; i++)
                       outbuffer[nout++] = buffer[i];
@@ -235,12 +235,12 @@ main(int           argc,
                 /*
                  ** If we already are at the end of the current scan
                  ** line, skip the rest of the encoding and start
-                 ** with a new scan line.  
+                 ** with a new scan line.
                  */
 
                 if (nbyte >= bytesperrow)
                   goto nextrow;
-                  
+
                 ecount = 0;     /* Equal items counter */
                 do              /* Find equal patterns */
                   {
@@ -248,25 +248,25 @@ main(int           argc,
                       ecount++;
                   } while (nbyte < bytesperrow && (olditem == buffer[nbyte])
                            && (ecount < MIN(bytesperrow, MAX_REPEAT)));
-                  
+
                 if (ecount > 1) {
                     /* More than 1 equal pattern */
                     if (olditem == '\0') {
                         /* White patterns */
                         if (nbyte >= bytesperrow-1) {
                             /* No more valid data ahead */
-                            outbuffer[nout++] = 
+                            outbuffer[nout++] =
                               (ecount-2) | SKIP_AND_PLOT_MASK;
                             outbuffer[nout++] = buffer[nbyte-1];
-                        } 
-                        else { 
+                        }
+                        else {
                             /* More valid data ahead */
-                            outbuffer[nout++] = 
+                            outbuffer[nout++] =
                               (ecount-1) | SKIP_AND_PLOT_MASK;
                             outbuffer[nout++] = buffer[nbyte++];
-                        } 
+                        }
                     }
-                    else { 
+                    else {
                         /* Non-white patterns */
                         outbuffer[nout++] = (ecount-1) | REPEAT_PLOT_MASK;
                         outbuffer[nout++] = olditem;
@@ -274,11 +274,11 @@ main(int           argc,
                 } /* if (ecount > 1) */
                 else
                   nbyte--;      /* No equal items found */
-                  
+
                 if (nbyte >= bytesperrow)
                   goto nextrow;
             } /* while (TRUE) */
-              
+
           nextrow: printf("%d/", nout+1); /* Total bytes to xfer = nout+1 */
             fflush(stdout);
 
@@ -298,7 +298,7 @@ main(int           argc,
                   linerepeat = 0;
               }
         }
-        
+
         /* Now we are ready for a new scan line */
         for (i = 0; i < bytesperrow; ++i)
           oldscanline[i] = newscanline[i];
diff --git a/converter/pbm/pbmtoibm23xx.c b/converter/pbm/pbmtoibm23xx.c
index 183d5419..3f1f9679 100644
--- a/converter/pbm/pbmtoibm23xx.c
+++ b/converter/pbm/pbmtoibm23xx.c
@@ -18,7 +18,7 @@
  */
 
 /*
- * This prgram is primarily based on the description of Brothers PPDS
+ * This program is primarily based on the description of Brothers PPDS
  * emulation (see
  * http://www.brother.de/download/send_file.cfm?file_name=guide_ibmpro.pdf).
  * However, there are some differences.  Their document states that
@@ -39,7 +39,7 @@
  * normally achieve in y.  But the printer is able to do line feeds in
  * terms of 1/240", so the trick to print in higher resolutions is to
  * print in several interleaved passes, and do a line feed of 1/240"
- * or 1/120" inbetween.
+ * or 1/120" in between.
  */
 
 #include <stdio.h>
@@ -131,7 +131,7 @@ process_handle(FILE *        const fh,
         int cols, rows, format;
         /* iteration variables */
         unsigned int x, y;
-        unsigned int bitline; /* pixel line within a sigle printing line */
+        unsigned int bitline; /* pixel line within a single printing line */
         unsigned int pass;
         /* here we build the to-be-printed data */
         unsigned char *output;  /* for reading one row from the file */
diff --git a/converter/pbm/pbmtolps.c b/converter/pbm/pbmtolps.c
index 5adef4c8..d974fcb2 100644
--- a/converter/pbm/pbmtolps.c
+++ b/converter/pbm/pbmtolps.c
@@ -1,181 +1,253 @@
-/*
- * pbmtolps -- convert a Portable BitMap into Postscript.  The
- * output Postscript uses lines instead of the image operator to
- * generate a (device dependent) picture which will be imaged
- * much faster.
- *
- * The Postscript path length is constrained to be less that 1000
- * points so that no limits are overrun on the Apple Laserwriter
- * and (presumably) no other printers.
- *
- * To do:
- *      make sure encapsulated format is correct
- *      repitition of black-white strips
- *      make it more device independent (is this possible?)
- *
- * Author:
- *      George Phillips <phillips@cs.ubc.ca>
- *      Department of Computer Science
- *      University of British Columbia
- */
-
-#include <string.h>
-#include <stdio.h>
-
+/*=============================================================================
+                             pbmtolps
+===============================================================================
+
+  Convert a PBM image to Postscript.  The output Postscript uses lines instead
+  of the image operator to generate a (device dependent) picture which will be
+  imaged much faster.
+
+  The Postscript path length is constrained to be at most 1000 vertices so that
+  no limits are overrun on the Apple Laserwriter and (presumably) no other
+  printers.  The typical limit is 1500.  See "4.4 Path Construction" and
+  "Appendix B: Implementation Limits" in: PostScript Language Reference Manual
+  https://www.adobe.com/content/dam/acom/en/devnet/actionscript/
+  articles/psrefman.pdf
+
+  To do:
+       make sure encapsulated format is correct
+       repetition of black-white strips
+       make it more device independent (is this possible?)
+
+  Author:
+       George Phillips <phillips@cs.ubc.ca>
+       Department of Computer Science
+       University of British Columbia
+=============================================================================*/
+#include <stdbool.h>
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
 #include "nstring.h"
+#include "shhopt.h"
 #include "pbm.h"
 
 
-static int prev_white = -1;
-static int prev_black = -1;
-static char cmd = '\0';
-static int pointcount = 2;
+static float        const MAX_DPI           = 5000;
+static float        const MIN_DPI           = 10;
+static unsigned int const MAX_PATH_VERTICES = 1000;
 
-#ifdef RUN
-static int run = 1;
-#endif
 
-static char 
-morepoints(char cmd, int howmany_pbmtolps) {
-    pointcount += 2;
-    if (pointcount > 1000) {
-        pointcount = 2;
-        cmd += 'm' - 'a';
-    }
-    return(cmd);
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line, in a form
+       easy for the program to use.
+    */
+    const char * inputFileName;  /* File name of input file */
+    unsigned int inputFileSpec;  /* Input file name specified */
+    float        lineWidth;      /* Line width, if specified */
+    unsigned int lineWidthSpec;  /* Line width specified */
+    float        dpi;            /* Resolution in DPI, if specified */
+    unsigned int dpiSpec;        /* Resolution specified */
+};
+
+
+
+static void
+validateDpi(float const dpi) {
+
+    if (dpi > MAX_DPI || dpi < MIN_DPI)
+        pm_error("Specified DPI value out of range (%f)", dpi);
 }
 
 
 
-static void 
-addstrip(int const white, 
-         int const black) {
-
-    if (cmd) {
-#ifdef RUN
-        if (white == prev_white && black == prev_black)
-            run++;
-        else {
-            if (run == 1)
-#endif
-                printf("%d %d %c ", 
-                       prev_black, prev_white, morepoints(cmd, 2));
-#ifdef RUN
-            else
-                                /* of course, we need to give a new command */
-                printf("%d %d %d %c ",
-                       prev_white, prev_black, run,
-                       morepoints(cmd + 'f' - 'a', 2 * run));
-            run = 1;
-        }
-#endif
+static void
+parseCommandLine(int                        argc,
+                 const char **        const 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.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;  /* malloc'ed */
+        /* 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 */
+    OPTENT3(0, "linewidth", OPT_FLOAT, &cmdlineP->lineWidth,
+                            &cmdlineP->lineWidthSpec,    0);
+    OPTENT3(0, "dpi",       OPT_FLOAT,  &cmdlineP->dpi,
+                            &cmdlineP->dpiSpec,          0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (cmdlineP->dpiSpec)
+        validateDpi(cmdlineP->dpi);
+    else
+        cmdlineP->dpi = 300;
+
+    if (argc-1 < 1)
+        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];
     }
 
-    prev_white = white;
-    prev_black = black;
-    cmd = 'a';
+    if (cmdlineP->inputFileName[0] == '-' &&
+        cmdlineP->inputFileName[1] == '\0')
+        cmdlineP->inputFileSpec = false;
+    else
+        cmdlineP->inputFileSpec = true;
+
+    free(option_def);
 }
 
 
 
-static void 
-nextline(void) {
-    /* need to check run, should have an outcommand */
-    if (cmd)
-        printf("%d %d %c\n", prev_black, prev_white, morepoints('c', 3));
-    else
-        printf("%c\n", morepoints('b', 1));
-    cmd = '\0';
+static void
+validateLineWidth(float const scCols,
+                  float const scRows,
+                  float const lineWidth) {
+
+    if (lineWidth >= scCols || lineWidth >= scRows)
+        pm_error("Absurdly large -linewidth value (%f)", lineWidth);
 }
 
 
 
-int
-main(int argc, char ** argv) {
-    FILE*   fp;
-    bit*    bits;
-    int             row;
-    int             col;
-    int         rows;
-    int             cols;
-    int             format;
-    int             white;
-    int             black;
-    const char*   name;
-    float   dpi = 300.0;
-    float   sc_rows;
-    float   sc_cols;
-    int             i;
-    const char*   const usage = "[ -dpi n ] [ pbmfile ]";
-
-
-	pbm_init(&argc, argv);
-
-    i = 1;
-    if (i < argc && streq(argv[i], "-dpi")) {
-        if (i == argc - 1)
-            pm_usage(usage);
-        sscanf(argv[i + 1], "%f", &dpi);
-        i += 2;
-    }
+static void
+doRaster(FILE *       const ifP,
+         unsigned int const cols,
+         unsigned int const rows,
+         int          const format,
+         FILE *       const ofP) {
 
-    if (i < argc - 1)
-        pm_usage(usage);
+    bit *        bitrow;
+    unsigned int row;
+    unsigned int vertexCt;
+        /* Number of vertices drawn since last stroke command */
 
-    if (i == argc) {
-        name = "noname";
-        fp = stdin;
-    } else {
-        name = argv[i];
-        fp = pm_openr(name);
-    }
-    pbm_readpbminit(fp, &cols, &rows, &format);
-    bits = pbm_allocrow(cols);
-
-    sc_rows = (float)rows / dpi * 72.0;
-    sc_cols = (float)cols / dpi * 72.0;
-
-    puts("%!PS-Adobe-2.0 EPSF-2.0");
-    puts("%%Creator: pbmtolps");
-    printf("%%%%Title: %s\n", name);
-    printf("%%%%BoundingBox: %d %d %d %d\n",
-           (int)(305.5 - sc_cols / 2.0),
-           (int)(395.5 - sc_rows / 2.0),
-           (int)(306.5 + sc_cols / 2.0),
-           (int)(396.5 + sc_rows / 2.0));
-    puts("%%EndComments");
-    puts("%%EndProlog");
-    puts("gsave");
-
-    printf("%f %f translate\n", 306.0 - sc_cols / 2.0, 396.0 + sc_rows / 2.0);
-    printf("72 %f div dup neg scale\n", dpi);
-    puts("/a { 0 rmoveto 0 rlineto } def");
-    puts("/b { 0 row 1 add dup /row exch def moveto } def");
-    puts("/c { a b } def");
-    puts("/m { currentpoint stroke newpath moveto a } def");
-    puts("/n { currentpoint stroke newpath moveto b } def");
-    puts("/o { currentpoint stroke newpath moveto c } def");
-    puts("/row 0 def");
-    puts("newpath 0 0 moveto");
-
-    for (row = 0; row < rows; row++) {
-        pbm_readpbmrow(fp, bits, cols, format);
-        /* output white-strip+black-strip sequences */
-        for (col = 0; col < cols; ) {
-            for (white = 0; col < cols && bits[col] == PBM_WHITE; col++)
-                white++;
-            for (black = 0; col < cols && bits[col] == PBM_BLACK; col++)
-                black++;
+    bitrow = pbm_allocrow(cols);
+
+    for (row = 0, vertexCt = 0; row < rows; ++row) {
+        unsigned int col;
+        bool firstRun;
+
+        firstRun = true;  /* initial value */
+
+        pbm_readpbmrow(ifP, bitrow, cols, format);
+
+        /* output white-strip + black-strip sequences */
 
-            if (black != 0)
-                addstrip(white, black);
+        for (col = 0; col < cols; ) {
+            unsigned int whiteCt;
+            unsigned int blackCt;
+
+            for (whiteCt = 0; col < cols && bitrow[col] == PBM_WHITE; ++col)
+                ++whiteCt;
+            for (blackCt = 0; col < cols && bitrow[col] == PBM_BLACK; ++col)
+                ++blackCt;
+
+            if (blackCt > 0) {
+                if (vertexCt > MAX_PATH_VERTICES) {
+                    printf("m ");
+                    vertexCt = 0;
+                }
+
+                if (firstRun) {
+                    printf("%u %u moveto %u 0 rlineto\n",
+                           whiteCt, row, blackCt);
+                    firstRun = false;
+                } else
+                    printf("%u %u a\n", blackCt, whiteCt);
+
+                vertexCt += 2;
+            }
         }
-        nextline();
     }
-    puts("stroke grestore showpage");
-    puts("%%Trailer");
+    pbm_freerow(bitrow);
+}
+
+
+
+static void
+pbmtolps(FILE *             const ifP,
+         FILE *             const ofP,
+         struct CmdlineInfo const cmdline) {
+
+    const char * const psName =
+        cmdline.inputFileSpec ? cmdline.inputFileName : "noname";
+
+    int          rows;
+    int          cols;
+    int          format;
+    float        scRows, scCols;
+        /* Dimensions of the printed image in points */
+
+    pbm_readpbminit(ifP, &cols, &rows, &format);
+
+    scRows = (float) rows / (cmdline.dpi / 72.0);
+    scCols = (float) cols / (cmdline.dpi / 72.0);
+
+    if (cmdline.lineWidthSpec)
+        validateLineWidth(scCols, scRows, cmdline.lineWidth);
+
+    fputs("%!PS-Adobe-2.0 EPSF-2.0\n", ofP);
+    fputs("%%Creator: pbmtolps\n", ofP);
+    fprintf(ofP, "%%%%Title: %s\n", psName);
+    fprintf(ofP, "%%%%BoundingBox: %d %d %d %d\n",
+           (int)(305.5 - scCols / 2.0),
+           (int)(395.5 - scRows / 2.0),
+           (int)(306.5 + scCols / 2.0),
+           (int)(396.5 + scRows / 2.0));
+    fputs("%%EndComments\n", ofP);
+    fputs("%%EndProlog\n", ofP);
+    fputs("gsave\n", ofP);
+
+    fprintf(ofP, "%f %f translate\n",
+            306.0 - scCols / 2.0, 396.0 + scRows / 2.0);
+    fprintf(ofP, "72 %f div dup neg scale\n", cmdline.dpi);
+
+    if (cmdline.lineWidthSpec)
+        fprintf(ofP, "%f setlinewidth\n", cmdline.lineWidth);
+
+    fputs("/a { 0 rmoveto 0 rlineto } def\n", ofP);
+    fputs("/m { currentpoint stroke newpath moveto } def\n", ofP);
+    fputs("newpath 0 0 moveto\n", ofP);
+
+    doRaster(ifP, cols, rows, format, ofP);
+
+    fputs("stroke grestore showpage\n", ofP);
+    fputs("%%Trailer\n", ofP);
+}
+
+
+
+int
+main(int argc, const char *argv[]) {
+    FILE *  ifP;
+    struct CmdlineInfo cmdline;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    pbmtolps(ifP, stdout, cmdline);
 
-    pm_close(fp);
+    pm_close(ifP);
 
-    exit(0);
+    return 0;
 }
diff --git a/converter/pbm/pbmtomacp.c b/converter/pbm/pbmtomacp.c
index e02f5559..4897e6d0 100644
--- a/converter/pbm/pbmtomacp.c
+++ b/converter/pbm/pbmtomacp.c
@@ -18,7 +18,7 @@
 
 /*
 
-  Implemention notes
+  Implementation notes
 
   Header size is 512 bytes.  There is no MacBinary header.
 
diff --git a/converter/pbm/pbmtomgr.c b/converter/pbm/pbmtomgr.c
index 0e529740..faa56d8f 100644
--- a/converter/pbm/pbmtomgr.c
+++ b/converter/pbm/pbmtomgr.c
@@ -33,7 +33,7 @@ putinit(unsigned int const rows,
     head._reserved = ' ';
     writtenCount = fwrite(&head, sizeof(head), 1, stdout);
     if (writtenCount != 1)
-        pm_error("fwrite() failed to write the MGR header.");    
+        pm_error("fwrite() failed to write the MGR header.");
 }
 
 
@@ -63,7 +63,7 @@ main(int argc,
         inputFileName = argv[1];
     else
         inputFileName = "-";
-    
+
     ifP = pm_openr(inputFileName);
 
     pbm_readpbminit(ifP, &cols, &rows, &format);
@@ -71,14 +71,14 @@ main(int argc,
         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);
 
     putinit(rows, cols);
-    
+
     for (row = 0; row < rows; ++row) {
-        /* The raster formats are identical. 
+        /* The raster formats are identical.
            The row end pad bits are set to 0 in mgr.
         */
         size_t bytesWritten;
@@ -89,7 +89,7 @@ main(int argc,
         bytesWritten = fwrite(bitrow, 1, bytesPerRow, stdout);
         if (bytesWritten != bytesPerRow )
             pm_error("fwrite() failed to write MGR bitmap "
-                     "to Standard Output.");    
+                     "to Standard Output.");
     }
     pm_close(ifP);
     return 0;
@@ -102,7 +102,7 @@ main(int argc,
    pbm_readpbmrow_packed(), write function from putc() to fwrite().
 
    Retired bitwise transformation functions.
-   
+
    Produces only new style bitmap (8 bit padding.)  See mgrtopbm.c .
 */
 
diff --git a/converter/pbm/pbmtonokia.c b/converter/pbm/pbmtonokia.c
index 80b0bd59..4604064a 100644
--- a/converter/pbm/pbmtonokia.c
+++ b/converter/pbm/pbmtonokia.c
@@ -83,7 +83,7 @@ parseCommandLine(int argc, char ** argv,
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENT3 */
-    OPTENT3(0, "fmt",     OPT_STRING, &fmtOpt, 
+    OPTENT3(0, "fmt",     OPT_STRING, &fmtOpt,
             &fmtSpec, 0);
     OPTENT3(0, "net",     OPT_STRING, &netOpt,
             &netSpec, 0);
@@ -135,7 +135,7 @@ parseCommandLine(int argc, char ** argv,
                  "the 120 characters allowed by the format.",
                  (unsigned)strlen(cmdlineP->txt));
 
-    if (argc-1 == 0) 
+    if (argc-1 == 0)
         cmdlineP->inputFileName = "-";
     else if (argc-1 != 1)
         pm_error("Program takes zero or one argument (filename).  You "
@@ -180,7 +180,7 @@ convertToHexNol(bit **       const image,
 
     /* header */
     fprintf(ofP, "06050415820000%s00%02X%02X01", networkCode, cols, rows);
-    
+
     /* image */
     for (row = 0; row < rows; ++row) {
         unsigned int col;
@@ -245,7 +245,7 @@ convertToHexNpm(bit **       const image,
                 FILE *       const ofP) {
 
     unsigned int row;
-    
+
     /* header */
     fprintf(ofP, "060504158A0000");
 
@@ -293,7 +293,7 @@ convertToNol(bit **       const image,
     unsigned int row;
     char header[32];
     unsigned int it;
-    
+
     /* header - this is a hack */
 
     header[ 0] = 'N';
@@ -318,7 +318,7 @@ convertToNol(bit **       const image,
     header[19] = 0;
 
     fwrite(header, 20, 1, ofP);
-    
+
     /* image */
     for (row = 0; row < rows; ++row) {
         unsigned int col;
@@ -368,7 +368,7 @@ convertToNgg(bit **       const image,
     header[15] = 0;
 
     fwrite(header, 16, 1, ofP);
-    
+
     /* image */
 
     for (row = 0; row < rows; ++row) {
@@ -395,35 +395,56 @@ convertToNpm(bit **       const image,
              const char * const text,
              FILE *       const ofP) {
 
+    size_t const textLen = text ? strlen(text) : 0;
+
     unsigned int row;
     char header[132];
-    size_t len;
-
-    if (text) 
-        len = strlen(text);
-    else
-        len = 0;
 
     /* header and optional text */
 
-    header[       0] = 'N';
-    header[       1] = 'P';
-    header[       2] = 'M';
-    header[       3] = 0;
-    header[       4] = len;
-    header[       5] = 0;
-    if (text)
-        memcpy(&header[6], text, len);
-    header[ 6 + len] = cols;
-    header[ 7 + len] = rows;
-    header[ 8 + len] = 1;
-    header[ 9 + len] = 1;
-    header[10 + len] = 0; /* unknown */
-
-    assert(10 + len < sizeof(header));
-
-    fwrite(header, 11 + len, 1, ofP);
-    
+    /* Our entry condition is that 'text' be a legal text field, which means
+       no more than 120 characters:
+    */
+    assert(textLen <= 120);
+
+    /* We don't have any specification of this format, but in May 2020, we
+       found what looks like a bug: the memcpy of the text field started at
+       &header[5] (overwriting the previous setting of header[5] and leaving
+       header[6+len-1] not set to anything).  Nobody ever complained about
+       this, so maybe somehow it worked better than the sensible code we have
+       now, where the text field starts in the 7th byte.
+    */
+
+    /* The code below that deliberately avoids using 'text' as an argument to
+       memcpy when 'text' is null looks like it should have no practical
+       effect, because with a zero length memcpy, it shouldn't matter what the
+       from and to arguments are.  But it's logically correct - a null pointer
+       just doesn't point anywhere.  And believe it or not, it has a practical
+       effect - a truly bizarre one.  This code used to be simpler and just
+       pass that null pointer to memcpy, with length 0, and as reported in May
+       2020, a new optimizing compiler caused header[3] to contain random
+       values.  That's right: 3.  Skipping that presumed no-op memcpy stopped
+       the behavior.
+    */
+
+    header[           0] = 'N';
+    header[           1] = 'P';
+    header[           2] = 'M';
+    header[           3] = 0;
+    header[           4] = textLen;
+    header[           5] = 0;
+    if (text)  /* see above */
+        memcpy(&header[6], text, textLen);
+    header[ 6 + textLen] = cols;
+    header[ 7 + textLen] = rows;
+    header[ 8 + textLen] = 1;
+    header[ 9 + textLen] = 1;
+    header[10 + textLen] = 0; /* unknown */
+
+    assert(10 + textLen < sizeof(header));
+
+    fwrite(header, 11 + textLen, 1, ofP);
+
     /* image: stream of bits, each row padded to a byte boundary
        inspired by gnokii/common/gsm-filesystems.c
      */
@@ -453,7 +474,7 @@ convertToNpm(bit **       const image,
 
 
 
-int 
+int
 main(int    argc,
      char * argv[]) {
 
@@ -521,6 +542,6 @@ Testing:
   The data was send with EMI/UCP protocol over TCP/IP.
 
   - 7.6.2001: tested with Nokia 3210: 72x14 Operator Logo
-  - 7.6.2001: tested with Nokia 6210: 72x14 Operator Logo and 
+  - 7.6.2001: tested with Nokia 6210: 72x14 Operator Logo and
               72x14 Group Graphic
 */
diff --git a/converter/pbm/pbmtopk.c b/converter/pbm/pbmtopk.c
index 2f05d449..3f54254c 100644
--- a/converter/pbm/pbmtopk.c
+++ b/converter/pbm/pbmtopk.c
@@ -1,8 +1,8 @@
 /*
   pbmtopk, adapted from "pxtopk.c by tomas rokicki" by AJCD 1/8/90
-  
+
   References (retrieved May 31 2015):
-  Packed (PK) Font File Format 
+  Packed (PK) Font File Format
   https://www.tug.org/TUGboat/tb06-3/tb13pk.pdf
 
   Tex Font Metric Files (TFM)
@@ -148,7 +148,7 @@ compute_checksum()
             temp_width:=memory[char_wd[c]];
             if design_units<>unity then
                temp_width:=round((temp_width/design_units)*1048576.0);
-            temp_width:=temp_width + (c+4)*@'20000000; 
+            temp_width:=temp_width + (c+4)*@'20000000;
                 {this should be positive}
             c0:=(c0+c0+temp_width) mod 255;
             c1:=(c1+c1+temp_width) mod 253;
@@ -173,12 +173,12 @@ compute_checksum()
 
 
 static byte
-add_tfmtable(int *        const table, 
-             int *        const count, 
-             int          const value, 
-             int          const max_count, 
+add_tfmtable(int *        const table,
+             int *        const count,
+             int          const value,
+             int          const max_count,
              const char * const name) {
-    
+
     integer i;
     for (i = 0; i < *count; i++) /* search for value in tfm table */
         if (table[i] == value) return (byte)i;
@@ -194,8 +194,8 @@ add_tfmtable(int *        const table,
 
 
 /* add a suffix to a filename in an allocated space */
-static void 
-pbmtopk_add_suffix(char * const name, 
+static void
+pbmtopk_add_suffix(char * const name,
                    const char * const suffix) {
 
     char *slash = strrchr(name, '/');
@@ -208,7 +208,7 @@ pbmtopk_add_suffix(char * const name,
 
 
 /* initialize the PK parameters */
-static void 
+static void
 initialize_pk(void) {
     integer i ;
     pm_message("This is PBMtoPK, version 2.4") ;
@@ -225,13 +225,13 @@ initialize_pk(void) {
 
 
 /* write a single byte to the PK file */
-static void 
+static void
 pbmtopk_pkbyte(integer const b_in) {
     integer b;
 
     b = b_in;  /* initial value */
 
-    if (b < 0) 
+    if (b < 0)
         b += 256 ;
     putc(b, pkfile) ;
     pbmtopk_pkloc++ ;
@@ -240,13 +240,13 @@ pbmtopk_pkbyte(integer const b_in) {
 
 
 /* write two bytes to the PK file */
-static void 
+static void
 pkhalfword(integer const a_in) {
     integer a;
 
     a = a_in;
 
-    if (a < 0) 
+    if (a < 0)
         a += 65536 ;
     pbmtopk_pkbyte(a >> 8) ;
     pbmtopk_pkbyte(a & 255) ;
@@ -255,7 +255,7 @@ pkhalfword(integer const a_in) {
 
 
 /* write three bytes to the PK file */
-static void 
+static void
 pkthreebytes(integer const a) {
 
     pbmtopk_pkbyte((a>>16) & 255) ;
@@ -266,7 +266,7 @@ pkthreebytes(integer const a) {
 
 
 /* write four bytes to the PK file */
-static void 
+static void
 pkword(integer const a) {
     pbmtopk_pkbyte((a>>24) & 255) ;
     pbmtopk_pkbyte((a>>16) & 255) ;
@@ -277,7 +277,7 @@ pkword(integer const a) {
 
 
 /* write a nibble to the PK file */
-static void 
+static void
 pknyb(integer const a) {
 
     if (bitweight == 16) {
@@ -292,15 +292,15 @@ pknyb(integer const a) {
 
 
 /* write preamble to PK file */
-static void 
+static void
 writepreamble(void) {
     integer i ;
     const char * const comment = "PBMtoPK 2.4 output" ;
-   
+
     pbmtopk_pkbyte(247) ;                /* PRE command */
     pbmtopk_pkbyte(89) ;             /* PK file type */
     pbmtopk_pkbyte(strlen(comment)) ;            /* output comment */
-    for (i = 0 ; i < strlen(comment); i++) 
+    for (i = 0 ; i < strlen(comment); i++)
         pbmtopk_pkbyte(xord[(int)comment[i]]) ;
     pkword(designsize) ;             /* write designsize */
     pkword(checksum) ;       /* write checksum; calculate if possible */
@@ -311,7 +311,7 @@ writepreamble(void) {
 
 
 /* write postamble to PK file, padded to word length */
-static void 
+static void
 writepostamble(void) {
     pbmtopk_pkbyte(245) ;                /* POST command */
     while (pbmtopk_pkloc % 4)
@@ -322,7 +322,7 @@ writepostamble(void) {
 
 
 /* write a byte to the TFM file */
-static void 
+static void
 tfmbyte(integer const b_in) {
     integer b;
 
@@ -335,9 +335,9 @@ tfmbyte(integer const b_in) {
 
 
 /* write a half word to the TFM file */
-static void 
+static void
 tfmhalfword(integer const a_in) {
-    
+
     integer a;
 
     a = a_in;
@@ -350,7 +350,7 @@ tfmhalfword(integer const a_in) {
 
 
 /* write a word to the TFM file */
-static void 
+static void
 tfmword(integer const a) {
     tfmbyte((a>>24) & 255) ;
     tfmbyte((a>>16) & 255) ;
@@ -361,12 +361,12 @@ tfmword(integer const a) {
 
 
 /* write the whole TFM file for the font */
-static void 
+static void
 writetfmfile(void) {
     integer totallength ;
     integer headersize = 17;
     integer i ;
-   
+
     if (largestch - smallestch < 0) {
         largestch = 0;
         smallestch = 1;
@@ -406,23 +406,23 @@ writetfmfile(void) {
     /* header */
     tfmword(checksum) ;              /* write checksum */
     tfmword(designsize) ;            /* write designsize */
-    if (strlen(codingscheme) > 39) 
+    if (strlen(codingscheme) > 39)
         tfmbyte(39) ; /* write coding scheme len */
-    else 
+    else
         tfmbyte(strlen(codingscheme)) ;
     for (i = 0; i < 39; i++)         /* write coding scheme */
-        if 
+        if
             (*codingscheme) tfmbyte(xord[(int)(*codingscheme++)]) ;
         else
             tfmbyte(0) ;
-    if (strlen(familyname) > 19) 
+    if (strlen(familyname) > 19)
         tfmbyte(19) ;   /* write family length */
-    else 
+    else
         tfmbyte(strlen(familyname)) ;
     for (i = 0; i < 19; i++)         /* write family */
-        if (*familyname) 
+        if (*familyname)
             tfmbyte(xord[(int)(*familyname++)]) ;
-        else 
+        else
             tfmbyte(0) ;
     /* char_info */
     for (car = smallestch; car <= largestch; car++)
@@ -441,7 +441,7 @@ writetfmfile(void) {
     for (i = 0; i < numdepth; i++) tfmword(depthtab[i]) ;
     /* italic correction table */
     for (i = 0; i < numitalic; i++) tfmword(italictab[i]) ;
-    /* no lig_kern, kern, or exten tables */
+    /* no lig_kern, kern, or extent tables */
     /* fontdimen table */
     for (i = 0; i < numparam; i++)
         if (i && !fixrange(parameters[i]))
@@ -456,11 +456,11 @@ writetfmfile(void) {
 /* read a character from a PBM file */
 static void readcharacter(void) {
     FILE *fp;
-   
+
     fp = pm_openr(filename[car]);
     bitmap = pbm_readpbm(fp, &width, &height) ;
     pm_close(fp) ;
-   
+
     if ((charflags[car] & HORZESC) == 0) horzesc[car] = width ;
     if ((charflags[car] & VERTESC) == 0) vertesc[car] = 0;
     if ((charflags[car] & XOFFSET) == 0) xoffset[car] = 0;
@@ -470,10 +470,10 @@ static void readcharacter(void) {
     if ((charflags[car] & TFMHEIGHT) == 0)
         hgtindex[car] = add_tfmheight(fixword(designunits(yoffset[car]+1)));
     if ((charflags[car] & TFMDEPTH) == 0)
-        depindex[car] = 
+        depindex[car] =
             add_tfmdepth(fixword(designunits(height-1-yoffset[car])));
     if ((charflags[car] & TFMITALIC) == 0) italindex[car] = 0;
-   
+
     if (car < smallestch) smallestch = car;
     if (car > largestch) largestch = car;
     if (width > emwidth) emwidth = width ;
@@ -482,14 +482,14 @@ static void readcharacter(void) {
 
 
 /* test if two rows of the PBM are the same */
-static int 
-equal(const bit * const row1, 
+static int
+equal(const bit * const row1,
       const bit * const row2) {
 
     integer i ;
-   
+
     for (i = 0; i < width; i++)
-        if (row1[i] != row2[i]) 
+        if (row1[i] != row2[i])
             return (0) ;
 
     return(1) ;
@@ -497,7 +497,7 @@ equal(const bit * const row1,
 
 
 
-static void 
+static void
 shipcharacter(void) {
 
     integer compsize ;
@@ -526,13 +526,13 @@ shipcharacter(void) {
     integer max2 ;
     integer predpkloc ;
     integer buff ;
-   
+
     integer tfwid = widthtab[tfmindex[car]] ;
     integer hesc = horzesc[car] ;
     integer vesc = vertesc[car] ;
     integer xoff = xoffset[car] ;
     integer yoff = yoffset[car] ;
-   
+
     MALLOCARRAY(repeatptr, height + 1);
     MALLOCARRAY(bitcounts, height * width);
     if (repeatptr == NULL || bitcounts == NULL)
@@ -781,8 +781,8 @@ shipcharacter(void) {
     }
     if (predpkloc != pbmtopk_pkloc)
         pm_error("bad predicted character length: character %d", car);
-    pbm_freerow(zerorow); 
-    pbm_freerow(onesrow); 
+    pbm_freerow(zerorow);
+    pbm_freerow(onesrow);
     free((char *)repeatptr);
     free((char *)bitcounts);
 }
@@ -790,7 +790,7 @@ shipcharacter(void) {
 
 
 /* check that character is in valid range */
-static void 
+static void
 checkchar(void) {
     if (car < 0 || car >= MAXPKCHAR)
         pm_error("character must be in range 0 to %d", MAXPKCHAR-1) ;
@@ -799,16 +799,16 @@ checkchar(void) {
 
 
 /* read character information from an option file */
-static void 
+static void
 optionfile(const char * const name) {
 
     FILE *fp ;
     char buffer[MAXOPTLINE] ;
-   
+
     fp = pm_openr(name);
     while (!feof(fp)) {
         char *here = buffer;
-      
+
         if (fgets(buffer, MAXOPTLINE, fp) == NULL) break ;
         while (ISSPACE(*here)) here++ ;
         if (*here && *here == '=') {
@@ -817,7 +817,7 @@ optionfile(const char * const name) {
         } else if (*here && *here != '%' && *here != '#') {
             char str[NAMELENGTH] ;
             integer i, n;
-     
+
             checkchar() ;
             if (sscanf(here, "%s%n", str, &n) != 1)
                 pm_error("bad option file line %s", buffer) ;
@@ -881,26 +881,26 @@ main(int argc, char *argv[]) {
 
     pbm_init(&argc, argv);
     initialize_pk() ;
-   
+
     if (--argc < 1) pm_usage(usage) ;
     ++argv;
     if(strlen(*argv) + 4 > NAMELENGTH)
         pm_error("pkname is too long");
     strcpy(pkname, *argv) ;
     pbmtopk_add_suffix(pkname, ".pk") ;
-   
+
     if (--argc < 1) pm_usage(usage);
     ++argv;
     if(strlen(*argv) + 4 > NAMELENGTH)
         pm_error("tfmname is too long");
     strcpy(tfmname, *argv) ;
     pbmtopk_add_suffix(tfmname, ".tfm") ;
-   
+
     if (--argc < 1) pm_usage(usage) ;
     resolution = atoi(*++argv) ;
     if (resolution < 1 || resolution > 32767)
         pm_error("unlikely resolution %d dpi", resolution);
-   
+
     car = flags = hesc = vesc = xoff = yoff = tfwid = 0;
     while (++argv, --argc) {
         if (argv[0][0] == '-' && argv[0][1]) {
@@ -922,7 +922,7 @@ main(int argc, char *argv[]) {
             case 's':
                 designsize = fixword(atof(p));
                 if (designsize < 1048576)
-                    pm_error("design size %f out of range", 
+                    pm_error("design size %f out of range",
                              unfixword(designsize));
             case 'h':
                 hesc = atoi(p) ;
@@ -1009,3 +1009,5 @@ main(int argc, char *argv[]) {
     return 0;
 }
 
+
+
diff --git a/converter/pbm/pbmtoppa/README.REDHAT b/converter/pbm/pbmtoppa/README.REDHAT
index 3586aea2..e7b30490 100644
--- a/converter/pbm/pbmtoppa/README.REDHAT
+++ b/converter/pbm/pbmtoppa/README.REDHAT
@@ -17,7 +17,7 @@ StartEntry: DeskJet720C
            It does does not support color printing. \
            IMPORTANT! Insert \
                 "- | pbm2ppa -" \
-           in the "Extra GS Otions" field.\
+           in the "Extra GS Options" field.\
          }
   Resolution: {600} {600} {}
 EndEntry
diff --git a/converter/pbm/pbmtoppa/ppa.c b/converter/pbm/pbmtoppa/ppa.c
index aa30d684..69e7bb79 100644
--- a/converter/pbm/pbmtoppa/ppa.c
+++ b/converter/pbm/pbmtoppa/ppa.c
@@ -207,7 +207,7 @@ void ppa_init_job(ppa_stat* prn)
     scp3_put (prn->fptr, 0x018f, sizeof(init3), 7, 2, 4, init3);
     break;
   default:
-    fprintf(stderr,"ppa_init_job(): unknown printer verson\n");
+    fprintf(stderr,"ppa_init_job(): unknown printer version\n");
   }
 }
 
@@ -238,7 +238,7 @@ void ppa_init_page(ppa_stat* prn)
     scp3_put (prn->fptr, 0x0183, sizeof(pageA), 5, 1, 0, pageA);
     break;
   default:
-    fprintf(stderr,"ppa_init_page(): unknown printer verson\n");
+    fprintf(stderr,"ppa_init_page(): unknown printer version\n");
   }
 }
 
@@ -260,7 +260,7 @@ void ppa_load_page(ppa_stat* prn)
     scp3_put (prn->fptr, 0x0181, sizeof(loadC), 7, 1, 0, loadC);
     break;
   default:
-    fprintf(stderr,"ppa_load_page(): unknown printer verson\n");
+    fprintf(stderr,"ppa_load_page(): unknown printer version\n");
   }
 }
 
@@ -282,7 +282,7 @@ void ppa_eject_page(ppa_stat* prn)
     scp3_put (prn->fptr, 0x0181, sizeof(loadC), 7, 1, 0, loadC);
     break;
   default:
-    fprintf(stderr,"ppa_eject_page(): unknown printer verson\n");
+    fprintf(stderr,"ppa_eject_page(): unknown printer version\n");
   }
 }
 
@@ -440,7 +440,7 @@ void ppa_print_sweep(ppa_stat* prn,ppa_sweep_data* data)
     MF=1;
     break;
   default:
-    fprintf(stderr,"ppa_print_sweep(): unknown printer verson\n");
+    fprintf(stderr,"ppa_print_sweep(): unknown printer version\n");
     return;
   }
 
diff --git a/converter/pbm/pbmtoptx.c b/converter/pbm/pbmtoptx.c
index c0fb0f80..69f1707a 100644
--- a/converter/pbm/pbmtoptx.c
+++ b/converter/pbm/pbmtoptx.c
@@ -12,10 +12,10 @@
 
 #include "pbm.h"
 
-/* Follwing is obtained by reversing bit order (MFS-LFS) and adding 64. */
+/* Following is obtained by reversing bit order (MFS-LFS) and adding 64. */
 /* Note the two escape sequences: \\ and \x7f . */
 
-static unsigned char const ptxchar[64] = 
+static unsigned char const ptxchar[64] =
   "@`PpHhXxDdTtLl\\|BbRrJjZzFfVvNn^~AaQqIiYyEeUuMm]}CcSsKk[{GgWwOo_\x7f";
 
 
@@ -32,7 +32,7 @@ putBitrow(const bit *  const bitrow,
         unsigned int const byteCnt = (itemCnt * 6) / 8;
         bit const byteCur  = bitrow[byteCnt];
         bit const byteNext = bitrow[byteCnt + 1];
-        
+
         unsigned int item;
 
         switch (itemCnt % 4) {
@@ -62,7 +62,7 @@ main(int argc, const char ** argv)  {
         ifP = stdin;
     else {
         ifP = pm_openr(argv[1]);
-        
+
         if (argc-1 > 1)
             pm_error("Too many arguments.  The only possible argument is "
                      "the input fil name");
@@ -82,9 +82,8 @@ main(int argc, const char ** argv)  {
 
     pbm_freerow_packed(bitrow);
     pm_close(ifP);
-    
+
     return 0;
 }
 
 
-
diff --git a/converter/pbm/pbmtox10bm b/converter/pbm/pbmtox10bm
index deb3aeab..ca82fcd2 100644
--- a/converter/pbm/pbmtox10bm
+++ b/converter/pbm/pbmtox10bm
@@ -37,6 +37,16 @@ exec perl -w -x -S -- "$0" "$@"
 use strict;
 use File::Basename;
 use Cwd 'abs_path';
+use IO::Handle;
+
+
+
+sub pm_message($) {
+    STDERR->print("pbmtox10bm: $_[0]\n");
+}
+
+
+
 
 sub doVersionHack($) {
     my ($argvR) = @_;
@@ -56,13 +66,12 @@ my $infile;
 foreach (@ARGV) {
     if (/^-/) {
         # It's an option.  But Pbmtox10bm didn't have any options.
-        print(STDERR "Invalid option '$_'\n");
+        pm_message("Invalid option '$_'");
         exit(10);
     } else {
         # It's a parameter
         if (defined($infile)) {
-            print(STDERR
-                  "You may specify at most one non-option parameter.\n");
+            pm_message("You may specify at most one non-option parameter.");
             exit(10);
         } else {
             $infile = $_;
diff --git a/converter/pbm/xbmtopbm.c b/converter/pbm/xbmtopbm.c
index bbf4e395..1f5384ed 100644
--- a/converter/pbm/xbmtopbm.c
+++ b/converter/pbm/xbmtopbm.c
@@ -109,25 +109,35 @@ parseDeclaration(const char * const line,
 -----------------------------------------------------------------------------*/
     char nameAndType[MAX_LINE];
     int rc;
-        
+
     rc = sscanf(line, "static short %s = {", nameAndType);
     if (rc == 1) {
         *version10P     = TRUE;
         *isDeclarationP = TRUE;
     } else {
         int rc;
-        rc = sscanf(line, "static char %s = {", nameAndType);
+        rc = sscanf(line, "static unsigned short %s = {", nameAndType);
         if (rc == 1) {
-            *version10P     = FALSE;
+            /* This is apparently not legal X10 XBM; we recognize it as an
+               extension.  Many non-Netpbm programs won't.
+            */
+            *version10P     = TRUE;
             *isDeclarationP = TRUE;
         } else {
             int rc;
-            rc = sscanf(line, "static unsigned char %s = {", nameAndType);
+            rc = sscanf(line, "static char %s = {", nameAndType);
             if (rc == 1) {
                 *version10P     = FALSE;
                 *isDeclarationP = TRUE;
-            } else
-                *isDeclarationP = FALSE;
+            } else {
+                int rc;
+                rc = sscanf(line, "static unsigned char %s = {", nameAndType);
+                if (rc == 1) {
+                    *version10P     = FALSE;
+                    *isDeclarationP = TRUE;
+                } else
+                    *isDeclarationP = FALSE;
+            }
         }
     }
 }
@@ -178,7 +188,7 @@ getXbmHeader(FILE *         const ifP,
         }
     }
 
-    if (!foundDeclaration) 
+    if (!foundDeclaration)
         pm_error("Unable to find a line in the file containing the start "
                  "of C array declaration (\"static char\" or whatever)");
 
@@ -208,7 +218,7 @@ getHexByte(FILE *         const ifP,
 
     assert(c1 >= 0); assert(c1 < 256);
     assert(c2 >= 0); assert(c2 < 256);
-    
+
     value = (hexTable[c1] << 4) + hexTable[c2];
     if (value >= 256)
         pm_error("Invalid XBM input.  What should be a two digit "
@@ -218,7 +228,7 @@ getHexByte(FILE *         const ifP,
 }
 
 
-                     
+
 static void
 readX10Raster(FILE *          const ifP,
               unsigned int    const rasterLength,
@@ -301,7 +311,7 @@ readBitmapFile(FILE *           const ifP,
     mustPad = (width % 16 >= 1 && width % 16 <= 8 && version10);
 
     bytesPerLine = (width + 7) / 8 + (mustPad ? 1 : 0);
-    
+
     rasterLength = bytesPerLine * height;
 
     MALLOCARRAY(data, rasterLength);
@@ -331,7 +341,7 @@ main(int    argc,
     const char * inputFileName;
     unsigned char * p;
         /* Cursor in raster data data[] */
-    
+
     initHexTable();
 
     pbm_init(&argc, argv);
@@ -339,7 +349,7 @@ main(int    argc,
     if (argc-1 > 1)
         pm_error("The only possible argument is the input file name.  "
                  "You specified %u arguments", argc-1);
-    
+
     if (argc-1 > 0)
         inputFileName = argv[1];
     else
@@ -359,7 +369,7 @@ main(int    argc,
     for (row = 0; row < rows; ++row) {
         unsigned int const bytesPerRow = pbm_packed_bytes(cols);
         unsigned int i;
-        
+
         for (i = 0; i < bytesPerRow; ++i)
             bitrow[i] = bitreverse[*p++];
 
diff --git a/converter/pbm/ybmtopbm.c b/converter/pbm/ybmtopbm.c
index ea7e66a7..36f2dee7 100644
--- a/converter/pbm/ybmtopbm.c
+++ b/converter/pbm/ybmtopbm.c
@@ -19,7 +19,7 @@ static short const ybmMagic = ( ( '!' << 8 ) | '!' );
 
 
 static void
-getinit(FILE *  const ifP,
+getinit(FILE *         const ifP,
         unsigned int * const colsP,
         unsigned int * const rowsP,
         int *          const depthP) {
@@ -80,7 +80,7 @@ main(int argc, const char * argv[]) {
     getinit(ifP, &cols, &rows, &depth);
     if (depth != 1)
         pm_error("YBM file has depth of %u, must be 1", (unsigned int) depth);
-    
+
     pbm_writepbminit(stdout, cols, rows, 0);
 
     bitrow = pbm_allocrow_packed(cols + 8);
@@ -95,7 +95,7 @@ main(int argc, const char * argv[]) {
         for (i = 0; i < itemCt; ++i) {
             short int item;
             pm_readbigshort(ifP, &item);
-            itemrow[i] = (uint16_t) item; 
+            itemrow[i] = (uint16_t) item;
         }
 
         for (i = 0; i < pbm_packed_bytes(cols); ++i)
diff --git a/converter/pgm/rawtopgm.c b/converter/pgm/rawtopgm.c
index 2e5fbb7d..7eb68694 100644
--- a/converter/pgm/rawtopgm.c
+++ b/converter/pgm/rawtopgm.c
@@ -10,6 +10,7 @@
 ** implied warranty.
 */
 
+#include <stdbool.h>
 #include <math.h>
 
 #include "pm_c_util.h"
@@ -17,7 +18,7 @@
 #include "shhopt.h"
 #include "pgm.h"
 
-struct cmdline_info {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -37,8 +38,8 @@ struct cmdline_info {
 
 
 static void
-parse_command_line(int argc, char ** argv,
-                   struct cmdline_info *cmdlineP) {
+parseCommandLine(int argc, const 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.
@@ -73,7 +74,7 @@ parse_command_line(int argc, char ** argv,
             NULL,   0);
 
     /* Set the defaults */
-    cmdlineP->bottomfirst = FALSE;
+    cmdlineP->bottomfirst = false;
     cmdlineP->headerskip = 0;
     cmdlineP->rowskip = 0.0;
     cmdlineP->bpp = 1;
@@ -81,33 +82,33 @@ parse_command_line(int argc, char ** argv,
     cmdlineP->maxval = -1;
 
     opt.opt_table = option_def;
-    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
-    opt.allowNegNum = FALSE;  /* We may have parms that are negative numbers */
+    opt.short_allowed = false;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = false;  /* We may have parms that are negative numbers */
 
-    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (argc-1 == 0) {
         cmdlineP->inputFileName = "-";
-        cmdlineP->autosize = TRUE;
+        cmdlineP->autosize = true;
     } else if (argc-1 == 1) {
         cmdlineP->inputFileName = argv[1];
-        cmdlineP->autosize = TRUE;
+        cmdlineP->autosize = true;
     } else if (argc-1 == 2) {
         cmdlineP->inputFileName = "-";
-        cmdlineP->autosize = FALSE;
+        cmdlineP->autosize = false;
         cmdlineP->width = pm_parse_width(argv[1]);
         cmdlineP->height = pm_parse_height(argv[2]);
     } else if (argc-1 == 3) {
         cmdlineP->inputFileName = argv[3];
-        cmdlineP->autosize = FALSE;
+        cmdlineP->autosize = false;
         cmdlineP->width = pm_parse_width(argv[1]);
         cmdlineP->height = pm_parse_height(argv[2]);
     } else
         pm_error("Program takes zero, one, two, or three arguments.  You "
                  "specified %d", argc-1);
 
-    if (cmdlineP->bpp != 1 && cmdlineP->bpp != 2) 
+    if (cmdlineP->bpp != 1 && cmdlineP->bpp != 2)
         pm_error("Bytes per pixel (-bpp) must be 1 or 2.  You specified %d.",
                  cmdlineP->bpp);
 
@@ -125,7 +126,7 @@ parse_command_line(int argc, char ** argv,
         pm_error("If you specify -rowskip, you must also give the image "
                  "dimensions.");
     if (cmdlineP->rowskip && cmdlineP->bottomfirst)
-        pm_error("You canot specify both -rowskip and -bottomfirst.  This is "
+        pm_error("You cannot specify both -rowskip and -bottomfirst.  This is "
                  "a limitation of this program.");
 
 }
@@ -133,52 +134,59 @@ parse_command_line(int argc, char ** argv,
 
 
 static void
-compute_image_size(const struct cmdline_info cmdline, const long nread,
-                   int * const rows_p, int * const cols_p) {
+computeImageSize(struct CmdlineInfo const cmdline,
+                 long               const nRead,
+                 unsigned int *     const rowsP,
+                 unsigned int *     const colsP) {
 
     if (cmdline.autosize) {
-        int sqrt_trunc = 
-            (int) sqrt((double) (nread-cmdline.headerskip));
-        if (sqrt_trunc*sqrt_trunc+cmdline.headerskip != nread) 
+        int sqrtTrunc =
+            (int) sqrt((double) (nRead - cmdline.headerskip));
+        if (sqrtTrunc * sqrtTrunc + cmdline.headerskip != nRead)
             pm_error( "You must specify the dimensions of the image unless "
                       "it is a quadratic image.  This one is not quadratic: "
                       "The number of "
                       "pixels in the input is %ld, which is not a perfect "
-                      "square.", nread-cmdline.headerskip);
-        *rows_p = *cols_p = sqrt_trunc;
-        pm_message( "Image size: %d cols, %d rows", *cols_p, *rows_p);
+                      "square.", nRead - cmdline.headerskip);
+        *rowsP = *colsP = sqrtTrunc;
+        pm_message( "Image size: %u cols, %u rows", *colsP, *rowsP);
     } else {
-        *rows_p = cmdline.height;
-        *cols_p = cmdline.width;
+        *rowsP = cmdline.height;
+        *colsP = cmdline.width;
     }
 }
 
 
 
 static void
-skip_header(FILE *ifp, const int headerskip) {
+skipHeader(FILE *       const ifP,
+           unsigned int const headerskip) {
+
     int i;
 
-    for ( i = 0; i < headerskip; ++i ) {
+    for (i = 0; i < headerskip; ++i) {
         /* Read a byte out of the file */
         int val;
-        val = getc( ifp );
-        if ( val == EOF )
-            pm_error("EOF / read error reading Byte %d in the header", i );
+        val = getc(ifP);
+        if (val == EOF)
+            pm_error("EOF / read error reading Byte %u in the header", i );
     }
 }
 
 
 
 static gray
-read_from_file(FILE *ifp, const int bpp, const int row, const int col,
-               const int littleendian) {
+readFromFile(FILE *        const ifP,
+             unsigned int  const bpp,
+             unsigned int  const row,
+             unsigned int  const col,
+             bool          const littleEndian) {
 /*----------------------------------------------------------------------------
-   Return the next sample value from the input file 'ifp', assuming the
+   Return the next sample value from the input file *ifP, assuming the
    input stream is 'bpp' bytes per pixel (1 or 2).  In the case of two
-   bytes, if 'littleendian', assume least significant byte is first.
+   bytes, if 'littleEndian', assume least significant byte is first.
    Otherwise, assume MSB first.
-   
+
    In error messages, say this is Column 'col', Row 'row'.  Exit program if
    error.
 -----------------------------------------------------------------------------*/
@@ -186,18 +194,18 @@ read_from_file(FILE *ifp, const int bpp, const int row, const int col,
 
     if (bpp == 1) {
         int val;
-        val = getc(ifp);
+        val = getc(ifP);
         if (val == EOF)
-            pm_error( "EOF / read error at Row %d Column %d",
+            pm_error( "EOF / read error at Row %u Column %u",
                       row, col);
         retval = (gray) val;
     } else {
         short val;
         int rc;
-        rc = littleendian ? 
-            pm_readlittleshort(ifp, &val) : pm_readbigshort(ifp, &val);
+        rc = littleEndian ?
+            pm_readlittleshort(ifP, &val) : pm_readbigshort(ifP, &val);
         if (rc != 0)
-            pm_error( "EOF / read error at Row %d Column %d",
+            pm_error( "EOF / read error at Row %u Column %u",
                       row, col);
         retval = (gray) val;
     }
@@ -207,87 +215,93 @@ read_from_file(FILE *ifp, const int bpp, const int row, const int col,
 
 
 int
-main(int argc, char *argv[] ) {
+main(int argc, const char ** argv) {
 
-    struct cmdline_info cmdline;
-    FILE* ifp;
-    gray* grayrow;
-    int rows, cols;
+    struct CmdlineInfo cmdline;
+    FILE * ifP;
+    gray * grayrow;
+    unsigned int rows, cols;
     gray maxval;
-    char* buf;
-    /* pixels_1 and pixels_2 are the array of pixels in the input buffer
-       (assuming we are using an input buffer).  pixels_1 is the array
-       as if the pixels are one byte each.  pixels_2 is the array as if
+    char * buf;
+    /* pixels1 and pixels2 are the array of pixels in the input buffer
+       (assuming we are using an input buffer).  pixels1 is the array
+       as if the pixels are one byte each.  pixels2 is the array as if
        they are two bytes each.
        */
-    unsigned char *pixels_1;  
-    unsigned short *pixels_2;
-    long nread;
-    int row;
+    unsigned char * pixels1;
+    unsigned short * pixels2;
+    long nRead;
+    unsigned int row;
     float toskip;
 
-    pgm_init( &argc, argv );
+    pm_proginit(&argc, argv);
 
-    parse_command_line(argc, argv, &cmdline);
+    parseCommandLine(argc, argv, &cmdline);
 
-    ifp = pm_openr(cmdline.inputFileName);
+    ifP = pm_openr(cmdline.inputFileName);
 
     if (cmdline.autosize || cmdline.bottomfirst) {
-        buf = pm_read_unknown_size( ifp, &nread );
-        pixels_1 = (unsigned char *) buf;
-        pixels_2 = (unsigned short *) buf;
+        buf = pm_read_unknown_size(ifP, &nRead);
+        pixels1 = (unsigned char *) buf;
+        pixels2 = (unsigned short *) buf;
     } else
         buf = NULL;
 
-    compute_image_size(cmdline, nread, &rows, &cols);
+    computeImageSize(cmdline, nRead, &rows, &cols);
 
     if (!buf)
-        skip_header(ifp, cmdline.headerskip);
+        skipHeader(ifP, cmdline.headerskip);
 
     toskip = 0.00001;
 
     if (cmdline.maxval == -1)
         maxval = (cmdline.bpp == 1 ? (gray) 255 : (gray) 65535);
     else
-        maxval = (gray) cmdline.maxval;
+        maxval = cmdline.maxval;
 
-    pgm_writepgminit( stdout, cols, rows, maxval, 0 );
-    grayrow = pgm_allocrow( cols );
+    pgm_writepgminit(stdout, cols, rows, maxval, 0);
 
-    for ( row = 0; row < rows; ++row) {
-        int col;
+    grayrow = pgm_allocrow(cols);
+
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
         unsigned int rowpos; /* index of this row in pixel array */
+
         if (cmdline.bottomfirst)
             rowpos = (rows-row-1) * cols;
         else
             rowpos = row * cols;
 
-        for ( col = 0; col < cols; ++col )
+        for (col = 0; col < cols; ++col) {
             if (buf) {
                 if (cmdline.bpp == 1)
-                    grayrow[col] = pixels_1[rowpos+col];
+                    grayrow[col] = pixels1[rowpos+col];
                 else
-                    grayrow[col] = pixels_2[rowpos+col];
+                    grayrow[col] = pixels2[rowpos+col];
             } else {
-                grayrow[col] = read_from_file(ifp, cmdline.bpp, 
-                                              row, col,
-                                              cmdline.littleendian);
+                grayrow[col] = readFromFile(ifP, cmdline.bpp,
+                                            row, col,
+                                            cmdline.littleendian > 0);
             }
-        for ( toskip += cmdline.rowskip; toskip >= 1.0; toskip -= 1.0 ) {
+        }
+        for (toskip += cmdline.rowskip; toskip >= 1.0; toskip -= 1.0) {
             /* Note that if we're using a buffer, cmdline.rowskip is zero */
             int val;
-            val = getc( ifp );
-            if ( val == EOF )
-                pm_error( "EOF / read error skipping bytes at the end "
-                          "of Row %d.", row);
+            val = getc(ifP);
+            if (val == EOF)
+                pm_error("EOF / read error skipping bytes at the end "
+                         "of Row %u.", row);
         }
-        pgm_writepgmrow( stdout, grayrow, cols, maxval, 0 );
+        pgm_writepgmrow(stdout, grayrow, cols, maxval, 0);
     }
-    
+
     if (buf)
         free(buf);
-    pm_close( ifp );
-    pm_close( stdout );
+    pm_close(ifP);
+    pm_close(stdout);
 
-    exit( 0 );
+    return 0;
 }
+
+
+
diff --git a/converter/pgm/st4topgm.c b/converter/pgm/st4topgm.c
index 8e4660a3..791184b7 100644
--- a/converter/pgm/st4topgm.c
+++ b/converter/pgm/st4topgm.c
@@ -69,11 +69,11 @@ writeRaster(FILE *       const ifP,
         unsigned int col;
 
         for (col = 0; col < st4Width; ++col) {
-            char c;
+            unsigned char c;
 
-            pm_readchar(ifP, &c);
+            pm_readcharu(ifP, &c);
 
-            tuplerow[col][0] = (unsigned char)c;
+            tuplerow[col][0] = c;
         }
         pnm_writepamrow(pamP, tuplerow);
     }
@@ -149,7 +149,7 @@ readFooter(FILE *             const ifP,
        109  10 Calibration factor
        119  73 Reserved
 
-       Note tha the footer is the same length as a raster row.
+       Note that the footer is the same length as a raster row.
     */
 
     bytesReadCt = fread(buffer, 1, sizeof(buffer), ifP);
diff --git a/converter/ppm/hpcdtoppm/Makefile b/converter/ppm/hpcdtoppm/Makefile
index 5777a84f..9633017e 100644
--- a/converter/ppm/hpcdtoppm/Makefile
+++ b/converter/ppm/hpcdtoppm/Makefile
@@ -7,11 +7,29 @@ VPATH=.:$(SRCDIR)/$(SUBDIR)
 
 include $(BUILDDIR)/config.mk
 
-all: hpcdtoppm
+SCRIPTS =  pcdovtoppm
+
+ifeq ($(file <hpcdtoppm-import/Makefile)x,x)
+  # The file does not exist, which means user did not augment the
+  # Netpbm source tree by adding hpcdtoppm source code.
+  #
+  # Therefore, we package the dummy 'hpcdtoppm' program that just tells the
+  # user how to get the real one.
+  #
+  # See README in this directory.
+  #
+  # (Note that empty file and nonexistent file look the same with
+  # $(file)).
+  SCRIPTS += hpcdtoppm
+else
+  SUBDIRS += hpcdtoppm-import
+endif
 
-SCRIPTS = hpcdtoppm pcdovtoppm
 MERGE_OBJECTS =
 
+.PHONY: all
+all: $(BINARIES) $(SUBDIRS:%=%/all)
+
 include $(SRCDIR)/common.mk
 
 install.bin install.merge: install.bin.local
diff --git a/converter/ppm/hpcdtoppm/README b/converter/ppm/hpcdtoppm/README
index a1c7c8c2..ec23ec1b 100644
--- a/converter/ppm/hpcdtoppm/README
+++ b/converter/ppm/hpcdtoppm/README
@@ -1,20 +1,25 @@
-This 'hpcdtoppm' directory is really just a placeholder for the real
-Hpcdtoppm source code.  
+The 'hpcdtoppm' code in this directory is just a dummy version of the program
+that tells you where to get the real code.
 
-The real Hpcdtoppm source code cannot be distributed on Sourceforge
-because a copyright holder does not license it in a way open enough to
-meet Sourceforge's requirements.
+The real "hpcdtoppm' source code cannot be distributed on Sourceforge because
+a copyright holder does not license it in a way open enough to meet
+Sourceforge's requirements.
 
-Therefore, the Netpbm maintainer distributes Hpcdtoppm via another channel
-and distributes this dummy directory in the main Netpbm source tree on 
-Sourceforge.  When you run the program named 'hpcdtoppm' in this directory,
-it tells you how to get the real Hpcdtoppm.
+Therefore, the Netpbm maintainer distributes 'hpcdtoppm' via another channel
+and distributes this dummy directory in the main Netpbm source tree on
+Sourceforge.
 
-When you get the real Hpcdtoppm tarball, just unpack it and replace
-this entire 'hpcdtoppm' directory with its contents.  Then build
-Netpbm normally.
+The code is at 
+
+  http://ibiblio.org/pub/Linux/apps/graphics/convert/hpcdtoppm-netpbm.tgz
+
+When you get the real 'hpcdtoppm' tarball, just unpack its contents into the
+'hpcdtoppm-import' subdirectory.  Then build Netpbm normally.  The build
+detects the presence of the code and builds and packages the real 'hpcdtoppm'
+program instead of the dummy one.
+
+Bear in mind when you get the real 'hpcdtoppm' that it is not as openly
+licensed as what's in the rest of the Netpbm source tree.  As you'll see in
+the license that comes with 'hpcdtoppm', you may _not_ sell it to someone
+else.)
 
-Bear in mind when you get the real Hpcdtoppm, that it is not as openly
-licensed as what's in the rest of the Netpbm source tree.  As you'll
-see in the license that comes with Hpcdtoppm, you may _not_ sell it to
-someone else.)
diff --git a/converter/ppm/hpcdtoppm/hpcdtoppm b/converter/ppm/hpcdtoppm/hpcdtoppm
index 2af4a384..2a61aa9d 100755
--- a/converter/ppm/hpcdtoppm/hpcdtoppm
+++ b/converter/ppm/hpcdtoppm/hpcdtoppm
@@ -8,18 +8,16 @@ The real 'hpcdtoppm' is a program that converts an image from Photo CD format
 to PPM format.  The program you are running now just issues the message you
 are reading.
 
-Please get a copy of Hpcdtoppm from 
-
-  http://terasaur.org/item/show/hpcdtoppm-netpbm-convert-photo-cd/4967
-
-and replace this stand-in program with the real one.
+Instructions for getting the 'hpcdtoppm' source code and building it into
+Netpbm are in the file converter/ppm/hpcdtoppm/README in the distributed
+Netpbm source tree.
 
 The point of this is that this stand-in 'hpcdtoppm' is distributed with Netpbm
-on Sourceforge.  Hpcdtoppm does not meet the requirements to be distributed on
-Sourceforge because a copyright holder does not permit people to sell copies.
-At one time, the real Hpcdtoppm was distributed with Netpbm on Sourceforge by
-mistake.
+on Sourceforge.  'hpcdtoppm' does not meet the requirements to be distributed
+on Sourceforge because a copyright holder does not permit people to sell
+copies.  At one time, the real 'hpcdtoppm' was distributed with Netpbm on
+Sourceforge by mistake.
 
 EOF
 
-exit 1
\ No newline at end of file
+exit 1
diff --git a/converter/ppm/hpcdtoppm/pcdovtoppm b/converter/ppm/hpcdtoppm/pcdovtoppm
index 01a68313..2a875690 100755
--- a/converter/ppm/hpcdtoppm/pcdovtoppm
+++ b/converter/ppm/hpcdtoppm/pcdovtoppm
@@ -19,12 +19,16 @@
 # Rewritten in sh by Steve McIntyre <93sam@debian.org>, 2001
 
 # You may want to change the default values in the next 6 lines:
-maxwidth=1152   # maximum width of the index image
-size=192                # make the images about this big
-across=6                # show this many images per row
-colors="noquant"        # maximum amount of colors or noquant (no quantization)
-back="-black"   # default background color
-font=" "                # default font or none (pbmtext's internal font)
+maxwidth=1152     # maximum width of the index image
+size=192          # make the images about this big
+across=6          # show this many images per row
+colors="noquant"  # maximum amount of colors or noquant (no quantization)
+back="-black"     # default background color
+font=" "          # default font or none (pbmtext's internal font)
+
+plainopt=""       # output plain ppm
+quietopt=""       # quiet operation (currently no effect)
+versionopt=0
 
 usage ()
 {
@@ -47,79 +51,108 @@ usage ()
     exit 1
 }
 
+version ()
+{
+    # report version using pnmscale
+    pnmscale -version $quietopt
+    exit 0
+}
+
 # Parse the options
 while :; do
     case "$1" in 
-        -m*)
+        -m|-ma|-max|-maxw|-maxwi|-maxwid|-maxwidt|-maxwidth )
              if [ $# -lt 2 ] ; then usage; fi
              maxwidth="$2"
              shift
              shift
              ;;
 
-        -s*)
+        -s|-si|-siz|-size )
              if [ $# -lt 2 ] ; then usage; fi
              size="$2"
              shift
              shift
              ;;
 
-            -a*)
-                if [ $# -lt 2 ] ; then usage; fi
-                across="$2"
-                shift
-                shift
-                ;;
-
-            -c*)
-                if [ $# -lt 2 ] ; then usage; fi
-                colors="$2"
-                shift
-                shift
-                ;;
-
-            -f*)
-                if [ $# -lt 2 ] ; then usage; fi
-                font="-font $2"
-                shift
-                shift
-                ;;
-
-            -b*)
-                back="-black"
-                shift
-                ;;
-
-            -w*)
-                back="-white"
-                shift
-                ;;
-
-            -*)
-                echo "$0 : Unknown option $1"
-                echo " "
-                usage
-                ;;
-
-            *)
-                break
-                ;;
+         -a|-ac|-acr|-acro|-acros|-across )
+             if [ $# -lt 2 ] ; then usage; fi
+             across="$2"
+             shift
+             shift
+             ;;
+
+         -c|-co|-col|-colo|-color|-colors )
+             if [ $# -lt 2 ] ; then usage; fi
+             colors="$2"
+             shift
+             shift
+             ;;
+
+         -f|-fo|-fon|-font )
+             if [ $# -lt 2 ] ; then usage; fi
+             font="-font $2"
+             shift
+             shift
+             ;;
+
+         -b|-bl|-bla|-blac|-black )
+             back="-black"
+             shift
+             ;;
+
+         -w|-wh|-whi|-whit|-white )
+             back="-white"
+             shift
+             ;;
+             
+         -p|-pl|-pla|-plai|-plain )
+             plainopt="-plain"
+             shift
+             ;;
+            
+         -q|-qu|-qui|-quie|-quiet )
+             quietopt="-quiet"
+             shift
+             ;;
+             
+         -v|-ve|-ver|-vers|-versi|-versio|-version )
+             versionopt="1"
+             shift
+             ;;
+                    
+         -*)
+             echo "$0 : Unknown option $1" 1>&2
+             echo " " 1>&2
+             usage
+             ;;
+
+         *)
+             break
+             ;;
 
     esac
 done
 
-if [ $# = 0 ]; then
+if [ $versionopt -eq 1 ] ; then
+    version
+elif [ $# -eq 0 ] ; then
     usage
 fi
 
-tmpfile=`tempfile -p pi -m 600`
+tempdir=$(mktemp -d "${TMPDIR:-/tmp}/pcdovtoppm.XXXXXXXX") ||
+    { echo "Could not create temporary file. Exiting." 1>&2; exit 1; }
+trap 'rm -rf $tempdir' 0
+
+tmpfile=$(mktemp --tmpdir piXXXXXX)
 
 # Convert the PCD overview file to many PPM images
 if [ -f $1 ] ; then
-    hpcdtoppm -Overview $1 $tmpfile
+    hpcdtoppm -Overview $1 $tmpfile ||
+        { echo "$0: Hpcdtoppm failed. Exiting" 1>&2 ; exit 1; }
 else
-    echo "$0 : Could not access $1"
-    echo " "
+    echo "$0 : Could not access $1" 1>&2
+    echo " " 1>&2
     usage
 fi
 
@@ -145,16 +178,17 @@ do
             fi
         fi
     fi
-    imagefile=pi.${row}.${col}.$$
+    imagefile=${tempdir}/pi.${row}.${col}
     rm -f $imagefile
     ttext="$i:t"
 
     if [ "$back" = "-white" ] ; then
-        pbmtext $font "$ttext" | pnmcrop -quiet | pnmmargin -white 2| \
-        pnmcat $back -tb $tmpfile - > $imagefile
+        pbmtext $font "$ttext" | pnmcrop -quiet | pnmmargin -white 2 | \
+        pamcat $back -topbottom $tmpfile - > $imagefile
     else
         pbmtext $font "$ttext" | pnmcrop -quiet | pnmmargin -white 2 | \
-        pnminvert | pnmcat $back -tb $tmpfile - > $imagefile
+          pnminvert | \
+          pamcat $back -topbottom $tmpfile - > $imagefile
     fi
 
     rm -f $tmpfile
@@ -163,12 +197,12 @@ do
     imagefiles="$imagefiles $imagefile"
 
     if [ $col -ge $across -o $width -gt $maxwidth ] ; then
-        rowfile=pi.${row}.$$
+        rowfile=${tempdir}/pi.${row}
         rm -f $rowfile
     if [ "$colors" = "n" ] ; then
-        pnmcat $back -lr -jbottom $imagefiles > $rowfile
+        pamcat $back -leftright -jbottom $imagefiles > $rowfile
     else
-        pnmcat $back -lr -jbottom $imagefiles | \
+        pamcat $back -leftright -jbottom $imagefiles | \
         ppmquant -quiet $colors > $rowfile
     fi
     rm -f $imagefiles
@@ -183,25 +217,27 @@ do
 done
 
 if [ -n $imagefiles ] ; then
-    rowfile=pi.${row}.$$
+    rowfile=${tempdir}/pi.${row}
     rm -f $rowfile
     if [ "$colors" = "n" ] ; then
-        pnmcat $back -lr -jbottom $imagefiles > $rowfile
+        pamcat $back -leftright -jbottom $imagefiles > $rowfile
     else
-        pnmcat $back -lr -jbottom $imagefiles | \
-        ppmquant -quiet $colors > $rowfile
+        pamcat $back -leftright -jbottom $imagefiles | \
+          ppmquant -quiet $colors > $rowfile
     fi
     rm -f $imagefiles
     rowfiles="$rowfiles $rowfile"
 fi
 
 if [ $(echo $rowfiles|wc -w) -eq 1 ] ; then
-    cat $rowfiles
+    ppmtoppm $plainopt < $rowfiles
 else
     if [ "$colors" = "n" ] ; then
-        pnmcat $back -tb $rowfiles
+        pamcat $back -topbottom $rowfiles | \
+          ppmtoppm $plainopt
     else
-        pnmcat $back -tb $rowfiles | ppmquant -quiet $colors
+        pamcat $back -tb $rowfiles | \
+          ppmquant $plainopt -quiet $colors
     fi
 fi
 
@@ -210,5 +246,3 @@ rm -f $rowfiles
 exit 0
 
 
-
-
diff --git a/converter/ppm/ilbm.h b/converter/ppm/ilbm.h
index dbe47758..c0fac7d2 100644
--- a/converter/ppm/ilbm.h
+++ b/converter/ppm/ilbm.h
@@ -25,8 +25,8 @@ typedef struct {
 #define mskHasTransparentColor  2
 #define mskLasso                3       /* can't handle this */
 #define mskMAXKNOWN             mskLasso
-static const char * mskNAME[] = { 
-    "none", "mask plane", "transparent color", "lasso" 
+static const char * mskNAME[] = {
+    "none", "mask plane", "transparent color", "lasso"
 };
 
 #define cmpNone                 0
@@ -147,98 +147,98 @@ typedef unsigned long   IFF_ID;
 #define MAKE_ID(a, b, c, d) \
     ((IFF_ID)(a)<<24 | (IFF_ID)(b)<<16 | (IFF_ID)(c)<<8 | (IFF_ID)(d))
 
-#define ID_FORM     MAKE_ID('F', 'O', 'R', 'M')     
+#define ID_FORM     MAKE_ID('F', 'O', 'R', 'M')
     /* EA IFF 85 group identifier */
-#define ID_CAT      MAKE_ID('C', 'A', 'T', ' ')     
+#define ID_CAT      MAKE_ID('C', 'A', 'T', ' ')
     /* EA IFF 85 group identifier */
-#define ID_LIST     MAKE_ID('L', 'I', 'S', 'T')     
+#define ID_LIST     MAKE_ID('L', 'I', 'S', 'T')
     /* EA IFF 85 group identifier */
-#define ID_PROP     MAKE_ID('P', 'R', 'O', 'P')     
+#define ID_PROP     MAKE_ID('P', 'R', 'O', 'P')
     /* EA IFF 85 group identifier */
-#define ID_END      MAKE_ID('E', 'N', 'D', ' ')     
+#define ID_END      MAKE_ID('E', 'N', 'D', ' ')
     /* unofficial END-of-FORM identifier (see Amiga RKM Devices Ed.3
        page 376) */
-#define ID_ILBM     MAKE_ID('I', 'L', 'B', 'M')     
+#define ID_ILBM     MAKE_ID('I', 'L', 'B', 'M')
     /* EA IFF 85 raster bitmap form */
-#define ID_DEEP     MAKE_ID('D', 'E', 'E', 'P')     
+#define ID_DEEP     MAKE_ID('D', 'E', 'E', 'P')
     /* Chunky pixel image files (Used in TV Paint) */
-#define ID_RGB8     MAKE_ID('R', 'G', 'B', '8')     
+#define ID_RGB8     MAKE_ID('R', 'G', 'B', '8')
     /* RGB image forms, Turbo Silver (Impulse) */
-#define ID_RGBN     MAKE_ID('R', 'G', 'B', 'N')     
+#define ID_RGBN     MAKE_ID('R', 'G', 'B', 'N')
     /* RGB image forms, Turbo Silver (Impulse) */
-#define ID_PBM      MAKE_ID('P', 'B', 'M', ' ')     
+#define ID_PBM      MAKE_ID('P', 'B', 'M', ' ')
     /* 256-color chunky format (DPaint 2 ?) */
-#define ID_ACBM     MAKE_ID('A', 'C', 'B', 'M')     
+#define ID_ACBM     MAKE_ID('A', 'C', 'B', 'M')
     /* Amiga Contiguous Bitmap (AmigaBasic) */
 
 /* generic */
 
-#define ID_FVER     MAKE_ID('F', 'V', 'E', 'R')     
+#define ID_FVER     MAKE_ID('F', 'V', 'E', 'R')
     /* AmigaOS version string */
-#define ID_JUNK     MAKE_ID('J', 'U', 'N', 'K')     
+#define ID_JUNK     MAKE_ID('J', 'U', 'N', 'K')
     /* always ignore this chunk */
-#define ID_ANNO     MAKE_ID('A', 'N', 'N', 'O')     
+#define ID_ANNO     MAKE_ID('A', 'N', 'N', 'O')
     /* EA IFF 85 Generic Annotation chunk */
-#define ID_AUTH     MAKE_ID('A', 'U', 'T', 'H')     
+#define ID_AUTH     MAKE_ID('A', 'U', 'T', 'H')
     /* EA IFF 85 Generic Author chunk */
-#define ID_CHRS     MAKE_ID('C', 'H', 'R', 'S')     
+#define ID_CHRS     MAKE_ID('C', 'H', 'R', 'S')
     /* EA IFF 85 Generic character string chunk */
-#define ID_NAME     MAKE_ID('N', 'A', 'M', 'E')     
+#define ID_NAME     MAKE_ID('N', 'A', 'M', 'E')
     /* EA IFF 85 Generic Name of art, music, etc. chunk */
-#define ID_TEXT     MAKE_ID('T', 'E', 'X', 'T')     
+#define ID_TEXT     MAKE_ID('T', 'E', 'X', 'T')
     /* EA IFF 85 Generic unformatted ASCII text chunk */
-#define ID_copy     MAKE_ID('(', 'c', ')', ' ')     
+#define ID_copy     MAKE_ID('(', 'c', ')', ' ')
 /* EA IFF 85 Generic Copyright text chunk */
 
 /* ILBM chunks */
 
-#define ID_BMHD     MAKE_ID('B', 'M', 'H', 'D')     
+#define ID_BMHD     MAKE_ID('B', 'M', 'H', 'D')
     /* ILBM BitmapHeader */
-#define ID_CMAP     MAKE_ID('C', 'M', 'A', 'P')     
+#define ID_CMAP     MAKE_ID('C', 'M', 'A', 'P')
     /* ILBM 8bit RGB colormap */
-#define ID_GRAB     MAKE_ID('G', 'R', 'A', 'B')     
-    /* ILBM "hotspot" coordiantes */
-#define ID_DEST     MAKE_ID('D', 'E', 'S', 'T')     
+#define ID_GRAB     MAKE_ID('G', 'R', 'A', 'B')
+    /* ILBM "hotspot" coordinates */
+#define ID_DEST     MAKE_ID('D', 'E', 'S', 'T')
     /* ILBM destination image info */
-#define ID_SPRT     MAKE_ID('S', 'P', 'R', 'T')     
+#define ID_SPRT     MAKE_ID('S', 'P', 'R', 'T')
     /* ILBM sprite identifier */
-#define ID_CAMG     MAKE_ID('C', 'A', 'M', 'G')     
+#define ID_CAMG     MAKE_ID('C', 'A', 'M', 'G')
     /* Amiga viewportmodes */
-#define ID_BODY     MAKE_ID('B', 'O', 'D', 'Y')     
+#define ID_BODY     MAKE_ID('B', 'O', 'D', 'Y')
     /* ILBM image data */
-#define ID_CRNG     MAKE_ID('C', 'R', 'N', 'G')     
+#define ID_CRNG     MAKE_ID('C', 'R', 'N', 'G')
     /* color cycling */
-#define ID_CCRT     MAKE_ID('C', 'C', 'R', 'T')     
+#define ID_CCRT     MAKE_ID('C', 'C', 'R', 'T')
     /* color cycling */
-#define ID_CLUT     MAKE_ID('C', 'L', 'U', 'T')     
+#define ID_CLUT     MAKE_ID('C', 'L', 'U', 'T')
     /* Color Lookup Table chunk */
-#define ID_DPI      MAKE_ID('D', 'P', 'I', ' ')     
+#define ID_DPI      MAKE_ID('D', 'P', 'I', ' ')
     /* Dots per inch chunk */
-#define ID_DPPV     MAKE_ID('D', 'P', 'P', 'V')     
+#define ID_DPPV     MAKE_ID('D', 'P', 'P', 'V')
     /* DPaint perspective chunk (EA) */
-#define ID_DRNG     MAKE_ID('D', 'R', 'N', 'G')     
+#define ID_DRNG     MAKE_ID('D', 'R', 'N', 'G')
     /* DPaint IV enhanced color cycle chunk (EA) */
-#define ID_EPSF     MAKE_ID('E', 'P', 'S', 'F')     
+#define ID_EPSF     MAKE_ID('E', 'P', 'S', 'F')
     /* Encapsulated Postscript chunk */
-#define ID_CMYK     MAKE_ID('C', 'M', 'Y', 'K')     
+#define ID_CMYK     MAKE_ID('C', 'M', 'Y', 'K')
     /* Cyan, Magenta, Yellow, & Black color map (Soft-Logik) */
-#define ID_CNAM     MAKE_ID('C', 'N', 'A', 'M')     
+#define ID_CNAM     MAKE_ID('C', 'N', 'A', 'M')
     /* Color naming chunk (Soft-Logik) */
-#define ID_PCHG     MAKE_ID('P', 'C', 'H', 'G')     
+#define ID_PCHG     MAKE_ID('P', 'C', 'H', 'G')
     /* Line by line palette control information (Sebastiano Vigna) */
-#define ID_PRVW     MAKE_ID('P', 'R', 'V', 'W')     
+#define ID_PRVW     MAKE_ID('P', 'R', 'V', 'W')
     /* A mini duplicate ILBM used for preview (Gary Bonham) */
-#define ID_XBMI     MAKE_ID('X', 'B', 'M', 'I')     
+#define ID_XBMI     MAKE_ID('X', 'B', 'M', 'I')
     /* eXtended BitMap Information (Soft-Logik) */
-#define ID_CTBL     MAKE_ID('C', 'T', 'B', 'L')     
+#define ID_CTBL     MAKE_ID('C', 'T', 'B', 'L')
     /* Newtek Dynamic Ham color chunk */
-#define ID_DYCP     MAKE_ID('D', 'Y', 'C', 'P')     
+#define ID_DYCP     MAKE_ID('D', 'Y', 'C', 'P')
     /* Newtek Dynamic Ham chunk */
-#define ID_SHAM     MAKE_ID('S', 'H', 'A', 'M')     
+#define ID_SHAM     MAKE_ID('S', 'H', 'A', 'M')
     /* Sliced HAM color chunk */
-#define ID_ABIT     MAKE_ID('A', 'B', 'I', 'T')     
+#define ID_ABIT     MAKE_ID('A', 'B', 'I', 'T')
     /* ACBM body chunk */
-#define ID_DCOL     MAKE_ID('D', 'C', 'O', 'L')     
+#define ID_DCOL     MAKE_ID('D', 'C', 'O', 'L')
     /* unofficial direct color */
 #define ID_DPPS     MAKE_ID('D', 'P', 'P', 'S')
     /* ? */
diff --git a/converter/ppm/ilbmtoppm.c b/converter/ppm/ilbmtoppm.c
index 92d4d6f2..b9b89862 100644
--- a/converter/ppm/ilbmtoppm.c
+++ b/converter/ppm/ilbmtoppm.c
@@ -1597,8 +1597,8 @@ rgbn_to_ppm(FILE *         const ifP,
  Multipalette chunk reader
 
     Currently there are three multipalette formats:
-        SHAM - sliced HAM (obselete)
-        CTBL - dynamic HAM/Hires (obselete)
+        SHAM - sliced HAM (obsolete)
+        CTBL - dynamic HAM/Hires (obsolete)
         PCHG - palette change
     There is no official documentation available for SHAM and CTBL, so
    this is mostly guesswork from other sources and hexdumps of pictures...
diff --git a/converter/ppm/picttoppm.c b/converter/ppm/picttoppm.c
index be6a3f97..ec701cfc 100644
--- a/converter/ppm/picttoppm.c
+++ b/converter/ppm/picttoppm.c
@@ -35,6 +35,7 @@
 #include "pbmfont.h"
 #include "mallocvar.h"
 #include "nstring.h"
+#include "shhopt.h"
 
 
 /*
@@ -46,31 +47,115 @@ typedef unsigned short Word;
 typedef unsigned long Longword;
 
 
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char * inputFileName;  /* File name of input file */
+
+    unsigned int fullres;
+    unsigned int noheader;
+    unsigned int quickdraw;
+    const char * fontdir;  /* Null if not specified */
+    unsigned int verbose;
+};
+
+
+
+static void
+parseCommandLine(int argc,
+                 const 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;
+    optStruct3 opt;
+        /* Instructions to pm_optParseOptions3 on how to parse our options. */
+
+    unsigned int option_def_index;
+
+    unsigned int fontdirSpec, verboseSpec;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "fontdir",     OPT_STRING,    &cmdlineP->fontdir,
+            &fontdirSpec,                     0);
+    OPTENT3(0, "fullres",     OPT_FLAG,      NULL,
+            &cmdlineP->fullres,               0);
+    OPTENT3(0, "noheader",    OPT_FLAG,      NULL,
+            &cmdlineP->noheader,              0);
+    OPTENT3(0, "quickdraw",   OPT_FLAG,      NULL,
+            &cmdlineP->quickdraw,             0);
+    OPTENT3(0, "verbose",     OPT_UINT,      &cmdlineP->verbose,
+            &verboseSpec,               0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = false;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = false;   /* We have no parms that are negative numbers */
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (!fontdirSpec)
+        cmdlineP->fontdir = NULL;
+
+    if (!verboseSpec)
+        cmdlineP->verbose = 0;
+
+    if (argc-1 < 1)
+        cmdlineP->inputFileName = "-";
+    else {
+        cmdlineP->inputFileName = argv[1];
+        if (argc-1 > 1)
+            pm_error("Too many arguments: %u.  The only possible non-option "
+                     "argument is the input file name", argc-1);
+    }
+}
+
+
+
 /*
  * Data structures for QuickDraw (and hence PICT) stuff.
  */
 
 struct Rect {
-    Word top;
-    Word left;
-    Word bottom;
-    Word right;
+/*----------------------------------------------------------------------------
+   A rectangle - description of a region of an image raster.
+
+   If last row or column is before first, it is a null rectangle - it
+   describes no pixels.
+-----------------------------------------------------------------------------*/
+    Word top;     /* Start row */
+    Word left;    /* Start column */
+    Word bottom;  /* End row */
+    Word right;   /* End column */
+
+    /* "End" means last plus one */
 };
 
-struct pixMap {
+struct PixMap {
     struct Rect Bounds;
-    Word version;
-    Word packType;
-    Longword packSize;
-    Longword hRes;
-    Longword vRes;
-    Word pixelType;
-    Word pixelSize;
-    Word cmpCount;
-    Word cmpSize;
-    Longword planeBytes;
-    Longword pmTable;
-    Longword pmReserved;
+    Word        version;
+    Word        packType;
+    Longword    packSize;
+    Longword    hRes;
+    Longword    vRes;
+    Word        pixelType;
+    Word        pixelSize;
+    Word        cmpCount;
+    Word        cmpSize;
+    Longword    planeBytes;
+    Longword    pmTable;
+    Longword    pmReserved;
 };
 
 struct RGBColor {
@@ -88,14 +173,21 @@ struct Pattern {
     Byte pix[64];
 };
 
-struct rgbPlanes {
+struct RgbPlanes {
+/*----------------------------------------------------------------------------
+   A raster, as three planes: red, green, blue.
+
+   Each plane is an array in row-major order.
+-----------------------------------------------------------------------------*/
+    unsigned int width;
+    unsigned int height;
     Word * red;
     Word * grn;
     Word * blu;
 };
 
-struct canvas {
-    struct rgbPlanes planes;
+struct Canvas {
+    struct RgbPlanes planes;
 };
 
 typedef void (*transfer_func) (struct RGBColor* src, struct RGBColor* dst);
@@ -105,7 +197,6 @@ static struct Rect picFrame;
 static Word rowlen;
 static Word collen;
 static int verbose;
-static int fullres;
 static int recognize_comment;
 
 static struct RGBColor black = { 0, 0, 0 };
@@ -142,7 +233,7 @@ static int ps_cent_x;
 static int ps_cent_y;
 static int ps_cent_set;
 
-struct raster {
+struct Raster {
 /*----------------------------------------------------------------------------
    An image raster.  May be either truecolor or paletted.
 
@@ -173,7 +264,7 @@ struct raster {
 
 
 static void
-allocateRaster(struct raster * const rasterP,
+allocateRaster(struct Raster * const rasterP,
                unsigned int    const width,
                unsigned int    const height,
                unsigned int    const bitsPerPixel) {
@@ -186,9 +277,9 @@ allocateRaster(struct raster * const rasterP,
    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
+   expressible 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.
+   Guillermo Gomez Valcarcel.
 -----------------------------------------------------------------------------*/
     unsigned int const allocWidth = ROUNDUP(width, 16);
 
@@ -202,19 +293,24 @@ allocateRaster(struct raster * const rasterP,
         /* TODO: I'm still trying to figure out this format.
 
            My theory today:
-           The row data is in plane order (a row consists of red
-           plane, then, green, then blue, then some 4th plane).
 
-           The old hack code said 3 bytes per pixel here, and could get
-           away with it because it never got to decoding the 4th plane.
+           The row data is in plane order (a row consists of red plane, then,
+           green, then blue, then some 4th plane).
 
-           But the new clean code needs to tell it like it is and allocate
-           4 bytes per pixel.  If we say 3 bytes per pixel here, we get an
-           "invalid PICT" error because the image actually contains 4
-           bytes per pixel and as we decompress it, we run out of place
-           to put the data.
+           If the image is compressed, each row is compressed separately, with
+           the planes opaque to the compressor.
 
-           We have yet to see if we can properly interpret the data.
+           The old hack code said 3 bytes per pixel here, and could get away
+           with it because it never got to decoding the 4th plane.
+
+           But the new clean code needs to tell it like it is and allocate 4
+           bytes per pixel.  If we say 3 bytes per pixel here, we get an
+           "invalid PICT" error on one image because the image actually
+           contains 4 bytes per pixel and as we decompress it, we run out of
+           place to put the data.
+
+           On another image we've seen, the decompressor generates 3 bytes per
+           pixel.
         */
 
         rasterP->rowSize = allocWidth * 4;
@@ -244,37 +340,37 @@ allocateRaster(struct raster * const rasterP,
 
 
 static void
-freeRaster(struct raster const raster) {
+freeRaster(struct Raster const raster) {
 
     free(raster.bytes);
 }
 
 
-struct blit_info {
-    struct Rect        srcRect;
-    struct Rect        srcBounds;
-    struct raster      srcplane;
-    int                pixSize;
-    struct Rect        dstRect;
-    struct RGBColor *  colorMap;
-    int                mode;
-    struct blit_info * next;
+struct BlitInfo {
+    struct Rect       srcRect;
+    struct Rect       srcBounds;
+    struct Raster     srcplane;
+    int               pixSize;
+    struct Rect       dstRect;
+    struct RGBColor * colorMap;
+    int               mode;
+    struct BlitInfo * next;
 };
 
 typedef struct {
-    struct blit_info * firstP;
-    struct blit_info ** connectorP;
+    struct BlitInfo * firstP;
+    struct BlitInfo ** 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;
+} BlitList;
 
 
-typedef void (drawFn)(struct canvas *, blitList *, int);
+typedef void (drawFn)(FILE *, struct Canvas *, BlitList *, int);
 
-struct opdef {
+struct Opdef {
     const char* name;
     int len;
         /* If non-negative, this is the length of the argument of the
@@ -307,16 +403,15 @@ struct opdef {
 #define RGB_LEN (6)
 
 
-static FILE* ifp;
 static int align = 0;
 
 
 
 static Byte
-readByte(void) {
+readByte(FILE * const ifP) {
     int c;
 
-    if ((c = fgetc(ifp)) == EOF)
+    if ((c = fgetc(ifP)) == EOF)
         pm_error("EOF / read error while %s", stage);
 
     ++align;
@@ -326,27 +421,29 @@ readByte(void) {
 
 
 static Word
-readWord(void) {
+readWord(FILE * const ifP) {
 
-    Byte const hi = readByte();
-    Byte const lo = readByte();
+    Byte const hi = readByte(ifP);
+    Byte const lo = readByte(ifP);
 
     return (hi << 8) | (lo << 0);
 }
 
 
 
-static void readPoint(struct Point * const p) {
-    p->y = readWord();
-    p->x = readWord();
+static void readPoint(FILE *         const ifP,
+                      struct Point * const p) {
+    p->y = readWord(ifP);
+    p->x = readWord(ifP);
 }
 
 
 
 static Longword
-readLong(void) {
-    Word const hi = readWord();
-    Word const lo = readWord();
+readLong(FILE * const ifP) {
+
+    Word const hi = readWord(ifP);
+    Word const lo = readWord(ifP);
 
     return (hi << 16) | (lo << 0);
 }
@@ -354,40 +451,45 @@ readLong(void) {
 
 
 static SignedByte
-readSignedByte(void) {
-    return (SignedByte)readByte();
+readSignedByte(FILE * const ifP) {
+    return (SignedByte)readByte(ifP);
 }
 
 
 
 static void
-readShortPoint(struct Point * const p) {
-    p->x = readSignedByte();
-    p->y = readSignedByte();
+readShortPoint(FILE *         const ifP,
+               struct Point * const p) {
+
+    p->x = readSignedByte(ifP);
+    p->y = readSignedByte(ifP);
 }
 
 
 
 static void
-skip(int const byteCount) {
-    static Byte buf[1024];
+skip(FILE *       const ifP,
+     unsigned int const byteCount) {
+
+    Byte buf[1024];
     int n;
 
     align += byteCount;
 
-    for (n = byteCount; n > 0; n -= 1024)
-        if (fread(buf, n > 1024 ? 1024 : n, 1, ifp) != 1)
+    for (n = byteCount; n > 0; n -= 1024) {
+        if (fread(buf, n > 1024 ? 1024 : n, 1, ifP) != 1)
             pm_error("EOF / read error while %s", stage);
+    }
 }
 
 
 
-struct const_name {
+struct ConstName {
     int value;
     const char * name;
 };
 
-struct const_name const transfer_name[] = {
+struct ConstName const transfer_name[] = {
     { 0,    "srcCopy" },
     { 1,    "srcOr" },
     { 2,    "srcXor" },
@@ -407,7 +509,7 @@ struct const_name const transfer_name[] = {
     { -1,   0 }
 };
 
-struct const_name font_name[] = {
+struct ConstName font_name[] = {
     { 0,    "systemFont" },
     { 1,    "applFont" },
     { 2,    "newYork" },
@@ -428,7 +530,7 @@ struct const_name font_name[] = {
     { -1,   0 }
 };
 
-struct const_name ps_just_name[] = {
+struct ConstName ps_just_name[] = {
     { 0,    "no" },
     { 1,    "left" },
     { 2,    "center" },
@@ -437,7 +539,7 @@ struct const_name ps_just_name[] = {
     { -1,   0 }
 };
 
-struct const_name ps_flip_name[] = {
+struct ConstName ps_flip_name[] = {
     { 0,    "no" },
     { 1,    "horizontal" },
     { 2,    "vertical" },
@@ -447,8 +549,8 @@ struct const_name ps_flip_name[] = {
 
 
 static const char*
-const_name(const struct const_name * const table,
-           unsigned int              const ct) {
+constName(const struct ConstName * const table,
+          unsigned int             const ct) {
 
     static char numbuf[32];
 
@@ -465,8 +567,9 @@ const_name(const struct const_name * const table,
 
 
 static void
-picComment(Word const type,
-           int const length) {
+picComment(FILE * const ifP,
+           Word   const type,
+           int    const length) {
 
     unsigned int remainingLength;
 
@@ -474,10 +577,10 @@ picComment(Word const type,
     case 150:
         if (verbose) pm_message("TextBegin");
         if (length >= 6) {
-            ps_just = readByte();
-            ps_flip = readByte();
-            ps_rotation = readWord();
-            ps_linespace = readByte();
+            ps_just = readByte(ifP);
+            ps_flip = readByte(ifP);
+            ps_rotation = readWord(ifP);
+            ps_linespace = readByte(ifP);
             remainingLength = length - 5;
             if (recognize_comment)
                 ps_text = 1;
@@ -485,8 +588,8 @@ picComment(Word const type,
             if (verbose) {
                 pm_message("%s justification, %s flip, %d degree rotation, "
                            "%d/2 linespacing",
-                           const_name(ps_just_name, ps_just),
-                           const_name(ps_flip_name, ps_flip),
+                           constName(ps_just_name, ps_just),
+                           constName(ps_flip_name, ps_flip),
                            ps_rotation, ps_linespace);
             }
         } else
@@ -510,14 +613,14 @@ picComment(Word const type,
         if (length < 8)
             remainingLength = length;
         else {
-            ps_cent_y = readWord();
+            ps_cent_y = readWord(ifP);
             if (ps_cent_y > 32767)
                 ps_cent_y -= 65536;
-            skip(2); /* ignore fractional part */
-            ps_cent_x = readWord();
+            skip(ifP, 2); /* ignore fractional part */
+            ps_cent_x = readWord(ifP);
             if (ps_cent_x > 32767)
                 ps_cent_x -= 65536;
-            skip(2); /* ignore fractional part */
+            skip(ifP, 2); /* ignore fractional part */
             remainingLength = length - 8;
             if (verbose)
                 pm_message("offset %d %d", ps_cent_x, ps_cent_y);
@@ -613,7 +716,7 @@ picComment(Word const type,
         break;
     }
     if (remainingLength > 0)
-        skip(remainingLength);
+        skip(ifP, remainingLength);
 }
 
 
@@ -621,11 +724,12 @@ picComment(Word const type,
 static drawFn ShortComment;
 
 static void
-ShortComment(struct canvas * const canvasP,
-             blitList *      const blitListP,
+ShortComment(FILE *          const ifP,
+             struct Canvas * const canvasP,
+             BlitList *      const blitListP,
              int             const version) {
 
-    picComment(readWord(), 0);
+    picComment(ifP, readWord(ifP), 0);
 }
 
 
@@ -633,27 +737,29 @@ ShortComment(struct canvas * const canvasP,
 static drawFn LongComment;
 
 static void
-LongComment(struct canvas * const canvasP,
-            blitList *      const blitListP,
+LongComment(FILE *          const ifP,
+            struct Canvas * const canvasP,
+            BlitList *      const blitListP,
             int             const version) {
 
     Word type;
 
-    type = readWord();
-    picComment(type, readWord());
+    type = readWord(ifP);
+    picComment(ifP, type, readWord(ifP));
 }
 
 
 
-static drawFn skip_poly_or_region;
+static drawFn skipPolyOrRegion;
 
 static void
-skip_poly_or_region(struct canvas * const canvasP,
-                    blitList *      const blitListP,
-                    int             const version) {
+skipPolyOrRegion(FILE *          const ifP,
+                 struct Canvas * const canvasP,
+                 BlitList *      const blitListP,
+                 int             const version) {
 
     stage = "skipping polygon or region";
-    skip(readWord() - 2);
+    skip(ifP, readWord(ifP) - 2);
 }
 
 
@@ -669,17 +775,17 @@ skip_poly_or_region(struct canvas * const canvasP,
 
 /* Some font searching routines */
 
-struct fontinfo {
+struct FontInfo {
     int font;
     int size;
     int style;
     char* filename;
     struct font* loaded;
-    struct fontinfo* next;
+    struct FontInfo* next;
 };
 
-static struct fontinfo* fontlist = 0;
-static struct fontinfo** fontlist_ins = &fontlist;
+static struct FontInfo* fontlist = 0;
+static struct FontInfo** fontlist_ins = &fontlist;
 
 
 
@@ -714,9 +820,9 @@ tokenize(char *         const s,
 
 static void
 parseFontLine(const char **      const token,
-              struct fontinfo ** const fontinfoPP) {
+              struct FontInfo ** const fontinfoPP) {
 
-    struct fontinfo * fontinfoP;
+    struct FontInfo * fontinfoP;
 
     MALLOCVAR(fontinfoP);
     if (fontinfoP == NULL)
@@ -737,7 +843,7 @@ parseFontLine(const char **      const token,
 
 
 static int
-load_fontdir(const char * const dirfile) {
+loadFontdir(const char * const dirfile) {
 /*----------------------------------------------------------------------------
    Load the font directory from file named 'dirfile'.  Add its contents
    to the global list of fonts 'fontlist'.
@@ -762,7 +868,7 @@ load_fontdir(const char * const dirfile) {
         } else if (nToken != 4) {
             /* Unrecognized format - ignore */
         } else {
-            struct fontinfo * fontinfoP;
+            struct FontInfo * fontinfoP;
 
             parseFontLine(token, &fontinfoP);
 
@@ -780,6 +886,23 @@ load_fontdir(const char * const dirfile) {
 
 
 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;
+
+    rc = stat("fontdir", &statbuf);
+
+    if (rc == 0)
+        loadFontdir("fontdir");
+}
+
+
+
+static void
 dumpRect(const char * const label,
          struct Rect  const rectangle) {
 
@@ -792,7 +915,8 @@ dumpRect(const char * const label,
 
 
 static void
-readRect(struct Rect * const r) {
+readRect(FILE *        const ifP,
+         struct Rect * const r) {
 
     /* We don't have a formal specification for the Pict format, but we have
        seen samples that have the rectangle corners either in top left, bottom
@@ -804,10 +928,10 @@ readRect(struct Rect * const r) {
        So now we accept all 4 possibilities.
     */
 
-    Word const y1 = readWord();
-    Word const x1 = readWord();
-    Word const y2 = readWord();
-    Word const x2 = readWord();
+    Word const y1 = readWord(ifP);
+    Word const x1 = readWord(ifP);
+    Word const y2 = readWord(ifP);
+    Word const x2 = readWord(ifP);
 
     r->top    = MIN(y1, y2);
     r->left   = MIN(x1, x2);
@@ -818,14 +942,36 @@ readRect(struct Rect * const r) {
 
 
 static int
+rectisnull(struct Rect * const r) {
+
+    return r->top >= r->bottom || r->left >= r->right;
+}
+
+
+
+static int
 rectwidth(const struct Rect * const r) {
+
     return r->right - r->left;
 }
 
 
 
+static bool
+rectequal(const struct Rect * const comparand,
+          const struct Rect * const comparator) {
+
+    return
+        comparand->top    == comparator->top &&
+        comparand->bottom == comparator->bottom &&
+        comparand->left   == comparator->left &&
+        comparand->right  == comparator->right;
+}
+
+
 static int
 rectheight(const struct Rect * const r) {
+
     return r->bottom - r->top;
 }
 
@@ -834,6 +980,7 @@ rectheight(const struct Rect * const r) {
 static bool
 rectsamesize(struct Rect const r1,
              struct Rect const r2) {
+
     return r1.right - r1.left == r2.right - r2.left &&
            r1.bottom - r1.top == r2.bottom - r2.top ;
 }
@@ -841,14 +988,18 @@ rectsamesize(struct Rect const r1,
 
 
 static void
-rectinter(struct Rect   const r1,
-          struct Rect   const r2,
-          struct Rect * const intersectionP) {
+rectintersect(const struct Rect * const r1P,
+              const struct Rect * const r2P,
+              struct Rect *       const intersectionP) {
+/*----------------------------------------------------------------------------
+   Compute the intersection of two rectangles.
 
-    intersectionP->left   = MAX(r1.left,   r2.left);
-    intersectionP->top    = MAX(r1.top,    r2.top);
-    intersectionP->right  = MIN(r1.right,  r2.right);
-    intersectionP->bottom = MIN(r1.bottom, r2.bottom);
+   Note that if the rectangles are disjoint, the result is a null rectangle.
+-----------------------------------------------------------------------------*/
+    intersectionP->left   = MAX(r1P->left,   r2P->left);
+    intersectionP->top    = MAX(r1P->top,    r2P->top);
+    intersectionP->right  = MIN(r1P->right,  r2P->right);
+    intersectionP->bottom = MIN(r1P->bottom, r2P->bottom);
 }
 
 
@@ -857,16 +1008,17 @@ static void
 rectscale(struct Rect * const r,
           double        const xscale,
           double        const yscale) {
-    r->left *= xscale;
-    r->right *= xscale;
-    r->top *= yscale;
+
+    r->left   *= xscale;
+    r->right  *= xscale;
+    r->top    *= yscale;
     r->bottom *= yscale;
 }
 
 
 
 static void
-    initBlitList(blitList * const blitListP) {
+initBlitList(BlitList * const blitListP) {
 
     blitListP->firstP          = NULL;
     blitListP->connectorP      = &blitListP->firstP;
@@ -876,16 +1028,16 @@ static void
 
 
 static void
-addBlitList(blitList *        const blitListP,
+addBlitList(BlitList *        const blitListP,
             struct Rect       const srcRect,
             struct Rect       const srcBounds,
-            struct raster     const srcplane,
+            struct Raster     const srcplane,
             int               const pixSize,
             struct Rect       const dstRect,
             struct RGBColor * const colorMap,
             int               const mode) {
 
-    struct blit_info * biP;
+    struct BlitInfo * biP;
 
     MALLOCVAR(biP);
     if (biP == NULL)
@@ -902,7 +1054,7 @@ addBlitList(blitList *        const blitListP,
         biP->next = NULL;
 
         *blitListP->connectorP = biP;
-        blitListP->connectorP = &biP->next;
+        blitListP->connectorP  = &biP->next;
     }
 }
 
@@ -927,12 +1079,15 @@ rgbAllSame(const struct RGBColor * const colorP,
 }
 
 
+
 static bool
 rgbIsWhite(const struct RGBColor * const colorP) {
 
     return rgbAllSame(colorP, 0xffff);
 }
 
+
+
 static bool
 rgbIsBlack(const struct RGBColor * const colorP) {
 
@@ -940,122 +1095,133 @@ rgbIsBlack(const struct RGBColor * const colorP) {
 }
 
 
+
 static void
-srcCopy(struct RGBColor * const src,
-        struct RGBColor * const dst) {
+srcCopy(struct RGBColor * const srcP,
+        struct RGBColor * const dstP) {
 
-    if (rgbIsBlack(src))
-        *dst = foreground;
+    if (rgbIsBlack(srcP))
+        *dstP = foreground;
     else
-        *dst = background;
+        *dstP = background;
 }
 
 
 
 static void
-srcOr(struct RGBColor * const src,
-      struct RGBColor * const dst) {
-    if (rgbIsBlack(src))
-        *dst = foreground;
+srcOr(struct RGBColor * const srcP,
+      struct RGBColor * const dstP) {
+
+    if (rgbIsBlack(srcP))
+        *dstP = foreground;
 }
 
 
 
 static void
-srcXor(struct RGBColor * const src,
-       struct RGBColor * const dst) {
-    dst->red ^= ~src->red;
-    dst->grn ^= ~src->grn;
-    dst->blu ^= ~src->blu;
+srcXor(struct RGBColor * const srcP,
+       struct RGBColor * const dstP) {
+
+    dstP->red ^= ~srcP->red;
+    dstP->grn ^= ~srcP->grn;
+    dstP->blu ^= ~srcP->blu;
 }
 
 
 
 static void
-srcBic(struct RGBColor * const src,
-       struct RGBColor * const dst) {
-    if (rgbIsBlack(src))
-        *dst = background;
+srcBic(struct RGBColor * const srcP,
+       struct RGBColor * const dstP) {
+
+    if (rgbIsBlack(srcP))
+        *dstP = background;
 }
 
 
 
 static void
-notSrcCopy(struct RGBColor * const src,
-           struct RGBColor * const dst) {
-    if (rgbIsWhite(src))
-        *dst = foreground;
-    else if (rgbIsBlack(src))
-        *dst = background;
+notSrcCopy(struct RGBColor * const srcP,
+           struct RGBColor * const dstP) {
+
+    if (rgbIsWhite(srcP))
+        *dstP = foreground;
+    else if (rgbIsBlack(srcP))
+        *dstP = background;
 }
 
 
 
 static void
-notSrcOr(struct RGBColor * const src,
-         struct RGBColor * const dst) {
-    if (rgbIsWhite(src))
-        *dst = foreground;
+notSrcOr(struct RGBColor * const srcP,
+         struct RGBColor * const dstP) {
+
+    if (rgbIsWhite(srcP))
+        *dstP = foreground;
 }
 
 
 
 static void
-notSrcBic(struct RGBColor * const src,
-          struct RGBColor * const dst) {
-    if (rgbIsWhite(src))
-        *dst = background;
+notSrcBic(struct RGBColor * const srcP,
+          struct RGBColor * const dstP) {
+
+    if (rgbIsWhite(srcP))
+        *dstP = background;
 }
 
 
 
 static void
-notSrcXor(struct RGBColor * const src,
-          struct RGBColor * const dst) {
-    dst->red ^= src->red;
-    dst->grn ^= src->grn;
-    dst->blu ^= src->blu;
+notSrcXor(struct RGBColor * const srcP,
+          struct RGBColor * const dstP) {
+
+    dstP->red ^= srcP->red;
+    dstP->grn ^= srcP->grn;
+    dstP->blu ^= srcP->blu;
 }
 
 
 
 static void
-addOver(struct RGBColor * const src,
-        struct RGBColor * const dst) {
-    dst->red += src->red;
-    dst->grn += src->grn;
-    dst->blu += src->blu;
+addOver(struct RGBColor * const srcP,
+        struct RGBColor * const dstP) {
+
+    dstP->red += srcP->red;
+    dstP->grn += srcP->grn;
+    dstP->blu += srcP->blu;
 }
 
 
 
 static void
-addPin(struct RGBColor * const src,
-       struct RGBColor * const dst) {
-    if ((long)dst->red + (long)src->red > (long)op_color.red)
-        dst->red = op_color.red;
+addPin(struct RGBColor * const srcP,
+       struct RGBColor * const dstP) {
+
+    if ((long)dstP->red + (long)srcP->red > (long)op_color.red)
+        dstP->red = op_color.red;
     else
-        dst->red = dst->red + src->red;
+        dstP->red = dstP->red + srcP->red;
 
-    if ((long)dst->grn + (long)src->grn > (long)op_color.grn)
-        dst->grn = op_color.grn;
+    if ((long)dstP->grn + (long)srcP->grn > (long)op_color.grn)
+        dstP->grn = op_color.grn;
     else
-        dst->grn = dst->grn + src->grn;
+        dstP->grn = dstP->grn + srcP->grn;
 
-    if ((long)dst->blu + (long)src->blu > (long)op_color.blu)
-        dst->blu = op_color.blu;
+    if ((long)dstP->blu + (long)srcP->blu > (long)op_color.blu)
+        dstP->blu = op_color.blu;
     else
-        dst->blu = dst->blu + src->blu;
+        dstP->blu = dstP->blu + srcP->blu;
 }
 
 
 
 static void
-subOver(struct RGBColor * const src,
-        struct RGBColor * const dst) {
-    dst->red -= src->red;
-    dst->grn -= src->grn;
-    dst->blu -= src->blu;
+subOver(struct RGBColor * const srcP,
+        struct RGBColor * const dstP) {
+
+    dstP->red -= srcP->red;
+    dstP->grn -= srcP->grn;
+    dstP->blu -= srcP->blu;
 }
 
 
@@ -1064,74 +1230,81 @@ subOver(struct RGBColor * const src,
 
 
 static void
-subPin(struct RGBColor * const src,
-       struct RGBColor * const dst) {
-    if ((long)dst->red - (long)src->red < (long)op_color.red)
-        dst->red = op_color.red;
+subPin(struct RGBColor * const srcP,
+       struct RGBColor * const dstP) {
+
+    if ((long)dstP->red - (long)srcP->red < (long)op_color.red)
+        dstP->red = op_color.red;
     else
-        dst->red = dst->red - src->red;
+        dstP->red = dstP->red - srcP->red;
 
-    if ((long)dst->grn - (long)src->grn < (long)op_color.grn)
-        dst->grn = op_color.grn;
+    if ((long)dstP->grn - (long)srcP->grn < (long)op_color.grn)
+        dstP->grn = op_color.grn;
     else
-        dst->grn = dst->grn - src->grn;
+        dstP->grn = dstP->grn - srcP->grn;
 
-    if ((long)dst->blu - (long)src->blu < (long)op_color.blu)
-        dst->blu = op_color.blu;
+    if ((long)dstP->blu - (long)srcP->blu < (long)op_color.blu)
+        dstP->blu = op_color.blu;
     else
-        dst->blu = dst->blu - src->blu;
+        dstP->blu = dstP->blu - srcP->blu;
 }
 
 
 
 static void
-adMax(struct RGBColor * const src,
-      struct RGBColor * const dst) {
-    if (src->red > dst->red) dst->red = src->red;
-    if (src->grn > dst->grn) dst->grn = src->grn;
-    if (src->blu > dst->blu) dst->blu = src->blu;
+adMax(struct RGBColor * const srcP,
+      struct RGBColor * const dstP) {
+
+    if (srcP->red > dstP->red) dstP->red = srcP->red;
+    if (srcP->grn > dstP->grn) dstP->grn = srcP->grn;
+    if (srcP->blu > dstP->blu) dstP->blu = srcP->blu;
 }
 
 
 
 static void
-adMin(struct RGBColor * const src,
-      struct RGBColor * const dst) {
-    if (src->red < dst->red) dst->red = src->red;
-    if (src->grn < dst->grn) dst->grn = src->grn;
-    if (src->blu < dst->blu) dst->blu = src->blu;
+adMin(struct RGBColor * const srcP,
+      struct RGBColor * const dstP) {
+
+    if (srcP->red < dstP->red) dstP->red = srcP->red;
+    if (srcP->grn < dstP->grn) dstP->grn = srcP->grn;
+    if (srcP->blu < dstP->blu) dstP->blu = srcP->blu;
 }
 
 
 
 static void
-blend(struct RGBColor * const src,
-      struct RGBColor * const dst) {
+blend(struct RGBColor * const srcP,
+      struct RGBColor * const dstP) {
+
 #define blend_component(cmp)    \
-    ((long)src->cmp * (long)op_color.cmp) / 65536 +    \
-    ((long)dst->cmp * (long)(65536 - op_color.cmp) / 65536)
+    ((long)srcP->cmp * (long)op_color.cmp) / 65536 +    \
+    ((long)dstP->cmp * (long)(65536 - op_color.cmp) / 65536)
 
-    dst->red = blend_component(red);
-    dst->grn = blend_component(grn);
-    dst->blu = blend_component(blu);
+    dstP->red = blend_component(red);
+    dstP->grn = blend_component(grn);
+    dstP->blu = blend_component(blu);
 }
 
 
 
 static void
-transparent(struct RGBColor * const src,
-            struct RGBColor * const dst) {
-    if (src->red != background.red ||
-        src->grn != background.grn ||
-        src->blu != background.blu) {
-        *dst = *src;
+transparent(struct RGBColor * const srcP,
+            struct RGBColor * const dstP) {
+
+    if (srcP->red != background.red ||
+        srcP->grn != background.grn ||
+        srcP->blu != background.blu) {
+
+        *dstP = *srcP;
     }
 }
 
 
 
 static transfer_func
-transfer(int const mode) {
+transferFunctionForMode(unsigned int const mode) {
+
     switch (mode) {
     case  0: return srcCopy;
     case  1: return srcOr;
@@ -1150,9 +1323,8 @@ transfer(int const mode) {
     case 38: return subOver;
     case 39: return adMin;
     default:
-        if (mode != 0)
-            pm_message("no transfer function for code %s, using srcCopy",
-                const_name(transfer_name, mode));
+        pm_message("no transfer function for code %s, using srcCopy",
+                   constName(transfer_name, mode));
         return srcCopy;
     }
 }
@@ -1192,43 +1364,122 @@ decode16(unsigned char * const sixteen) {
 
 
 static void
-doDiffSize(struct Rect       const clipsrc,
-           struct Rect       const clipdst,
-           int               const pixSize,
-           int               const xsize,
-           int               const ysize,
+closeValidatePamscalePipe(FILE * const pipeP) {
+
+    int rc;
+
+    rc = pclose(pipeP);
+
+    if (rc != 0)
+        pm_error("pamscale failed.  pclose() returned Errno %s (%d)",
+                 strerror(errno), errno);
+}
+
+
+
+static void
+convertScaledPpm(const char *      const scaledFilename,
+                 transfer_func     const trf,
+                 struct RgbPlanes  const dst,
+                 unsigned int      const dstadd) {
+
+    Word * reddst;
+    Word * grndst;
+    Word * bludst;
+    FILE * scaledP;
+    int cols, rows, format;
+    pixval maxval;
+    pixel * pixrow;
+
+    reddst = &dst.red[0];  /* initial value */
+    grndst = &dst.grn[0];  /* initial value */
+    bludst = &dst.blu[0];  /* initial value */
+
+    scaledP = pm_openr(scaledFilename);
+
+    ppm_readppminit(scaledP, &cols, &rows, &maxval, &format);
+
+    pixrow = ppm_allocrow(cols);
+
+    if (trf) {
+        unsigned int row;
+
+        for (row = 0; row < rows; ++row) {
+            unsigned int col;
+
+            ppm_readppmrow(scaledP, pixrow, cols, maxval, format);
+
+            for (col = 0; col < cols; ++col) {
+                struct RGBColor dst_c, src_c;
+                dst_c.red = *reddst;
+                dst_c.grn = *grndst;
+                dst_c.blu = *bludst;
+                src_c.red = PPM_GETR(pixrow[col]) * 65536L / (maxval + 1);
+                src_c.grn = PPM_GETG(pixrow[col]) * 65536L / (maxval + 1);
+                src_c.blu = PPM_GETB(pixrow[col]) * 65536L / (maxval + 1);
+                (*trf)(&src_c, &dst_c);
+                *reddst++ = dst_c.red;
+                *grndst++ = dst_c.grn;
+                *bludst++ = dst_c.blu;
+            }
+            reddst += dstadd;
+            grndst += dstadd;
+            bludst += dstadd;
+        }
+    } else {
+        unsigned int row;
+
+        for (row = 0; row < rows; ++row) {
+            unsigned int col;
+
+            ppm_readppmrow(scaledP, pixrow, cols, maxval, format);
+
+            for (col = 0; col < cols; ++col) {
+                *reddst++ = PPM_GETR(pixrow[col]) * 65536L / (maxval + 1);
+                *grndst++ = PPM_GETG(pixrow[col]) * 65536L / (maxval + 1);
+                *bludst++ = PPM_GETB(pixrow[col]) * 65536L / (maxval + 1);
+            }
+            reddst += dstadd;
+            grndst += dstadd;
+            bludst += dstadd;
+        }
+    }
+    assert(reddst == &dst.red[dst.height * dst.width]);
+    assert(grndst == &dst.grn[dst.height * dst.width]);
+    assert(bludst == &dst.blu[dst.height * dst.width]);
+
+    ppm_freerow(pixrow);
+    pm_close(scaledP);
+}
+
+
+
+static void
+doDiffSize(struct Rect       const srcRect,
+           struct Rect       const dstRect,
+           unsigned int      const pixSize,
            transfer_func     const trf,
            struct RGBColor * const color_map,
            unsigned char *   const src,
-           int               const srcwid,
-           struct rgbPlanes  const dst,
-           unsigned int      const dstwid) {
-
-    unsigned int const dstadd = dstwid - rectwidth(&clipdst);
+           unsigned int      const srcwid,
+           struct RgbPlanes  const dst) {
+/*----------------------------------------------------------------------------
+   Generate the raster in the plane buffers indicated by 'dst'.
 
+   'src' is the source pixels as a row-major array with rows 'srcwid' bytes
+   long.
+-----------------------------------------------------------------------------*/
     FILE * pamscalePipeP;
     const char * command;
-    FILE * scaled;
-    int cols, rows, format;
-    pixval maxval;
-    pixel * row;
-    pixel * rowp;
     FILE * tempFileP;
     const char * tempFilename;
-    Word * reddst;
-    Word * grndst;
-    Word * bludst;
-
-    reddst = dst.red;  /* initial value */
-    grndst = dst.grn;  /* initial value */
-    bludst = dst.blu;  /* initial value */
 
     pm_make_tmpfile(&tempFileP, &tempFilename);
 
     pm_close(tempFileP);
 
-    pm_asprintf(&command, "pamscale -xsize %d -ysize %d > %s",
-                rectwidth(&clipdst), rectheight(&clipdst), tempFilename);
+    pm_asprintf(&command, "pamscale -xsize %u -ysize %u > %s",
+                rectwidth(&dstRect), rectheight(&dstRect), tempFilename);
 
     pm_message("running command '%s'", command);
 
@@ -1239,108 +1490,61 @@ doDiffSize(struct Rect       const clipsrc,
 
     pm_strfree(command);
 
-    fprintf(pamscalePipeP, "P6\n%d %d\n%d\n",
-            rectwidth(&clipsrc), rectheight(&clipsrc), PPM_MAXMAXVAL);
+    fprintf(pamscalePipeP, "P6\n%u %u\n%u\n",
+            rectwidth(&srcRect), rectheight(&srcRect), PPM_MAXMAXVAL);
 
     switch (pixSize) {
     case 8: {
-        unsigned int rowNumber;
-        for (rowNumber = 0; rowNumber < ysize; ++rowNumber) {
-            unsigned char * const row = &src[rowNumber * srcwid];
-            unsigned int colNumber;
-            for (colNumber = 0; colNumber < xsize; ++colNumber) {
-                unsigned int const colorIndex = row[colNumber];
+        unsigned int row;
+        for (row = 0; row < rectheight(&srcRect); ++row) {
+            unsigned char * const rowBytes = &src[row * srcwid];
+            unsigned int col;
+            for (col = 0; col < rectwidth(&srcRect); ++col) {
+                unsigned int const colorIndex = rowBytes[col];
                 struct RGBColor * const ct = &color_map[colorIndex];
                 fputc(redepth(ct->red, 65535L), pamscalePipeP);
                 fputc(redepth(ct->grn, 65535L), pamscalePipeP);
                 fputc(redepth(ct->blu, 65535L), pamscalePipeP);
             }
         }
-    }
-    break;
+    } break;
     case 16: {
-        unsigned int rowNumber;
-        for (rowNumber = 0; rowNumber < ysize; ++rowNumber) {
-            unsigned char * const row = &src[rowNumber * srcwid];
-            unsigned int colNumber;
-            for (colNumber = 0; colNumber < xsize; ++colNumber) {
-                struct RGBColor const color = decode16(&row[colNumber * 2]);
+        unsigned int row;
+        for (row = 0; row < rectheight(&srcRect); ++row) {
+            unsigned char * const rowBytes = &src[row * srcwid];
+            unsigned int col;
+            for (col = 0; col < rectwidth(&srcRect); ++col) {
+                struct RGBColor const color = decode16(&rowBytes[col * 2]);
                 fputc(redepth(color.red, 32), pamscalePipeP);
                 fputc(redepth(color.grn, 32), pamscalePipeP);
                 fputc(redepth(color.blu, 32), pamscalePipeP);
             }
         }
-    }
-    break;
+    } break;
     case 32: {
-        unsigned int const planeSize = rectwidth(&clipsrc);
-        unsigned int rowNumber;
-
-        for (rowNumber = 0; rowNumber < ysize; ++rowNumber) {
-            unsigned char * const row = &src[rowNumber * srcwid];
-            unsigned char * const redPlane = &row[planeSize * 0];
-            unsigned char * const grnPlane = &row[planeSize * 1];
-            unsigned char * const bluPlane = &row[planeSize * 2];
-
-            unsigned int colNumber;
-            for (colNumber = 0; colNumber < xsize; ++colNumber) {
-                fputc(redepth(redPlane[colNumber], 256), pamscalePipeP);
-                fputc(redepth(grnPlane[colNumber], 256), pamscalePipeP);
-                fputc(redepth(bluPlane[colNumber], 256), pamscalePipeP);
+        unsigned int const planeSize = rectwidth(&srcRect);
+        unsigned int row;
+
+        for (row = 0; row < rectheight(&srcRect); ++row) {
+            unsigned char * const rowBytes = &src[row * srcwid];
+            unsigned char * const redPlane = &rowBytes[planeSize * 0];
+            unsigned char * const grnPlane = &rowBytes[planeSize * 1];
+            unsigned char * const bluPlane = &rowBytes[planeSize * 2];
+
+            unsigned int col;
+            for (col = 0; col < rectwidth(&srcRect); ++col) {
+                fputc(redepth(redPlane[col], 256), pamscalePipeP);
+                fputc(redepth(grnPlane[col], 256), pamscalePipeP);
+                fputc(redepth(bluPlane[col], 256), pamscalePipeP);
             }
         }
-    }
-    break;
-    }
+    } break;
+    } /* switch */
 
-    if (pclose(pamscalePipeP))
-        pm_error("pamscale failed.  pclose() returned Errno %s (%d)",
-                 strerror(errno), errno);
+    closeValidatePamscalePipe(pamscalePipeP);
 
-    ppm_readppminit(scaled = pm_openr(tempFilename), &cols, &rows,
-                    &maxval, &format);
-    row = ppm_allocrow(cols);
-    /* couldn't hurt to assert cols, rows and maxval... */
-
-    if (trf == NULL) {
-        while (rows-- > 0) {
-            unsigned int i;
-            ppm_readppmrow(scaled, row, cols, maxval, format);
-            for (i = 0, rowp = row; i < cols; ++i, ++rowp) {
-                *reddst++ = PPM_GETR(*rowp) * 65536L / (maxval + 1);
-                *grndst++ = PPM_GETG(*rowp) * 65536L / (maxval + 1);
-                *bludst++ = PPM_GETB(*rowp) * 65536L / (maxval + 1);
-            }
-            reddst += dstadd;
-            grndst += dstadd;
-            bludst += dstadd;
-        }
-    }
-    else {
-        while (rows-- > 0) {
-            unsigned int i;
-            ppm_readppmrow(scaled, row, cols, maxval, format);
-            for (i = 0, rowp = row; i < cols; i++, rowp++) {
-                struct RGBColor dst_c, src_c;
-                dst_c.red = *reddst;
-                dst_c.grn = *grndst;
-                dst_c.blu = *bludst;
-                src_c.red = PPM_GETR(*rowp) * 65536L / (maxval + 1);
-                src_c.grn = PPM_GETG(*rowp) * 65536L / (maxval + 1);
-                src_c.blu = PPM_GETB(*rowp) * 65536L / (maxval + 1);
-                (*trf)(&src_c, &dst_c);
-                *reddst++ = dst_c.red;
-                *grndst++ = dst_c.grn;
-                *bludst++ = dst_c.blu;
-            }
-            reddst += dstadd;
-            grndst += dstadd;
-            bludst += dstadd;
-        }
-    }
+    convertScaledPpm(tempFilename, trf, dst, dst.width-rectwidth(&dstRect));
 
-    pm_close(scaled);
-    ppm_freerow(row);
     pm_strfree(tempFilename);
     unlink(tempFilename);
 }
@@ -1348,7 +1552,7 @@ doDiffSize(struct Rect       const clipsrc,
 
 
 static void
-getRgb(struct rgbPlanes  const planes,
+getRgb(struct RgbPlanes  const planes,
        unsigned int      const index,
        struct RGBColor * const rgbP) {
 
@@ -1362,7 +1566,7 @@ getRgb(struct rgbPlanes  const planes,
 static void
 putRgb(struct RGBColor  const rgb,
        unsigned int     const index,
-       struct rgbPlanes const planes) {
+       struct RgbPlanes const planes) {
 
     planes.red[index] = rgb.red;
     planes.grn[index] = rgb.grn;
@@ -1372,182 +1576,171 @@ putRgb(struct RGBColor  const rgb,
 
 
 static void
-doSameSize(transfer_func           trf,
-           int               const pixSize,
-           int               const xsize,
-           int               const ysize,
-           unsigned char *   const src,
-           unsigned int      const srcwid,
-           struct RGBColor * const color_map,
-           struct rgbPlanes  const dst,
-           unsigned int      const dstwid) {
-/*----------------------------------------------------------------------------
-   Transfer pixels from 'src' to 'dst', applying the transfer function
-   'trf'.
+doSameSize8bpp(transfer_func           trf,
+               unsigned int      const xsize,
+               unsigned int      const ysize,
+               unsigned char *   const src,
+               unsigned int      const srcwid,
+               struct RGBColor * const colorMap,
+               struct RgbPlanes  const dst,
+               unsigned int      const dstwid) {
+
+    unsigned int rowNumber;
+
+    for (rowNumber = 0; rowNumber < ysize; ++rowNumber) {
+        unsigned char * const srcrow = &src[rowNumber * srcwid];
+        unsigned int const dstRowCurs = rowNumber * dstwid;
+
+        unsigned int colNumber;
+        for (colNumber = 0; colNumber < xsize; ++colNumber) {
+            unsigned int const dstCursor = dstRowCurs + colNumber;
+            unsigned int const colorIndex = srcrow[colNumber];
+
+            if (trf) {
+                struct RGBColor dstColor;
 
-   'src' has the same format as the 'bytes' member of struct raster.
-   'srcwid' is the size in bytes of each row, like raster.rowSize.
+                getRgb(dst, dstCursor, &dstColor);
+                (*trf)(&colorMap[colorIndex], &dstColor);
+                putRgb(dstColor, dstCursor, dst);
+            } else
+                putRgb(colorMap[colorIndex], dstCursor, dst);
+        }
+    }
+}
 
-   We use only the first 'ysize' rows and only the first 'xsize'
-   pixels of each row.
 
-   We really should clean this up so that we can take pixels out of
-   the middle of a row and rows out of the middle of the raster.  As
-   it stands, Caller achieves the same result by passing as 'src'
-   a pointer into the middle of a raster -- the upper left corner of
-   the rectangle he wants.  But that is messy and nonobvious.
 
-   Each plane of 'dst' 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.
------------------------------------------------------------------------------*/
-    switch (pixSize) {
-    case 8: {
-        unsigned int rowNumber;
+static void
+doSameSize16bpp(transfer_func           trf,
+                unsigned int      const xsize,
+                unsigned int      const ysize,
+                unsigned char *   const src,
+                unsigned int      const srcwid,
+                struct RgbPlanes  const dst,
+                unsigned int      const dstwid) {
 
-        for (rowNumber = 0; rowNumber < ysize; ++rowNumber) {
-            unsigned char * const srcrow = &src[rowNumber * srcwid];
-            unsigned int const dstRowCurs = rowNumber * dstwid;
+    unsigned int rowNumber;
 
-            unsigned int colNumber;
-            for (colNumber = 0; colNumber < xsize; ++colNumber) {
-                unsigned int const dstCursor = dstRowCurs + colNumber;
-                unsigned int const colorIndex = srcrow[colNumber];
-                struct RGBColor dstColor;
-                getRgb(dst, dstCursor, &dstColor);
-                (*trf)(&color_map[colorIndex], &dstColor);
-                putRgb(dstColor, dstCursor, dst);
-            }
-        }
-    } break;
-    case 16: {
-        unsigned int rowNumber;
+    for (rowNumber = 0; rowNumber < ysize; ++rowNumber) {
+        unsigned char * const row = &src[rowNumber * srcwid];
+        unsigned int const dstRowCurs = rowNumber * dstwid;
+
+        unsigned int colNumber;
+        for (colNumber = 0; colNumber < xsize; ++colNumber) {
+            unsigned int const dstCursor = dstRowCurs + colNumber;
+            struct RGBColor const srcColor = decode16(&row[colNumber*2]);
+
+            struct RGBColor scaledSrcColor;
 
-        for (rowNumber = 0; rowNumber < ysize; ++rowNumber) {
-            unsigned char * const row = &src[rowNumber * srcwid];
-            unsigned int const dstRowCurs = rowNumber * dstwid;
+            scaledSrcColor.red = srcColor.red << 11;
+            scaledSrcColor.grn = srcColor.grn << 11;
+            scaledSrcColor.blu = srcColor.blu << 11;
 
-            unsigned int colNumber;
-            for (colNumber = 0; colNumber < xsize; ++colNumber) {
-                unsigned int const dstCursor = dstRowCurs + colNumber;
-                struct RGBColor const srcColor = decode16(&row[colNumber*2]);
+            if (trf) {
                 struct RGBColor dstColor;
-                struct RGBColor scaledSrcColor;
-                scaledSrcColor.red = srcColor.red << 11;
-                scaledSrcColor.grn = srcColor.grn << 11;
-                scaledSrcColor.blu = srcColor.blu << 11;
+
                 getRgb(dst, dstCursor, &dstColor);
                 (*trf)(&scaledSrcColor, &dstColor);
                 putRgb(dstColor, dstCursor, dst);
-            }
+            } else
+                putRgb(scaledSrcColor, dstCursor, dst);
         }
-    } break;
-    case 32: {
-        unsigned int const planeSize = xsize;
-        unsigned int rowNumber;
+    }
+}
+
+
+
+static void
+doSameSize32bpp(transfer_func           trf,
+                unsigned int      const xsize,
+                unsigned int      const ysize,
+                unsigned char *   const src,
+                unsigned int      const srcwid,
+                struct RgbPlanes  const dst,
+                unsigned int      const dstwid) {
+
+    unsigned int const planeSize = xsize;
+
+    unsigned int rowNumber;
+
+    for (rowNumber = 0; rowNumber < ysize; ++rowNumber) {
+        unsigned char * const row = &src[rowNumber * srcwid];
+        unsigned char * const redPlane = &row[planeSize * 0];
+        unsigned char * const grnPlane = &row[planeSize * 1];
+        unsigned char * const bluPlane = &row[planeSize * 2];
+        unsigned int const dstRowCurs = rowNumber * dstwid;
+
+        unsigned int colNumber;
+
+        for (colNumber = 0; colNumber < xsize; ++colNumber) {
+            unsigned int const dstCursor = dstRowCurs + colNumber;
 
-        for (rowNumber = 0; rowNumber < ysize; ++rowNumber) {
-            unsigned char * const row = &src[rowNumber * srcwid];
-            unsigned char * const redPlane = &row[planeSize * 0];
-            unsigned char * const grnPlane = &row[planeSize * 1];
-            unsigned char * const bluPlane = &row[planeSize * 2];
-            unsigned int const dstRowCurs = rowNumber * dstwid;
+            struct RGBColor srcColor;
 
-            unsigned int colNumber;
+            srcColor.red = redPlane[colNumber] << 8;
+            srcColor.grn = grnPlane[colNumber] << 8;
+            srcColor.blu = bluPlane[colNumber] << 8;
+
+            if (trf) {
+                struct RGBColor dstColor;
 
-            for (colNumber = 0; colNumber < xsize; ++colNumber) {
-                unsigned int const dstCursor = dstRowCurs + colNumber;
-                struct RGBColor srcColor, dstColor;
                 getRgb(dst, dstCursor, &dstColor);
-                srcColor.red = redPlane[colNumber] << 8;
-                srcColor.grn = grnPlane[colNumber] << 8;
-                srcColor.blu = bluPlane[colNumber] << 8;
                 (*trf)(&srcColor, &dstColor);
                 putRgb(dstColor, dstCursor, dst);
-            }
+            } else
+                putRgb(srcColor, dstCursor, dst);
         }
-    } break;
-    default:
-        pm_error("Impossible value of pixSize: %u", pixSize);
     }
 }
 
 
 
 static void
-blitIdempotent(unsigned int          const pixSize,
-               unsigned int          const xsize,
-               unsigned int          const ysize,
-               unsigned char *       const src,
-               unsigned int          const srcwid,
-               struct RGBColor *     const colorMap,
-               struct rgbPlanes      const dst,
-               unsigned int          const dstwid) {
+doSameSize(transfer_func           trf,
+           int               const pixSize,
+           struct Rect       const srcRect,
+           unsigned char *   const src,
+           unsigned int      const srcwid,
+           struct RGBColor * const colorMap,
+           struct RgbPlanes  const dst,
+           unsigned int      const dstwid) {
 /*----------------------------------------------------------------------------
-  This is the same as doSameSize(), except optimized for the case that
-  the transfer function is idempotent (i.e. it's just a straight copy).
-  The original author's comments suggest that this optimization isn't
-  all that important -- that he just wrote this first and instead of
-  expanding it to handle arbitrary transfer functions, added functions
-  for that.
+   Transfer pixels from 'src' to 'dst', applying the transfer function
+   'trf'.
+
+   'src' has the same format as the 'bytes' member of struct Raster.
+   'srcwid' is the size in bytes of each row, like raster.rowSize.
+   Note that there may be padding in there; there isn't necessarily
+   'srcwid' bytes of information in a row.
+
+   We use only the first 'ysize' rows and only the first 'xsize'
+   pixels of each row.
+
+   We really should clean this up so that we can take pixels out of
+   the middle of a row and rows out of the middle of the raster.  As
+   it stands, Caller achieves the same result by passing as 'src'
+   a pointer into the middle of a raster -- the upper left corner of
+   the rectangle he wants.  But that is messy and nonobvious.
+
+   Each plane of 'dst' 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 int const xsize = rectwidth(&srcRect);
+    unsigned int const ysize = rectheight(&srcRect);
+
     switch (pixSize) {
-    case 8: {
-        unsigned int rowNumber;
-
-        for (rowNumber = 0; rowNumber < ysize; ++rowNumber) {
-            unsigned char * const srcrow = &src[rowNumber * srcwid];
-            unsigned int const dstRowCurs = rowNumber * dstwid;
-            unsigned int colNumber;
-            for (colNumber = 0; colNumber < xsize; ++colNumber) {
-                unsigned int const dstCursor = dstRowCurs + colNumber;
-                struct RGBColor * const ct = colorMap + srcrow[colNumber];
-                dst.red[dstCursor] = ct->red;
-                dst.grn[dstCursor] = ct->grn;
-                dst.blu[dstCursor] = ct->blu;
-            }
-        }
-    } break;
-    case 16: {
-        unsigned int rowNumber;
-
-        for (rowNumber = 0; rowNumber < ysize; ++rowNumber) {
-            unsigned char * const srcrow = &src[rowNumber * srcwid];
-            unsigned int const dstRowCurs = rowNumber * dstwid;
-            unsigned int colNumber;
-            for (colNumber = 0; colNumber < xsize; ++colNumber) {
-                unsigned int const dstCursor = dstRowCurs + colNumber;
-                struct RGBColor const srcColor =
-                    decode16(&srcrow[colNumber * 2]);
-                dst.red[dstCursor] = srcColor.red << 11;
-                dst.grn[dstCursor] = srcColor.grn << 11;
-                dst.blu[dstCursor] = srcColor.blu << 11;
-            }
-        }
-    } break;
-    case 32: {
-        unsigned int const planeSize = xsize;
-        unsigned int rowNumber;
-
-        for (rowNumber = 0; rowNumber < ysize; ++rowNumber) {
-            unsigned char * const srcrow = &src[rowNumber * srcwid];
-            unsigned char * const redPlane = &srcrow[planeSize * 0];
-            unsigned char * const grnPlane = &srcrow[planeSize * 1];
-            unsigned char * const bluPlane = &srcrow[planeSize * 2];
-            unsigned int const dstRowCurs = rowNumber * dstwid;
-
-            unsigned int colNumber;
-            for (colNumber = 0; colNumber < xsize; ++colNumber) {
-                unsigned int const dstCursor = dstRowCurs + colNumber;
-                dst.red[dstCursor] = redPlane[colNumber] << 8;
-                dst.grn[dstCursor] = grnPlane[colNumber] << 8;
-                dst.blu[dstCursor] = bluPlane[colNumber] << 8;
-            }
-        }
-    } break;
+    case 8:
+        doSameSize8bpp(trf, xsize, ysize, src, srcwid, colorMap, dst, dstwid);
+        break;
+    case 16:
+        doSameSize16bpp(trf, xsize, ysize, src, srcwid, dst, dstwid);
+        break;
+    case 32:
+        doSameSize32bpp(trf, xsize, ysize, src, srcwid, dst, dstwid);
+        break;
     default:
-        pm_error("INTERNAL ERROR: invalid bits per pixel (%u) in "
-                 "blitIdempotent()", pixSize);
+        pm_error("Impossible value of pixSize: %u", pixSize);
     }
 }
 
@@ -1557,16 +1750,15 @@ static void
 doBlit(struct Rect       const srcRect,
        struct Rect       const dstRect,
        struct Rect       const srcBounds,
-       struct raster     const srcplane,
+       struct Raster     const srcplane,
        struct Rect       const dstBounds,
-       struct rgbPlanes  const canvasPlanes,
+       struct RgbPlanes  const canvasPlanes,
        int               const pixSize,
        int               const dstwid,
-       struct RGBColor * const color_map,
-       int               const mode) {
+       struct RGBColor * const colorMap,
+       unsigned int      const mode) {
 /*----------------------------------------------------------------------------
-   Transfer some pixels from 'srcplane' to 'canvasPlanes', applying the
-   transfer function 'trf'.
+   Transfer some pixels from 'srcplane' to 'canvasPlanes'.
 
    'srcplane' contains the rectangle 'srcBounds' of the image.
    'canvasPlanes' contains the rectangle 'dstRect' of the image.
@@ -1579,11 +1771,12 @@ doBlit(struct Rect       const srcRect,
    with 'dstwid' words per row.
 -----------------------------------------------------------------------------*/
     unsigned char * src;
-    struct rgbPlanes dst;
+    struct RgbPlanes dst;
     int dstoff;
-    int xsize;
-    int ysize;
     transfer_func trf;
+        /* A transfer function to use as we transfer the pixels.
+           NULL for none.
+        */
 
     if (verbose) {
         dumpRect("copying from:", srcRect);
@@ -1601,12 +1794,17 @@ doBlit(struct Rect       const srcRect,
         assert(srcRowNumber < srcplane.rowCount);
         assert(srcRowOffset < srcplane.rowSize);
         src = srcplane.bytes + srcRowNumber * srcplane.rowSize + srcRowOffset;
-        xsize = rectwidth(&srcRect);
-        ysize = rectheight(&srcRect);
     }
 
+    /* This 'dstoff'/'dstadd' abomination has to be fixed.  We need to pass to
+       'doDiffSize' the whole actual canvas, 'canvasPlanes', and tell it to
+       what part of the canvas to write.  It can compute the location of each
+       destination row as it comes to it.
+     */
     dstoff = (dstRect.top - dstBounds.top) * dstwid +
         (dstRect.left - dstBounds.left);
+    dst.height = canvasPlanes.height - (dstRect.top - dstBounds.top);
+    dst.width  = canvasPlanes.width;
     dst.red = canvasPlanes.red + dstoff;
     dst.grn = canvasPlanes.grn + dstoff;
     dst.blu = canvasPlanes.blu + dstoff;
@@ -1615,35 +1813,31 @@ doBlit(struct Rect       const srcRect,
     if ((mode & ~64) == 0)
         trf = NULL;    /* optimized srcCopy */
     else
-        trf = transfer(mode & ~64);
+        trf = transferFunctionForMode(mode & ~64);
 
     if (!rectsamesize(srcRect, dstRect))
-        doDiffSize(srcRect, dstRect, pixSize, xsize, ysize,
-                   trf, color_map, src, srcplane.rowSize, dst, dstwid);
+        doDiffSize(srcRect, dstRect, pixSize,
+                   trf, colorMap, src, srcplane.rowSize, dst);
     else {
-        if (trf == NULL)
-            blitIdempotent(pixSize, xsize, ysize, src, srcplane.rowSize,
-                           color_map, dst, dstwid);
-        else
-            doSameSize(trf, pixSize, xsize, ysize, src, srcplane.rowSize,
-                       color_map, dst, dstwid);
+        doSameSize(trf, pixSize, srcRect, src, srcplane.rowSize,
+                   colorMap, dst, dstwid);
     }
 }
 
 
 
-static int
+static void
 blit(struct Rect       const srcRect,
      struct Rect       const srcBounds,
-     struct raster     const srcplane,
-     struct canvas *   const canvasP,
-     blitList *        const blitListP,
+     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) {
+     unsigned int      const mode) {
 /*----------------------------------------------------------------------------
    'srcplane' contains the rectangle 'srcBounds' of the image.
 
@@ -1652,43 +1846,27 @@ blit(struct Rect       const srcRect,
    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,
-       and several calls that examine it.  I'm guessing that "1" is the
-       appropriate thing to return in those cases, so I made it so.
-       -Bryan 00.03.02
-    */
-
-    int retval;
-
-    if (ps_text)
-        retval = 1;
-    else {
+    if (ps_text) {
+    } else {
         /* Almost got it.  Clip source rect with source bounds.
            clip dest rect with dest bounds.
         */
         struct Rect clipsrc;
         struct Rect clipdst;
 
-        rectinter(srcBounds, srcRect, &clipsrc);
-        rectinter(dstBounds, dstRect, &clipdst);
+        rectintersect(&srcBounds, &srcRect, &clipsrc);
+        rectintersect(&dstBounds, &dstRect, &clipdst);
 
         if (blitListP) {
             addBlitList(blitListP,
                         clipsrc, srcBounds, srcplane, pixSize,
                         clipdst, color_map, mode);
-
-            retval = 0;
         } else {
             doBlit(clipsrc, clipdst,
                    srcBounds, srcplane, dstBounds, canvasP->planes,
                    pixSize, dstwid, color_map, mode);
-
-            retval = 1;
         }
     }
-    return retval;
 }
 
 
@@ -1702,11 +1880,14 @@ blit(struct Rect       const srcRect,
 static void
 allocPlanes(unsigned int       const width,
             unsigned int       const height,
-            struct rgbPlanes * const planesP) {
+            struct RgbPlanes * const planesP) {
 
     unsigned int const planelen = width * height;
 
-    struct rgbPlanes planes;
+    struct RgbPlanes planes;
+
+    planes.width  = width;
+    planes.height = height;
 
     MALLOCARRAY(planes.red, planelen);
     MALLOCARRAY(planes.grn, planelen);
@@ -1725,7 +1906,7 @@ allocPlanes(unsigned int       const width,
 
 
 static void
-freePlanes(struct rgbPlanes const planes) {
+freePlanes(struct RgbPlanes const planes) {
 
     free(planes.red);
     free(planes.grn);
@@ -1743,11 +1924,11 @@ compact(Word const input) {
 
 
 static void
-reportBlitList(blitList * const blitListP) {
+reportBlitList(BlitList * const blitListP) {
 
     if (verbose) {
         unsigned int count;
-        struct blit_info * biP;
+        struct BlitInfo * biP;
 
         for (count = 0, biP = blitListP->firstP; biP; biP = biP->next)
             ++count;
@@ -1759,15 +1940,15 @@ reportBlitList(blitList * const blitListP) {
 
 
 static void
-doBlitList(struct canvas * const canvasP,
-           blitList *      const blitListP) {
+doBlitList(struct Canvas * const canvasP,
+           BlitList *      const blitListP) {
 /*----------------------------------------------------------------------------
    Do the list of blits *blitListP, drawing on canvas *canvasP.
 
    We allocate new plane data structures in *canvasP.  We assume it doesn't
    have them already.
 -----------------------------------------------------------------------------*/
-    struct blit_info * bi;
+    struct BlitInfo * bi;
     int srcwidth, dstwidth, srcheight, dstheight;
     double  scale, scalelow, scalehigh;
     double  xscale = 1.0;
@@ -1777,8 +1958,6 @@ doBlitList(struct canvas * const canvasP,
 
     reportBlitList(blitListP);
 
-    fullres = 0;
-
     for (bi = blitListP->firstP; bi; bi = bi->next) {
         srcwidth = rectwidth(&bi->srcRect);
         dstwidth = rectwidth(&bi->dstRect);
@@ -1855,7 +2034,7 @@ doBlitList(struct canvas * const canvasP,
     }
 
     if (xscale != 1.0 || yscale != 1.0) {
-        struct blit_info * biP;
+        struct BlitInfo * biP;
 
         for (biP = blitListP->firstP; biP; biP = biP->next)
             rectscale(&biP->dstRect, xscale, yscale);
@@ -1882,7 +2061,7 @@ doBlitList(struct canvas * const canvasP,
 
 static void
 outputPpm(FILE *           const ofP,
-          struct rgbPlanes const planes) {
+          struct RgbPlanes const planes) {
 
     unsigned int width;
     unsigned int height;
@@ -1922,18 +2101,20 @@ outputPpm(FILE *           const ofP,
  * is padded with a null.
  */
 static Word
-get_op(int const version) {
-    if ((align & 1) && version == 2) {
+nextOp(FILE *       const ifP,
+       unsigned int const version) {
+
+    if ((align & 0x1) && version == 2) {
         stage = "aligning for opcode";
-        readByte();
+        readByte(ifP);
     }
 
     stage = "reading opcode";
 
     if (version == 1)
-        return readByte();
+        return readByte(ifP);
     else
-        return readWord();
+        return readWord(ifP);
 }
 
 
@@ -1941,11 +2122,12 @@ get_op(int const version) {
 static drawFn ClipRgn;
 
 static void
-ClipRgn(struct canvas * const canvasP,
-        blitList *      const blitListP,
+ClipRgn(FILE *          const ifP,
+        struct Canvas * const canvasP,
+        BlitList *      const blitListP,
         int             const version) {
 
-    Word const len = readWord();
+    Word const len = readWord(ifP);
         /* Length in bytes of the parameter (including this word) */
 
     if (len == 10) {    /* null rgn */
@@ -1958,14 +2140,23 @@ ClipRgn(struct canvas * const canvasP,
            it to accept this clip rectangle, this program found the image to
            have an invalid raster.
         */
+        struct Rect clipRgnParm;
+
+        readRect(ifP, &clipRgnParm);
+
+        rectintersect(&clipRgnParm, &picFrame, &clip_rect);
 
-        readRect(&clip_rect);
-        rectinter(clip_rect, picFrame, &clip_rect);
-        /* XXX should clip this by picFrame */
+        if (!rectequal(&clipRgnParm, &clip_rect)) {
+            pm_message("ClipRgn opcode says to clip to a region which "
+                       "is not contained within the picture frame.  "
+                       "Ignoring the part outside the picture frame.");
+            dumpRect("ClipRgn:", clipRgnParm);
+            dumpRect("Picture frame:", picFrame);
+        }
         if (verbose)
             dumpRect("clipping to", clip_rect);
     } else
-        skip(len - 2);
+        skip(ifP, len - 2);
 }
 
 
@@ -1973,35 +2164,37 @@ ClipRgn(struct canvas * const canvasP,
 static drawFn OpColor;
 
 static void
-OpColor(struct canvas * const canvasP,
-        blitList *      const blitListP,
+OpColor(FILE *          const ifP,
+        struct Canvas * const canvasP,
+        BlitList *      const blitListP,
         int             const version) {
 
-    op_color.red = readWord();
-    op_color.grn = readWord();
-    op_color.blu = readWord();
+    op_color.red = readWord(ifP);
+    op_color.grn = readWord(ifP);
+    op_color.blu = readWord(ifP);
 }
 
 
 
 static void
-readPixmap(struct pixMap * const p) {
+readPixmap(FILE *          const ifP,
+           struct PixMap * const p) {
 
     stage = "getting pixMap header";
 
-    readRect(&p->Bounds);
-    p->version    = readWord();
-    p->packType   = readWord();
-    p->packSize   = readLong();
-    p->hRes       = readLong();
-    p->vRes       = readLong();
-    p->pixelType  = readWord();
-    p->pixelSize  = readWord();
-    p->cmpCount   = readWord();
-    p->cmpSize    = readWord();
-    p->planeBytes = readLong();
-    p->pmTable    = readLong();
-    p->pmReserved = readLong();
+    readRect(ifP, &p->Bounds);
+    p->version    = readWord(ifP);
+    p->packType   = readWord(ifP);
+    p->packSize   = readLong(ifP);
+    p->hRes       = readLong(ifP);
+    p->vRes       = readLong(ifP);
+    p->pixelType  = readWord(ifP);
+    p->pixelSize  = readWord(ifP);
+    p->cmpCount   = readWord(ifP);
+    p->cmpSize    = readWord(ifP);
+    p->planeBytes = readLong(ifP);
+    p->pmTable    = readLong(ifP);
+    p->pmReserved = readLong(ifP);
 
     if (verbose) {
         pm_message("pixelType: %d", p->pixelType);
@@ -2024,19 +2217,20 @@ readPixmap(struct pixMap * const p) {
 
 
 static struct RGBColor*
-readColorTable(void) {
+readColorTable(FILE * const ifP) {
+
     Longword ctSeed;
     Word ctFlags;
     Word ctSize;
     Word val;
     int i;
-    struct RGBColor* color_table;
+    struct RGBColor* colorTable;
 
     stage = "getting color table info";
 
-    ctSeed = readLong();
-    ctFlags = readWord();
-    ctSize = readWord();
+    ctSeed  = readLong(ifP);
+    ctFlags = readWord(ifP);
+    ctSize  = readWord(ifP);
 
     if (verbose) {
         pm_message("ctSeed:  %ld", ctSeed);
@@ -2046,12 +2240,12 @@ readColorTable(void) {
 
     stage = "reading color table";
 
-    MALLOCARRAY(color_table, ctSize + 1);
-    if (color_table == NULL)
+    MALLOCARRAY(colorTable, ctSize + 1);
+    if (!colorTable)
         pm_error("no memory for color table");
 
-    for (i = 0; i <= ctSize; i++) {
-        val = readWord();
+    for (i = 0; i <= ctSize; ++i) {
+        val = readWord(ifP);
         /* The indices in a device color table are bogus and usually == 0.
          * so I assume we allocate up the list of colors in order.
          */
@@ -2059,18 +2253,19 @@ readColorTable(void) {
             val = i;
         if (val > ctSize)
             pm_error("pixel value greater than color table size");
-        color_table[val].red = readWord();
-        color_table[val].grn = readWord();
-        color_table[val].blu = readWord();
+
+        colorTable[val].red = readWord(ifP);
+        colorTable[val].grn = readWord(ifP);
+        colorTable[val].blu = readWord(ifP);
 
         if (verbose > 1)
             pm_message("Color %3u: [%u,%u,%u]", val,
-                color_table[val].red,
-                color_table[val].grn,
-                color_table[val].blu);
+                colorTable[val].red,
+                colorTable[val].grn,
+                colorTable[val].blu);
     }
 
-    return color_table;
+    return colorTable;
 }
 
 
@@ -2166,7 +2361,7 @@ expand1Bit(unsigned char * const packed,
 static void
 unpackBuf(unsigned char *  const packed,
           unsigned int     const packedLen,
-          int              const bitsPerPixel,
+          unsigned int     const bitsPerPixel,
           unsigned char ** const expandedP,
           unsigned int *   const expandedLenP) {
 /*----------------------------------------------------------------------------
@@ -2222,7 +2417,7 @@ unpackBuf(unsigned char *  const packed,
 
 static void
 unpackUncompressedBits(FILE *          const ifP,
-                       struct raster   const raster,
+                       struct Raster   const raster,
                        unsigned int    const rowBytes,
                        unsigned int    const bitsPerPixel) {
 /*----------------------------------------------------------------------------
@@ -2237,6 +2432,9 @@ unpackUncompressedBits(FILE *          const ifP,
     unsigned int rowOfRect;
     unsigned char * linebuf;
 
+    if (verbose)
+        pm_message("Bits are not packed");
+
     MALLOCARRAY(linebuf, rowBytes + 100);
     if (linebuf == NULL)
         pm_error("can't allocate memory for line buffer");
@@ -2269,13 +2467,15 @@ reportValidateCompressedLineLen(unsigned int const row,
                                 unsigned int const linelen,
                                 unsigned int const rowSize) {
 /*----------------------------------------------------------------------------
-   'row' is a row number in the raster.
+  Report the line length and fail the program if it is obviously wrong.
+
+ '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.
+ '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).
+ '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);
@@ -2333,7 +2533,7 @@ expandRun(unsigned char * const block,
 
         assert(block[0] & 0x80);  /* It's a run */
 
-        if (verbose > 1)
+        if (verbose > 2)
             pm_message("Block: run of %u packed %u-byte units",
                        runLength, pkpixsize);
 
@@ -2412,7 +2612,7 @@ copyPixelGroup(unsigned char * const block,
         assert(blockLimit >= 1);  /* block[0] exists */
         assert((block[0] & 0x80) == 0);  /* It's not a run */
 
-        if (verbose > 1)
+        if (verbose > 2)
             pm_message("Block: %u explicit packed %u-byte units",
                        groupLen, pkpixsize);
 
@@ -2474,10 +2674,6 @@ interpretOneRasterBlock(unsigned char * const block,
 
 
 
-static unsigned int const maxPixelBytesPerBlock = 1024;
-
-
-
 static void
 interpretCompressedLine(unsigned char * const linebuf,
                         unsigned int    const linelen,
@@ -2485,13 +2681,13 @@ interpretCompressedLine(unsigned char * const linebuf,
                         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[].
+   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.
+   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 */
@@ -2518,7 +2714,8 @@ interpretCompressedLine(unsigned char * const linebuf,
         assert(rasterCursor <= rowSize);
     }
     if (verbose > 1)
-        pm_message("Got %u pixels for row", rasterCursor);
+        pm_message("Decompressed %u bytes into %u bytes for row",
+                   lineCursor, rasterCursor);
 }
 
 
@@ -2551,11 +2748,11 @@ interpretCompressedLine(unsigned char * const linebuf,
 
 static void
 unpackCompressedBits(FILE *          const ifP,
-                     struct raster   const raster,
+                     struct Raster   const raster,
                      unsigned int    const rowBytes,
                      unsigned int    const bitsPerPixel) {
 /*----------------------------------------------------------------------------
-   Read the raster on file *ifP and place it in 'raster'.
+   Set the raster bytes of 'raster' with bytes read from *ifP.
 
    The data in the file is compressed with run length encoding and
    possibly packed multiple pixels per byte as well.
@@ -2574,6 +2771,9 @@ unpackCompressedBits(FILE *          const ifP,
     unsigned char * linebuf;
     unsigned int linebufSize;
 
+    if (verbose)
+        pm_message("Bits are packed");
+
     linebufSize = rowBytes;
     MALLOCARRAY(linebuf, linebufSize);
     if (linebuf == NULL)
@@ -2585,9 +2785,9 @@ unpackCompressedBits(FILE *          const ifP,
         unsigned int linelen;
 
         if (llsize == 2)
-            linelen = readWord();
+            linelen = readWord(ifP);
         else
-            linelen = readByte();
+            linelen = readByte(ifP);
 
         reportValidateCompressedLineLen(row, linelen, raster.rowSize);
 
@@ -2611,19 +2811,19 @@ static void
 unpackbits(FILE *           const ifP,
            struct Rect *    const boundsP,
            Word             const rowBytesArg,
-           int              const bitsPerPixel,
-           struct raster *  const rasterP) {
+           unsigned int     const bitsPerPixel,
+           struct Raster *  const rasterP) {
 
     unsigned int const rectHeight = boundsP->bottom - boundsP->top;
     unsigned int const rectWidth  = boundsP->right  - boundsP->left;
 
-    struct raster raster;
+    struct Raster raster;
     unsigned int rowBytes;
 
     stage = "unpacking packbits";
 
     if (verbose)
-        pm_message("rowBytes = %u, bitsPerPixel = %d",
+        pm_message("rowBytes = %u, bitsPerPixel = %u",
                    rowBytesArg, bitsPerPixel);
 
     allocateRaster(&raster, rectWidth, rectHeight, bitsPerPixel);
@@ -2663,33 +2863,33 @@ interpretRowBytesWord(Word           const rowBytesWord,
  * a pattern in the fabled complete version.
  */
 static void
-readPattern(void) {
+readPattern(FILE * const ifP) {
 
     Word PatType;
 
     stage = "Reading a pattern";
 
-    PatType = readWord();
+    PatType = readWord(ifP);
 
     switch (PatType) {
     case 2:
-        skip(8); /* old pattern data */
-        skip(5); /* RGB for pattern */
+        skip(ifP, 8); /* old pattern data */
+        skip(ifP, 5); /* RGB for pattern */
         break;
     case 1: {
         Word rowBytesWord;
         bool pixMap;
         unsigned int rowBytes;
-        struct pixMap p;
-        struct raster raster;
+        struct PixMap p;
+        struct Raster raster;
         struct RGBColor * ct;
 
-        skip(8); /* old pattern data */
-        rowBytesWord = readWord();
+        skip(ifP, 8); /* old pattern data */
+        rowBytesWord = readWord(ifP);
         interpretRowBytesWord(rowBytesWord, &pixMap, &rowBytes);
-        readPixmap(&p);
-        ct = readColorTable();
-        unpackbits(ifp, &p.Bounds, rowBytes, p.pixelSize, &raster);
+        readPixmap(ifP, &p);
+        ct = readColorTable(ifP);
+        unpackbits(ifP, &p.Bounds, rowBytes, p.pixelSize, &raster);
         freeRaster(raster);
         free(ct);
     } break;
@@ -2700,16 +2900,17 @@ readPattern(void) {
 
 
 
-/* these 3 do nothing but skip over their data! */
+/* These three do nothing but skip over their data! */
 
 static drawFn BkPixPat;
 
 static void
-BkPixPat(struct canvas * const canvasP,
-         blitList *      const blitListP,
+BkPixPat(FILE *          const ifP,
+         struct Canvas * const canvasP,
+         BlitList *      const blitListP,
          int             const version) {
 
-    readPattern();
+    readPattern(ifP);
 }
 
 
@@ -2717,11 +2918,12 @@ BkPixPat(struct canvas * const canvasP,
 static drawFn PnPixPat;
 
 static void
-PnPixPat(struct canvas * const canvasP,
-         blitList *      const blitListP,
+PnPixPat(FILE *          const ifP,
+         struct Canvas * const canvasP,
+         BlitList *      const blitListP,
          int             const version) {
 
-    readPattern();
+    readPattern(ifP);
 }
 
 
@@ -2729,17 +2931,20 @@ PnPixPat(struct canvas * const canvasP,
 static drawFn FillPixPat;
 
 static void
-FillPixPat(struct canvas * const canvasP,
-           blitList *      const blitListP,
+FillPixPat(FILE *          const ifP,
+           struct Canvas * const canvasP,
+           BlitList *      const blitListP,
            int             const version) {
 
-    readPattern();
+    readPattern(ifP);
 }
 
 
 
 static void
-read8x8Pattern(struct Pattern * const pat) {
+read8x8Pattern(FILE *           const ifP,
+               struct Pattern * const pat) {
+
     unsigned char buf[8];
     unsigned char * exp;
     unsigned int len;
@@ -2747,7 +2952,7 @@ read8x8Pattern(struct Pattern * const pat) {
     unsigned int i;
 
     len = 8;  /* initial value */
-    readBytes(ifp, len, buf);
+    readBytes(ifP, len, buf);
     if (verbose) {
         pm_message("pattern: %02x%02x%02x%02x",
                    buf[0], buf[1], buf[2], buf[3]);
@@ -2764,11 +2969,12 @@ read8x8Pattern(struct Pattern * const pat) {
 static drawFn BkPat;
 
 static void
-BkPat(struct canvas * const canvasP,
-      blitList *      const blitListP,
+BkPat(FILE *          const ifP,
+      struct Canvas * const canvasP,
+      BlitList *      const blitListP,
       int             const version) {
 
-    read8x8Pattern(&bkpat);
+    read8x8Pattern(ifP, &bkpat);
 }
 
 
@@ -2776,11 +2982,12 @@ BkPat(struct canvas * const canvasP,
 static drawFn PnPat;
 
 static void
-PnPat(struct canvas * const canvasP,
-      blitList *      const blitListP,
+PnPat(FILE *          const ifP,
+      struct Canvas * const canvasP,
+      BlitList *      const blitListP,
       int             const version) {
 
-    read8x8Pattern(&pen_pat);
+    read8x8Pattern(ifP, &pen_pat);
 }
 
 
@@ -2788,11 +2995,12 @@ PnPat(struct canvas * const canvasP,
 static drawFn FillPat;
 
 static void
-FillPat(struct canvas * const canvasP,
-        blitList *      const blitListP,
+FillPat(FILE *          const ifP,
+        struct Canvas * const canvasP,
+        BlitList *      const blitListP,
         int             const version) {
 
-    read8x8Pattern(&fillpat);
+    read8x8Pattern(ifP, &fillpat);
 }
 
 
@@ -2800,12 +3008,14 @@ FillPat(struct canvas * const canvasP,
 static drawFn PnSize;
 
 static void
-PnSize(struct canvas * const canvasP,
-       blitList *      const blitListP,
+PnSize(FILE *          const ifP,
+       struct Canvas * const canvasP,
+       BlitList *      const blitListP,
        int             const version) {
 
-    pen_height = readWord();
-    pen_width = readWord();
+    pen_height = readWord(ifP);
+    pen_width  = readWord(ifP);
+
     if (verbose)
         pm_message("pen size %d x %d", pen_width, pen_height);
 }
@@ -2815,28 +3025,31 @@ PnSize(struct canvas * const canvasP,
 static drawFn PnSize;
 
 static void
-PnMode(struct canvas * const canvasP,
-       blitList *      const blitListP,
+PnMode(FILE *          const ifP,
+       struct Canvas * const canvasP,
+       BlitList *      const blitListP,
        int             const version) {
 
-    pen_mode = readWord();
+    pen_mode = readWord(ifP);
 
     if (pen_mode >= 8 && pen_mode < 15)
         pen_mode -= 8;
     if (verbose)
         pm_message("pen transfer mode = %s",
-            const_name(transfer_name, pen_mode));
+            constName(transfer_name, pen_mode));
 
-    pen_trf = transfer(pen_mode);
+    pen_trf = transferFunctionForMode(pen_mode);
 }
 
 
 
 static void
-readRgb(struct RGBColor * const rgb) {
-    rgb->red = readWord();
-    rgb->grn = readWord();
-    rgb->blu = readWord();
+readRgb(FILE *            const ifP,
+        struct RGBColor * const rgb) {
+
+    rgb->red = readWord(ifP);
+    rgb->grn = readWord(ifP);
+    rgb->blu = readWord(ifP);
 }
 
 
@@ -2844,11 +3057,13 @@ readRgb(struct RGBColor * const rgb) {
 static drawFn RGBFgCol;
 
 static void
-RGBFgCol(struct canvas * const canvasP,
-         blitList *      const blitListP,
+RGBFgCol(FILE *          const ifP,
+         struct Canvas * const canvasP,
+         BlitList *      const blitListP,
          int             const version) {
 
-    readRgb(&foreground);
+    readRgb(ifP, &foreground);
+
     if (verbose)
         pm_message("foreground now [%d,%d,%d]",
             foreground.red, foreground.grn, foreground.blu);
@@ -2859,11 +3074,13 @@ RGBFgCol(struct canvas * const canvasP,
 static drawFn RGBBkCol;
 
 static void
-RGBBkCol(struct canvas * const canvasP,
-         blitList *      const blitListP,
+RGBBkCol(FILE *          const ifP,
+         struct Canvas * const canvasP,
+         BlitList *      const blitListP,
          int             const version) {
 
-    readRgb(&background);
+    readRgb(ifP, &background);
+
     if (verbose)
         pm_message("background now [%d,%d,%d]",
             background.red, background.grn, background.blu);
@@ -2871,19 +3088,32 @@ RGBBkCol(struct canvas * const canvasP,
 
 
 
-#define PIXEL_INDEX(x,y) ((y) - picFrame.top) * rowlen + (x) - picFrame.left
+static unsigned int
+pixelIndex(struct Rect  const picFrame,
+           unsigned int const x,
+           unsigned int const y) {
+
+    unsigned int const rowLen = picFrame.right - picFrame.left;
+
+    assert(y >= picFrame.top  && y < picFrame.bottom);
+    assert(x >= picFrame.left && x < picFrame.right);
+
+    return (y - picFrame.top) * rowLen + (x - picFrame.left);
+}
+
+
 
 static void
-draw_pixel(struct canvas *   const canvasP,
-           int               const x,
-           int               const y,
-           struct RGBColor * const clr,
-           transfer_func           trf) {
+drawPixel(struct Canvas *   const canvasP,
+          int               const x,
+          int               const y,
+          struct RGBColor * const clr,
+          transfer_func           trf) {
 
     if (x < clip_rect.left || x >= clip_rect.right ||
         y < clip_rect.top  || y >= clip_rect.bottom) {
     } else {
-        unsigned int const i = PIXEL_INDEX(x, y);
+        unsigned int const i = pixelIndex(picFrame, x, y);
 
         struct RGBColor dst;
 
@@ -2902,55 +3132,66 @@ draw_pixel(struct canvas *   const canvasP,
 
 
 static void
-draw_pen_rect(struct canvas * const canvasP,
-              struct Rect *   const r) {
+drawPenRect(struct Canvas * const canvasP,
+            struct Rect *   const rP) {
 
-    int const rowadd = rowlen - (r->right - r->left);
+    if (!rectisnull(rP)) {
+        unsigned int const rowadd = rowlen - (rP->right - rP->left);
 
-    int i;
-    int x, y;
-    struct RGBColor dst;
+        unsigned int i;
+        unsigned int y;
 
-    i = PIXEL_INDEX(r->left, r->top);  /* initial value */
+        dumpRect("BRYAN: drawing rectangle ", *rP);
+        i = pixelIndex(picFrame, rP->left, rP->top);  /* initial value */
 
-    for (y = r->top; y < r->bottom; y++) {
-        for (x = r->left; x < r->right; x++) {
-            dst.red = canvasP->planes.red[i];
-            dst.grn = canvasP->planes.grn[i];
-            dst.blu = canvasP->planes.blu[i];
+        for (y = rP->top; y < rP->bottom; ++y) {
 
-            if (pen_pat.pix[(x & 7) + (y & 7) * 8])
-                (*pen_trf)(&black, &dst);
-            else
-                (*pen_trf)(&white, &dst);
+            unsigned int x;
+
+            for (x = rP->left; x < rP->right; ++x) {
 
-            canvasP->planes.red[i] = dst.red;
-            canvasP->planes.grn[i] = dst.grn;
-            canvasP->planes.blu[i] = dst.blu;
+                struct RGBColor dst;
 
-            i++;
+                assert(i < canvasP->planes.height * canvasP->planes.width);
+
+                dst.red = canvasP->planes.red[i];
+                dst.grn = canvasP->planes.grn[i];
+                dst.blu = canvasP->planes.blu[i];
+
+                if (pen_pat.pix[(x & 7) + (y & 7) * 8])
+                    (*pen_trf)(&black, &dst);
+                else
+                    (*pen_trf)(&white, &dst);
+
+                canvasP->planes.red[i] = dst.red;
+                canvasP->planes.grn[i] = dst.grn;
+                canvasP->planes.blu[i] = dst.blu;
+
+                ++i;
+            }
+            i += rowadd;
         }
-        i += rowadd;
     }
 }
 
 
 
 static void
-draw_pen(struct canvas * const canvasP,
-         int             const x,
-         int             const y) {
+drawPen(struct Canvas * const canvasP,
+        int             const x,
+        int             const y) {
 
-    struct Rect penrect;
+    struct Rect unclippedPenrect;
+    struct Rect clippedPenrect;
 
-    penrect.left = x;
-    penrect.right = x + pen_width;
-    penrect.top = y;
-    penrect.bottom = y + pen_height;
+    unclippedPenrect.left = x;
+    unclippedPenrect.right = x + pen_width;
+    unclippedPenrect.top = y;
+    unclippedPenrect.bottom = y + pen_height;
 
-    rectinter(penrect, clip_rect, &penrect);
+    rectintersect(&unclippedPenrect, &clip_rect, &clippedPenrect);
 
-    draw_pen_rect(canvasP, &penrect);
+    drawPenRect(canvasP, &clippedPenrect);
 }
 
 /*
@@ -2967,11 +3208,11 @@ draw_pen(struct canvas * const canvasP,
  * Paul Heckbert    3 Sep 85
  */
 static void
-scan_line(struct canvas * const canvasP,
-          short           const x1,
-          short           const y1,
-          short           const x2,
-          short           const y2) {
+scanLine(struct Canvas * const canvasP,
+         short           const x1,
+         short           const y1,
+         short           const x2,
+         short           const y2) {
 
     int d, x, y, ax, ay, sx, sy, dx, dy;
 
@@ -2985,7 +3226,7 @@ scan_line(struct canvas * const canvasP,
         if (ax>ay) {        /* x dominant */
             d = ay-(ax>>1);
             for (;;) {
-                draw_pen(canvasP, x, y);
+                drawPen(canvasP, x, y);
                 if (x==x2) return;
                 if ((x > rowlen) && (sx > 0)) return;
                 if (d>=0) {
@@ -2999,7 +3240,7 @@ scan_line(struct canvas * const canvasP,
         else {          /* y dominant */
             d = ax-(ay>>1);
             for (;;) {
-                draw_pen(canvasP, x, y);
+                drawPen(canvasP, x, y);
                 if (y==y2) return;
                 if ((y > collen) && (sy > 0)) return;
                 if (d>=0) {
@@ -3018,17 +3259,20 @@ scan_line(struct canvas * const canvasP,
 static drawFn Line;
 
 static void
-Line(struct canvas * const canvasP,
-     blitList *      const blitListP,
+Line(FILE *          const ifP,
+     struct Canvas * const canvasP,
+     BlitList *      const blitListP,
      int             const version) {
 
   struct Point p1;
-  readPoint(&p1);
-  readPoint(&current);
+  readPoint(ifP, &p1);
+  readPoint(ifP, &current);
+
   if (verbose)
     pm_message("(%d,%d) to (%d, %d)",
            p1.x,p1.y,current.x,current.y);
-  scan_line(canvasP, p1.x,p1.y,current.x,current.y);
+
+  scanLine(canvasP, p1.x,p1.y,current.x,current.y);
 }
 
 
@@ -3036,17 +3280,20 @@ Line(struct canvas * const canvasP,
 static drawFn LineFrom;
 
 static void
-LineFrom(struct canvas * const canvasP,
-         blitList *      const blitListP,
+LineFrom(FILE *          const ifP,
+         struct Canvas * const canvasP,
+         BlitList *      const blitListP,
          int             const version) {
 
     struct Point p1;
-    readPoint(&p1);
+
+    readPoint(ifP, &p1);
+
     if (verbose)
         pm_message("(%d,%d) to (%d, %d)", current.x, current.y, p1.x, p1.y);
 
     if (!blitListP)
-        scan_line(canvasP, current.x, current.y, p1.x, p1.y);
+        scanLine(canvasP, current.x, current.y, p1.x, p1.y);
 
     current.x = p1.x;
     current.y = p1.y;
@@ -3057,20 +3304,24 @@ LineFrom(struct canvas * const canvasP,
 static drawFn ShortLine;
 
 static void
-ShortLine(struct canvas * const canvasP,
-          blitList *      const blitListP,
+ShortLine(FILE *          const ifP,
+          struct Canvas * const canvasP,
+          BlitList *      const blitListP,
           int             const version) {
 
     struct Point p1;
-    readPoint(&p1);
-    readShortPoint(&current);
+
+    readPoint(ifP,&p1);
+    readShortPoint(ifP, &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);
+        scanLine(canvasP, p1.x, p1.y, current.x, current.y);
 }
 
 
@@ -3078,19 +3329,25 @@ ShortLine(struct canvas * const canvasP,
 static drawFn ShortLineFrom;
 
 static void
-ShortLineFrom(struct canvas * const canvasP,
-              blitList *      const blitListP,
+ShortLineFrom(FILE *          const ifP,
+              struct Canvas * const canvasP,
+              BlitList *      const blitListP,
               int             const version) {
 
     struct Point p1;
-    readShortPoint(&p1);
+
+    readShortPoint(ifP, &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);
+        scanLine(canvasP, current.x, current.y, p1.x, p1.y);
+
     current.x = p1.x;
     current.y = p1.y;
 }
@@ -3098,17 +3355,17 @@ ShortLineFrom(struct canvas * const canvasP,
 
 
 static void
-do_paintRect(struct canvas * const canvasP,
-             struct Rect     const prect) {
+doPaintRect(struct Canvas * const canvasP,
+            struct Rect     const prect) {
 
     struct Rect rect;
 
     if (verbose)
         dumpRect("painting", prect);
 
-    rectinter(clip_rect, prect, &rect);
+    rectintersect(&clip_rect, &prect, &rect);
 
-    draw_pen_rect(canvasP, &rect);
+    drawPenRect(canvasP, &rect);
 }
 
 
@@ -3116,13 +3373,15 @@ do_paintRect(struct canvas * const canvasP,
 static drawFn paintRect;
 
 static void
-paintRect(struct canvas * const canvasP,
-          blitList *      const blitListP,
+paintRect(FILE *          const ifP,
+          struct Canvas * const canvasP,
+          BlitList *      const blitListP,
           int             const version) {
 
-    readRect(&cur_rect);
+    readRect(ifP, &cur_rect);
+
     if (!blitListP)
-        do_paintRect(canvasP, cur_rect);
+        doPaintRect(canvasP, cur_rect);
 }
 
 
@@ -3130,19 +3389,20 @@ paintRect(struct canvas * const canvasP,
 static drawFn paintSameRect;
 
 static void
-paintSameRect(struct canvas * const canvasP,
-              blitList *      const blitListP,
+paintSameRect(FILE *          const ifP,
+              struct Canvas * const canvasP,
+              BlitList *      const blitListP,
               int             const version) {
 
     if (!blitListP)
-        do_paintRect(canvasP, cur_rect);
+        doPaintRect(canvasP, cur_rect);
 }
 
 
 
 static void
-do_frameRect(struct canvas * const canvasP,
-             struct Rect     const rect) {
+doFrameRect(struct Canvas * const canvasP,
+            struct Rect     const rect) {
 
     if (verbose)
         dumpRect("framing", rect);
@@ -3151,13 +3411,13 @@ do_frameRect(struct canvas * const canvasP,
         unsigned int x, y;
 
         for (x = rect.left; x <= rect.right - pen_width; x += pen_width) {
-            draw_pen(canvasP, x, rect.top);
-            draw_pen(canvasP, x, rect.bottom - pen_height);
+            drawPen(canvasP, x, rect.top);
+            drawPen(canvasP, x, rect.bottom - pen_height);
         }
 
         for (y = rect.top; y <= rect.bottom - pen_height ; y += pen_height) {
-            draw_pen(canvasP, rect.left, y);
-            draw_pen(canvasP, rect.right - pen_width, y);
+            drawPen(canvasP, rect.left, y);
+            drawPen(canvasP, rect.right - pen_width, y);
         }
     }
 }
@@ -3167,13 +3427,15 @@ do_frameRect(struct canvas * const canvasP,
 static drawFn frameRect;
 
 static void
-frameRect(struct canvas * const canvasP,
-          blitList *      const blitListP,
+frameRect(FILE *          const ifP,
+          struct Canvas * const canvasP,
+          BlitList *      const blitListP,
           int             const version) {
 
-    readRect(&cur_rect);
+    readRect(ifP, &cur_rect);
+
     if (!blitListP)
-        do_frameRect(canvasP, cur_rect);
+        doFrameRect(canvasP, cur_rect);
 }
 
 
@@ -3181,12 +3443,13 @@ frameRect(struct canvas * const canvasP,
 static drawFn frameSameRect;
 
 static void
-frameSameRect(struct canvas * const canvasP,
-              blitList *      const blitListP,
+frameSameRect(FILE *          const ifP,
+              struct Canvas * const canvasP,
+              BlitList *      const blitListP,
               int             const version) {
 
     if (!blitListP)
-        do_frameRect(canvasP, cur_rect);
+        doFrameRect(canvasP, cur_rect);
 }
 
 
@@ -3194,7 +3457,7 @@ frameSameRect(struct canvas * const canvasP,
 /* a stupid shell sort - I'm so embarrassed  */
 
 static void
-poly_sort(int const sort_index, struct Point points[]) {
+polySort(int const sort_index, struct Point points[]) {
   int d, i, j, temp;
 
   /* initialize and set up sort interval */
@@ -3227,9 +3490,9 @@ poly_sort(int const sort_index, struct Point points[]) {
 /* Watch out for the lack of error checking in the next two functions ... */
 
 static void
-scan_poly(struct canvas * const canvasP,
-          int             const np,
-          struct Point          pts[]) {
+scanPoly(struct Canvas * const canvasP,
+         int             const np,
+         struct Point          pts[]) {
 
   int dx,dy,dxabs,dyabs,i,scan_index,j,k,px,py;
   int sdx,sdy,x,y,toggle,old_sdy,sy0;
@@ -3283,7 +3546,7 @@ scan_poly(struct canvas * const canvasP,
         scan_index++;
       }
       px += sdx;
-      draw_pen(canvasP, px, py);
+      drawPen(canvasP, px, py);
     }
       }
     else
@@ -3299,7 +3562,7 @@ scan_poly(struct canvas * const canvasP,
         old_sdy = sdy;
         if (sdy != 0) scan_index--;
       }
-      draw_pen(canvasP, px,py);
+      drawPen(canvasP, px,py);
       coord[scan_index].x = px;
       coord[scan_index].y = py;
       scan_index++;
@@ -3312,14 +3575,14 @@ scan_poly(struct canvas * const canvasP,
   scan_index--;
   if (sy0 + sdy == 0) scan_index--;
 
-  poly_sort(scan_index, coord);
+  polySort(scan_index, coord);
 
   toggle = 0;
   for (i = 0; i < scan_index; i++) {
     if ((coord[i].y == coord[i+1].y) && (toggle == 0))
       {
     for (j = coord[i].x; j <= coord[i+1].x; j++)
-      draw_pen(canvasP, j, coord[i].y);
+      drawPen(canvasP, j, coord[i].y);
     toggle = 1;
       }
     else
@@ -3332,21 +3595,26 @@ scan_poly(struct canvas * const canvasP,
 static drawFn paintPoly;
 
 static void
-paintPoly(struct canvas * const canvasP,
-          blitList *      const blitListP,
+paintPoly(FILE *          const ifP,
+          struct Canvas * const canvasP,
+          BlitList *      const blitListP,
           int             const version) {
 
   struct Rect bb;
   struct Point pts[100];
-  int i, np = (readWord() - 10) >> 2;
+  int i;
+  int np;
+
+  np = (readWord(ifP) - 10) >> 2;
+
+  readRect(ifP, &bb);
 
-  readRect(&bb);
-  for (i=0; i<np; ++i)
-    readPoint(&pts[i]);
+  for (i = 0; i < np; ++i)
+      readPoint(ifP, &pts[i]);
 
   /* scan convert poly ... */
   if (!blitListP)
-      scan_poly(canvasP, np, pts);
+      scanPoly(canvasP, np, pts);
 }
 
 
@@ -3354,11 +3622,14 @@ paintPoly(struct canvas * const canvasP,
 static drawFn PnLocHFrac;
 
 static void
-PnLocHFrac(struct canvas * const canvasP,
-           blitList *      const blitListP,
+PnLocHFrac(FILE *          const ifP,
+           struct Canvas * const canvasP,
+           BlitList *      const blitListP,
            int             const version) {
 
-    Word frac = readWord();
+    Word frac;
+
+    frac = readWord(ifP);
 
     if (verbose)
         pm_message("PnLocHFrac = %d", frac);
@@ -3369,20 +3640,21 @@ PnLocHFrac(struct canvas * const canvasP,
 static drawFn TxMode;
 
 static void
-TxMode(struct canvas * const canvasP,
-       blitList *      const blitListP,
+TxMode(FILE *          const ifP,
+       struct Canvas * const canvasP,
+       BlitList *      const blitListP,
        int             const version) {
 
-    text_mode = readWord();
+    text_mode = readWord(ifP);
 
     if (text_mode >= 8 && text_mode < 15)
         text_mode -= 8;
     if (verbose)
         pm_message("text transfer mode = %s",
-            const_name(transfer_name, text_mode));
+            constName(transfer_name, text_mode));
 
     /* ignore the text mask bit 'cause we don't handle it yet */
-    text_trf = transfer(text_mode & ~64);
+    text_trf = transferFunctionForMode(text_mode & ~64);
 }
 
 
@@ -3390,13 +3662,15 @@ TxMode(struct canvas * const canvasP,
 static drawFn TxFont;
 
 static void
-TxFont(struct canvas * const canvasP,
-       blitList *      const blitListP,
+TxFont(FILE *          const ifP,
+       struct Canvas * const canvasP,
+       BlitList *      const blitListP,
        int             const version) {
 
-    text_font = readWord();
+    text_font = readWord(ifP);
+
     if (verbose)
-        pm_message("text font %s", const_name(font_name, text_font));
+        pm_message("text font %s", constName(font_name, text_font));
 }
 
 
@@ -3404,11 +3678,13 @@ TxFont(struct canvas * const canvasP,
 static drawFn TxFace;
 
 static void
-TxFace(struct canvas * const canvasP,
-       blitList *      const blitListP,
+TxFace(FILE *          const ifP,
+       struct Canvas * const canvasP,
+       BlitList *      const blitListP,
        int             const version) {
 
-    text_face = readByte();
+    text_face = readByte(ifP);
+
     if (verbose)
         pm_message("text face %d", text_face);
 }
@@ -3418,11 +3694,13 @@ TxFace(struct canvas * const canvasP,
 static drawFn TxSize;
 
 static void
-TxSize(struct canvas * const canvasP,
-       blitList *      const blitListP,
+TxSize(FILE *          const ifP,
+       struct Canvas * const canvasP,
+       BlitList *      const blitListP,
        int             const version) {
 
-    text_size = readWord();
+    text_size = readWord(ifP);
+
     if (verbose)
         pm_message("text size %d", text_size);
 }
@@ -3430,9 +3708,10 @@ TxSize(struct canvas * const canvasP,
 
 
 static void
-skip_text(blitList * const blitListP) {
+skipText(FILE *     const ifP,
+         BlitList * const blitListP) {
 
-    skip(readByte());
+    skip(ifP, readByte(ifP));
 
     blitListP->unblittableText = true;
 }
@@ -3440,7 +3719,7 @@ skip_text(blitList * const blitListP) {
 
 
 static int
-abs_value(int const x) {
+absValue(int const x) {
     if (x < 0)
         return -x;
     else
@@ -3450,18 +3729,18 @@ abs_value(int const x) {
 
 
 static struct font*
-get_font(int const font,
-         int const size,
-         int const style) {
+getFont(int const font,
+        int const size,
+        int const style) {
 
     int closeness, bestcloseness;
-    struct fontinfo* fi, *best;
+    struct FontInfo* fi, *best;
 
     best = 0;
     for (fi = fontlist; fi; fi = fi->next) {
-        closeness = abs_value(fi->font - font) * 10000 +
-            abs_value(fi->size - size) * 100 +
-            abs_value(fi->style - style);
+        closeness = absValue(fi->font - font) * 10000 +
+            absValue(fi->size - size) * 100 +
+            absValue(fi->style - style);
         if (!best || closeness < bestcloseness) {
             best = fi;
             bestcloseness = closeness;
@@ -3515,9 +3794,10 @@ rotate(int * const x,
 
 
 static void
-do_ps_text(struct canvas * const canvasP,
-           Word            const tx,
-           Word            const ty) {
+doPsText(FILE *          const ifP,
+         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;
@@ -3532,12 +3812,12 @@ do_ps_text(struct canvas * const canvasP,
         ps_cent_set = 1;
     }
 
-    len = readByte();
+    len = readByte(ifP);
 
     /* XXX this width calculation is not completely correct */
     width = 0;
     for (i = 0; i < len; i++) {
-        ch = str[i] = readByte();
+        ch = str[i] = readByte(ifP);
         if (tfont->glyph[ch])
             width += tfont->glyph[ch]->xadd;
     }
@@ -3567,7 +3847,7 @@ do_ps_text(struct canvas * const canvasP,
                 if ((rx >= picFrame.left) && (rx < picFrame.right) &&
                     (ry >= picFrame.top) && (ry < picFrame.bottom))
                 {
-                    o = PIXEL_INDEX(rx, ry);
+                    o = pixelIndex(picFrame, rx, ry);
                     if (glyph->bmap[h * glyph->width + w]) {
                         canvasP->planes.red[o] = foreground.red;
                         canvasP->planes.grn[o] = foreground.grn;
@@ -3584,27 +3864,28 @@ do_ps_text(struct canvas * const canvasP,
 
 
 static void
-do_text(struct canvas *  const canvasP,
-        blitList *       const blitListP,
-        Word             const startx,
-        Word             const starty) {
+doText(FILE *           const ifP,
+       struct Canvas *  const canvasP,
+       BlitList *       const blitListP,
+       Word             const startx,
+       Word             const starty) {
 
     if (blitListP)
-        skip_text(blitListP);
+        skipText(ifP, blitListP);
     else {
-        if (!(tfont = get_font(text_font, text_size, text_face)))
+        if (!(tfont = getFont(text_font, text_size, text_face)))
             tfont = pbm_defaultfont("bdf");
 
         if (ps_text)
-            do_ps_text(canvasP, startx, starty);
+            doPsText(ifP, canvasP, startx, starty);
         else {
             int len;
             Word x, y;
 
             x = startx;
             y = starty;
-            for (len = readByte(); len > 0; --len) {
-                struct glyph* const glyph = tfont->glyph[readByte()];
+            for (len = readByte(ifP); len > 0; --len) {
+                struct glyph* const glyph = tfont->glyph[readByte(ifP)];
                 if (glyph) {
                     int dy;
                     int h;
@@ -3616,8 +3897,8 @@ do_text(struct canvas *  const canvasP,
                             struct RGBColor * const colorP =
                                 glyph->bmap[h * glyph->width + w] ?
                                 &black : &white;
-                            draw_pixel(canvasP,
-                                       x + w + glyph->x, dy, colorP, text_trf);
+                            drawPixel(canvasP,
+                                      x + w + glyph->x, dy, colorP, text_trf);
                         }
                     }
                     x += glyph->xadd;
@@ -3634,15 +3915,16 @@ do_text(struct canvas *  const canvasP,
 static drawFn LongText;
 
 static void
-LongText(struct canvas * const canvasP,
-         blitList *      const blitListP,
+LongText(FILE *          const ifP,
+         struct Canvas * const canvasP,
+         BlitList *      const blitListP,
          int             const version) {
 
     struct Point p;
 
-    readPoint(&p);
+    readPoint(ifP, &p);
 
-    do_text(canvasP, blitListP, p.x, p.y);
+    doText(ifP, canvasP, blitListP, p.x, p.y);
 }
 
 
@@ -3650,13 +3932,14 @@ LongText(struct canvas * const canvasP,
 static drawFn DHText;
 
 static void
-DHText(struct canvas * const canvasP,
-       blitList *      const blitListP,
+DHText(FILE *          const ifP,
+       struct Canvas * const canvasP,
+       BlitList *      const blitListP,
        int             const version) {
 
-    current.x += readByte();
+    current.x += readByte(ifP);
 
-    do_text(canvasP, blitListP, current.x, current.y);
+    doText(ifP, canvasP, blitListP, current.x, current.y);
 }
 
 
@@ -3664,13 +3947,14 @@ DHText(struct canvas * const canvasP,
 static drawFn DVText;
 
 static void
-DVText(struct canvas * const canvasP,
-       blitList *      const blitListP,
+DVText(FILE *          const ifP,
+       struct Canvas * const canvasP,
+       BlitList *      const blitListP,
        int             const version) {
 
-    current.y += readByte();
+    current.y += readByte(ifP);
 
-    do_text(canvasP, blitListP, current.x, current.y);
+    doText(ifP, canvasP, blitListP, current.x, current.y);
 }
 
 
@@ -3678,13 +3962,15 @@ DVText(struct canvas * const canvasP,
 static drawFn DHDVText;
 
 static void
-DHDVText(struct canvas * const canvasP,
-         blitList *      const blitListP,
+DHDVText(FILE *          const ifP,
+         struct Canvas * const canvasP,
+         BlitList *      const blitListP,
          int             const version) {
+
     Byte dh, dv;
 
-    dh = readByte();
-    dv = readByte();
+    dh = readByte(ifP);
+    dv = readByte(ifP);
 
     if (verbose)
         pm_message("dh, dv = %d, %d", dh, dv);
@@ -3692,7 +3978,7 @@ DHDVText(struct canvas * const canvasP,
     current.x += dh;
     current.y += dv;
 
-    do_text(canvasP, blitListP, current.x, current.y);
+    doText(ifP, canvasP, blitListP, current.x, current.y);
 }
 
 
@@ -3702,50 +3988,51 @@ DHDVText(struct canvas * const canvasP,
  */
 
 static void
-directBits(struct canvas * const canvasP,
-           blitList *      const blitListP,
+directBits(FILE *          const ifP,
+           struct Canvas * const canvasP,
+           BlitList *      const blitListP,
            unsigned int    const pictVersion,
            bool            const skipRegion) {
 
-    struct pixMap   p;
+    struct PixMap   p;
     struct Rect     srcRect;
     struct Rect     dstRect;
-    struct raster   raster;
+    struct Raster   raster;
     Word            mode;
 
     /* skip fake len, and fake EOF */
-    skip(4);    /* Ptr baseAddr == 0x000000ff */
-    readWord();    /* version */
-    readRect(&p.Bounds);
-    p.packType = readWord();
-    p.packSize = readLong();
-    p.hRes = readLong();
-    p.vRes = readLong();
-    p.pixelType = readWord();
-    p.pixelSize = readWord();
-    p.pixelSize = readWord();    /* XXX twice??? */
-    p.cmpCount = readWord();
-    p.cmpSize = readWord();
-    p.planeBytes = readLong();
-    p.pmTable = readLong();
-    p.pmReserved = readLong();
-
-    readRect(&srcRect);
+    skip(ifP, 4);    /* Ptr baseAddr == 0x000000ff */
+    readWord(ifP);    /* version */
+    readRect(ifP, &p.Bounds);
+    p.packType   = readWord(ifP);
+    p.packSize   = readLong(ifP);
+    p.hRes       = readLong(ifP);
+    p.vRes       = readLong(ifP);
+    p.pixelType  = readWord(ifP);
+    p.pixelSize  = readWord(ifP);
+    p.pixelSize  = readWord(ifP);    /* XXX twice??? */
+    p.cmpCount   = readWord(ifP);
+    p.cmpSize    = readWord(ifP);
+    p.planeBytes = readLong(ifP);
+    p.pmTable    = readLong(ifP);
+    p.pmReserved = readLong(ifP);
+
+    readRect(ifP, &srcRect);
     if (verbose)
         dumpRect("source rectangle:", srcRect);
 
-    readRect(&dstRect);
+    readRect(ifP, &dstRect);
     if (verbose)
         dumpRect("destination rectangle:", dstRect);
 
-    mode = readWord();
+    mode = readWord(ifP);
     if (verbose)
-        pm_message("transfer mode = %s", const_name(transfer_name, mode));
+        pm_message("transfer mode = %s", constName(transfer_name, mode));
 
     if (skipRegion)
-        skip_poly_or_region(canvasP, blitListP, pictVersion);
+        skipPolyOrRegion(ifP, canvasP, blitListP, pictVersion);
 
-    unpackbits(ifp, &p.Bounds, 0, p.pixelSize, &raster);
+    unpackbits(ifP, &p.Bounds, 0, p.pixelSize, &raster);
 
     blit(srcRect, p.Bounds, raster, canvasP, blitListP, p.pixelSize,
          dstRect, picFrame, rowlen, NULL, mode);
@@ -3761,11 +4048,12 @@ directBits(struct canvas * const canvasP,
 static drawFn DirectBitsRect;
 
 static void
-DirectBitsRect(struct canvas * const canvasP,
-               blitList *      const blitListP,
+DirectBitsRect(FILE *          const ifP,
+               struct Canvas * const canvasP,
+               BlitList *      const blitListP,
                int             const version) {
 
-    directBits(canvasP, blitListP, version, SKIP_REGION_FALSE);
+    directBits(ifP, canvasP, blitListP, version, SKIP_REGION_FALSE);
 }
 
 
@@ -3773,78 +4061,80 @@ DirectBitsRect(struct canvas * const canvasP,
 static drawFn DirectBitsRgn;
 
 static void
-DirectBitsRgn(struct canvas * const canvasP,
-              blitList *      const blitListP,
+DirectBitsRgn(FILE *          const ifP,
+              struct Canvas * const canvasP,
+              BlitList *      const blitListP,
               int             const version) {
 
-    directBits(canvasP, blitListP, version, SKIP_REGION_TRUE);
+    directBits(ifP, canvasP, blitListP, version, SKIP_REGION_TRUE);
 }
 
 
 
 static void
-do_pixmap(struct canvas * const canvasP,
-          blitList *      const blitListP,
-          int             const version,
-          Word            const rowBytes,
-          int             const is_region) {
+doPixmap(FILE *          const ifP,
+         struct Canvas * const canvasP,
+         BlitList *      const blitListP,
+         int             const version,
+         Word            const rowBytes,
+         int             const is_region) {
 /*----------------------------------------------------------------------------
    Do a paletted image.
 -----------------------------------------------------------------------------*/
     Word mode;
-    struct pixMap p;
-    struct raster raster;
-    struct RGBColor * color_table;
+    struct PixMap p;
+    struct Raster raster;
+    struct RGBColor * colorTable;
     struct Rect srcRect;
     struct Rect dstRect;
 
-    readPixmap(&p);
+    readPixmap(ifP, &p);
 
     if (verbose)
         pm_message("%u x %u paletted image",
                    p.Bounds.right - p.Bounds.left,
                    p.Bounds.bottom - p.Bounds.top);
 
-    color_table = readColorTable();
+    colorTable = readColorTable(ifP);
 
-    readRect(&srcRect);
+    readRect(ifP, &srcRect);
 
     if (verbose)
         dumpRect("source rectangle:", srcRect);
 
-    readRect(&dstRect);
+    readRect(ifP, &dstRect);
 
     if (verbose)
         dumpRect("destination rectangle:", dstRect);
 
-    mode = readWord();
+    mode = readWord(ifP);
 
     if (verbose)
-        pm_message("transfer mode = %s", const_name(transfer_name, mode));
+        pm_message("transfer mode = %s", constName(transfer_name, mode));
 
     if (is_region)
-        skip_poly_or_region(canvasP, blitListP, version);
+        skipPolyOrRegion(ifP, canvasP, blitListP, version);
 
     stage = "unpacking rectangle";
 
-    unpackbits(ifp, &p.Bounds, rowBytes, p.pixelSize, &raster);
+    unpackbits(ifP, &p.Bounds, rowBytes, p.pixelSize, &raster);
 
     blit(srcRect, p.Bounds, raster, canvasP, blitListP, 8,
-         dstRect, picFrame, rowlen, color_table, mode);
+         dstRect, picFrame, rowlen, colorTable, mode);
 
-    free(color_table);
+    free(colorTable);
     freeRaster(raster);
 }
 
 
 
 static void
-do_bitmap(FILE *          const ifP,
-          struct canvas * const canvasP,
-          blitList *      const blitListP,
-          int             const version,
-          int             const rowBytes,
-          int             const is_region) {
+doBitmap(FILE *          const ifP,
+         struct Canvas * const canvasP,
+         BlitList *      const blitListP,
+         int             const version,
+         int             const rowBytes,
+         int             const is_region) {
 /*----------------------------------------------------------------------------
    Do a bitmap.  That's one bit per pixel, 0 is white, 1 is black.
 
@@ -3854,22 +4144,22 @@ do_bitmap(FILE *          const ifP,
     struct Rect srcRect;
     struct Rect dstRect;
     Word mode;
-    struct raster raster;
+    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} };
 
-    readRect(&Bounds);
-    readRect(&srcRect);
-    readRect(&dstRect);
-    mode = readWord();
+    readRect(ifP, &Bounds);
+    readRect(ifP, &srcRect);
+    readRect(ifP, &dstRect);
+    mode = readWord(ifP);
     if (verbose)
-        pm_message("transfer mode = %s", const_name(transfer_name, mode));
+        pm_message("transfer mode = %s", constName(transfer_name, mode));
 
     if (is_region)
-        skip_poly_or_region(canvasP, blitListP, version);
+        skipPolyOrRegion(ifP, canvasP, blitListP, version);
 
     stage = "unpacking rectangle";
 
@@ -3886,8 +4176,9 @@ do_bitmap(FILE *          const ifP,
 static drawFn BitsRect;
 
 static void
-BitsRect(struct canvas * const canvasP,
-         blitList *      const blitListP,
+BitsRect(FILE *          const ifP,
+         struct Canvas * const canvasP,
+         BlitList *      const blitListP,
          int             const version) {
 
     Word rowBytesWord;
@@ -3895,14 +4186,14 @@ BitsRect(struct canvas * const canvasP,
     unsigned int rowBytes;
 
     stage = "Reading rowBytes word for bitsrect";
-    rowBytesWord = readWord();
+    rowBytesWord = readWord(ifP);
 
     interpretRowBytesWord(rowBytesWord, &pixMap, &rowBytes);
 
     if (pixMap)
-        do_pixmap(canvasP, blitListP, version, rowBytes, 0);
+        doPixmap(ifP, canvasP, blitListP, version, rowBytes, 0);
     else
-        do_bitmap(ifp, canvasP, blitListP, version, rowBytes, 0);
+        doBitmap(ifP, canvasP, blitListP, version, rowBytes, 0);
 }
 
 
@@ -3910,8 +4201,9 @@ BitsRect(struct canvas * const canvasP,
 static drawFn BitsRegion;
 
 static void
-BitsRegion(struct canvas * const canvasP,
-           blitList *      const blitListP,
+BitsRegion(FILE *          const ifP,
+           struct Canvas * const canvasP,
+           BlitList *      const blitListP,
            int             const version) {
 
     Word rowBytesWord;
@@ -3919,14 +4211,14 @@ BitsRegion(struct canvas * const canvasP,
     unsigned int rowBytes;
 
     stage = "Reading rowBytes for bitsregion";
-    rowBytesWord = readWord();
+    rowBytesWord = readWord(ifP);
 
     interpretRowBytesWord(rowBytesWord, &pixMap, &rowBytes);
 
     if (pixMap)
-        do_pixmap(canvasP, blitListP, version, rowBytes, 1);
+        doPixmap(ifP, canvasP, blitListP, version, rowBytes, 1);
     else
-        do_bitmap(ifp, canvasP, blitListP, version, rowBytes, 1);
+        doBitmap(ifP, canvasP, blitListP, version, rowBytes, 1);
 }
 
 
@@ -3935,7 +4227,7 @@ BitsRegion(struct canvas * const canvasP,
   * See http://developer.apple.com/techpubs/mac/QuickDraw/QuickDraw-461.html
   * for opcode description
   */
-static struct opdef const optable[] = {
+static struct Opdef const optable[] = {
 /* 0x00 */  { "NOP", 0, NULL, "nop" },
 /* 0x01 */  { "ClipRgn", NA, ClipRgn, "clip region" },
 /* 0x02 */  { "BkPat", 8, BkPat, "background pattern" },
@@ -4051,14 +4343,14 @@ static struct opdef const optable[] = {
 /* 0x6d */  RESERVED_OP(4),
 /* 0x6e */  RESERVED_OP(4),
 /* 0x6f */  RESERVED_OP(4),
-/* 0x70 */  { "framePoly", NA, skip_poly_or_region, "poly" },
+/* 0x70 */  { "framePoly", NA, skipPolyOrRegion, "poly" },
 /* 0x71 */  { "paintPoly", NA, paintPoly, "poly" },
-/* 0x72 */  { "erasePoly", NA, skip_poly_or_region, "poly" },
-/* 0x73 */  { "invertPoly", NA, skip_poly_or_region, "poly" },
-/* 0x74 */  { "fillPoly", NA, skip_poly_or_region, "poly" },
-/* 0x75 */  RESERVED_OP_F(skip_poly_or_region),
-/* 0x76 */  RESERVED_OP_F(skip_poly_or_region),
-/* 0x77 */  RESERVED_OP_F(skip_poly_or_region),
+/* 0x72 */  { "erasePoly", NA, skipPolyOrRegion, "poly" },
+/* 0x73 */  { "invertPoly", NA, skipPolyOrRegion, "poly" },
+/* 0x74 */  { "fillPoly", NA, skipPolyOrRegion, "poly" },
+/* 0x75 */  RESERVED_OP_F(skipPolyOrRegion),
+/* 0x76 */  RESERVED_OP_F(skipPolyOrRegion),
+/* 0x77 */  RESERVED_OP_F(skipPolyOrRegion),
 /* 0x78 */  { "frameSamePoly", 0, NULL, "poly (NYI)" },
 /* 0x79 */  { "paintSamePoly", 0, NULL, "poly (NYI)" },
 /* 0x7a */  { "eraseSamePoly", 0, NULL, "poly (NYI)" },
@@ -4067,14 +4359,14 @@ static struct opdef const optable[] = {
 /* 0x7d */  RESERVED_OP(0),
 /* 0x7e */  RESERVED_OP(0),
 /* 0x7f */  RESERVED_OP(0),
-/* 0x80 */  { "frameRgn", NA, skip_poly_or_region, "region" },
-/* 0x81 */  { "paintRgn", NA, skip_poly_or_region, "region" },
-/* 0x82 */  { "eraseRgn", NA, skip_poly_or_region, "region" },
-/* 0x83 */  { "invertRgn", NA, skip_poly_or_region, "region" },
-/* 0x84 */  { "fillRgn", NA, skip_poly_or_region, "region" },
-/* 0x85 */  RESERVED_OP_F(skip_poly_or_region),
-/* 0x86 */  RESERVED_OP_F(skip_poly_or_region),
-/* 0x87 */  RESERVED_OP_F(skip_poly_or_region),
+/* 0x80 */  { "frameRgn", NA, skipPolyOrRegion, "region" },
+/* 0x81 */  { "paintRgn", NA, skipPolyOrRegion, "region" },
+/* 0x82 */  { "eraseRgn", NA, skipPolyOrRegion, "region" },
+/* 0x83 */  { "invertRgn", NA, skipPolyOrRegion, "region" },
+/* 0x84 */  { "fillRgn", NA, skipPolyOrRegion, "region" },
+/* 0x85 */  RESERVED_OP_F(skipPolyOrRegion),
+/* 0x86 */  RESERVED_OP_F(skipPolyOrRegion),
+/* 0x87 */  RESERVED_OP_F(skipPolyOrRegion),
 /* 0x88 */  { "frameSameRgn", 0, NULL, "region (NYI)" },
 /* 0x89 */  { "paintSameRgn", 0, NULL, "region (NYI)" },
 /* 0x8a */  { "eraseSameRgn", 0, NULL, "region (NYI)" },
@@ -4109,9 +4401,10 @@ static struct opdef const optable[] = {
 
 
 static void
-processOpcode(Word            const opcode,
-              struct canvas * const canvasP,
-              blitList *      const blitListP,
+processOpcode(FILE *          const ifP,
+              Word            const opcode,
+              struct Canvas * const canvasP,
+              BlitList *      const blitListP,
               unsigned int    const version) {
 
     if (opcode < 0xa2) {
@@ -4124,15 +4417,15 @@ processOpcode(Word            const opcode,
         }
 
         if (optable[opcode].impl != NULL)
-            (*optable[opcode].impl)(canvasP, blitListP, version);
+            (*optable[opcode].impl)(ifP, canvasP, blitListP, version);
         else if (optable[opcode].len >= 0)
-            skip(optable[opcode].len);
+            skip(ifP, optable[opcode].len);
         else {
             /* It's a special length code */
             switch (optable[opcode].len) {
             case WORD_LEN: {
-                Word const len = readWord();
-                skip(len);
+                Word const len = readWord(ifP);
+                skip(ifP, len);
             } break;
             default:
                 pm_error("can't do length %d", optable[opcode].len);
@@ -4142,12 +4435,12 @@ processOpcode(Word            const opcode,
         if (verbose)
             pm_message("HeaderOp");
         stage = "HeaderOp";
-        skip(24);
+        skip(ifP, 24);
     } else if (opcode >= 0xa2 && opcode <= 0xaf) {
         stage = "skipping reserved";
         if (verbose)
             pm_message("%s 0x%x", stage, opcode);
-        skip(readWord());
+        skip(ifP, readWord(ifP));
     } else if (opcode >= 0xb0 && opcode <= 0xcf) {
         /* just a reserved opcode, no data */
         if (verbose)
@@ -4156,12 +4449,12 @@ processOpcode(Word            const opcode,
         stage = "skipping reserved";
         if (verbose)
             pm_message("%s 0x%x", stage, opcode);
-        skip(readLong());
+        skip(ifP, readLong(ifP));
     } else if (opcode >= 0x100 && opcode <= 0x7fff) {
         stage = "skipping reserved";
         if (verbose)
             pm_message("%s 0x%x", stage, opcode);
-        skip((opcode >> 7) & 255);
+        skip(ifP, (opcode >> 7) & 255);
     } else if (opcode >= 0x8000 && opcode <= 0x80ff) {
         /* just a reserved opcode, no data */
         if (verbose)
@@ -4170,7 +4463,7 @@ processOpcode(Word            const opcode,
         stage = "skipping reserved";
         if (verbose)
             pm_message("%s 0x%x", stage, opcode);
-        skip(readLong());
+        skip(ifP, readLong(ifP));
     } else
         pm_error("This program does not understand opcode 0x%04x", opcode);
 }
@@ -4178,15 +4471,23 @@ processOpcode(Word            const opcode,
 
 
 static void
-interpretPict(FILE * const ofP) {
+interpretPict(FILE *       const ifP,
+              FILE *       const ofP,
+              bool         const noheader,
+              bool         const fullres,
+              bool         const quickdraw,
+              unsigned int const verboseArg) {
 
     Byte ch;
     Word picSize;
     Word opcode;
     unsigned int version;
     unsigned int i;
-    struct canvas canvas;
-    blitList blitList;
+    struct Canvas canvas;
+    BlitList blitList;
+
+    verbose = verboseArg;
+    recognize_comment = !quickdraw;
 
     initBlitList(&blitList);
 
@@ -4194,18 +4495,24 @@ interpretPict(FILE * const ofP) {
         pen_pat.pix[i] = bkpat.pix[i] = fillpat.pix[i] = 1;
     pen_width = pen_height = 1;
     pen_mode = 0; /* srcCopy */
-    pen_trf = transfer(pen_mode);
+    pen_trf = transferFunctionForMode(pen_mode);
     text_mode = 0; /* srcCopy */
-    text_trf = transfer(text_mode);
+    text_trf = transferFunctionForMode(text_mode);
+
+    if (!noheader) {
+        stage = "Reading 512 byte header";
+        /* Note that the "header" in PICT is entirely comment! */
+        skip(ifP, 512);
+    }
 
     stage = "Reading picture size";
-    picSize = readWord();
+    picSize = readWord(ifP);
 
     if (verbose)
         pm_message("picture size = %u (0x%x)", picSize, picSize);
 
     stage = "reading picture frame";
-    readRect(&picFrame);
+    readRect(ifP, &picFrame);
 
     if (verbose) {
         dumpRect("Picture frame:", picFrame);
@@ -4223,18 +4530,18 @@ interpretPict(FILE * const ofP) {
         clip_rect = picFrame;
     }
 
-    while ((ch = readByte()) == 0)
+    while ((ch = readByte(ifP)) == 0)
         ;
     if (ch != 0x11)
         pm_error("No version number");
 
-    version = readByte();
+    version = readByte(ifP);
 
     switch (version) {
     case 1:
         break;
     case 2: {
-        unsigned char const subcode = readByte();
+        unsigned char const subcode = readByte(ifP);
         if (subcode != 0xff)
             pm_error("The only Version 2 PICT images this program "
                      "undertands are subcode 0xff.  This image has "
@@ -4247,8 +4554,9 @@ interpretPict(FILE * const ofP) {
     if (verbose)
         pm_message("PICT version %u", version);
 
-    while((opcode = get_op(version)) != 0xff)
-        processOpcode(opcode, &canvas, fullres ? &blitList : NULL, version);
+    while((opcode = nextOp(ifP, version)) != 0xff)
+        processOpcode(ifP, opcode, &canvas, fullres ? &blitList : NULL,
+                      version);
 
     if (fullres) {
         if (blitList.unblittableText)
@@ -4263,79 +4571,30 @@ interpretPict(FILE * const ofP) {
 
 
 
-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;
-
-    rc = stat("fontdir", &statbuf);
-
-    if (rc == 0)
-        load_fontdir("fontdir");
-}
+int
+main(int argc, const char *argv[]) {
 
+    struct CmdlineInfo cmdline;
+    FILE * ifP;
 
+    pm_proginit(&argc, argv);
 
-int
-main(int argc, char * argv[]) {
-    int argn;
-    int header;
-    const char* const usage =
-"[-verbose] [-fullres] [-noheader] [-quickdraw] [-fontdir file] [pictfile]";
-
-    ppm_init( &argc, argv );
-
-    argn = 1;
-    verbose = 0;
-    fullres = 0;
-    header = 1;
-    recognize_comment = 1;
-
-    while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') {
-        if (pm_keymatch(argv[argn], "-verbose", 2))
-            verbose++;
-        else if (pm_keymatch(argv[argn], "-fullres", 3))
-            fullres = 1;
-        else if (pm_keymatch(argv[argn], "-noheader", 2))
-            header = 0;
-        else if (pm_keymatch(argv[argn], "-quickdraw", 2))
-            recognize_comment = 0;
-        else if (pm_keymatch(argv[argn], "-fontdir", 3)) {
-            argn++;
-            if (!argv[argn])
-                pm_usage(usage);
-            else
-                load_fontdir(argv[argn]);
-        }
-        else
-            pm_usage(usage);
-        ++argn;
-    }
+    parseCommandLine(argc, argv, &cmdline);
 
-    if (argn < argc) {
-        ifp = pm_openr(argv[argn]);
-        ++argn;
-    } else
-        ifp = stdin;
+    ifP = pm_openr(cmdline.inputFileName);
 
-    if (argn != argc)
-        pm_usage(usage);
+    if (cmdline.fontdir)
+        loadFontdir(cmdline.fontdir);
 
     loadDefaultFontDir();
 
-    if (header) {
-        stage = "Reading 512 byte header";
-        /* Note that the "header" in PICT is entirely comment! */
-        skip(512);
-    }
-
-    interpretPict(stdout);
+    interpretPict(ifP, stdout, cmdline.noheader,
+                  cmdline.fullres, cmdline.quickdraw, cmdline.verbose);
 
     pm_close(stdout);
 
     return 0;
 }
+
+
+
diff --git a/converter/ppm/pjtoppm.c b/converter/ppm/pjtoppm.c
index b0c879a0..e556803f 100644
--- a/converter/ppm/pjtoppm.c
+++ b/converter/ppm/pjtoppm.c
@@ -161,7 +161,7 @@ main(int argc, const char ** argv) {
                 switch (c) {
                 case 'M':   /* transmission mode */
                     if (val != 0 && val != 1)
-                        pm_error("unimplemented trasmission mode %d", val);
+                        pm_error("unimplemented transmission mode %d", val);
                     mode = val;
                     modeIsSet = true;
                     break;
diff --git a/converter/ppm/ppmtoapplevol.c b/converter/ppm/ppmtoapplevol.c
index eb4b6b2a..1e979de9 100644
--- a/converter/ppm/ppmtoapplevol.c
+++ b/converter/ppm/ppmtoapplevol.c
@@ -78,7 +78,7 @@ main (int argc, const char * argv[]) {
 
     for (row = 0; row < rows; row++) {
         unsigned int col;
-        
+
         ppm_readppmrow(ifP, pixelrow, cols, maxval, format);
 
         for (col = 0; col < cols; ++col) {
diff --git a/converter/ppm/ppmtoarbtxt.c b/converter/ppm/ppmtoarbtxt.c
index 6d4ed04e..6d4c6eac 100644
--- a/converter/ppm/ppmtoarbtxt.c
+++ b/converter/ppm/ppmtoarbtxt.c
@@ -1079,7 +1079,7 @@ readSkeletonFile(const char *      const filename,
                 int rc;
                 rc = getc(sklfileP);
                 if (rc == EOF) {
-                    /* Not a replacement sequence, just an escape caharacter
+                    /* Not a replacement sequence, just an escape character
                        at the end of the file.
                     */
                     Buffer_add(&buffer, escape);
diff --git a/converter/ppm/ppmtobmp.c b/converter/ppm/ppmtobmp.c
index f89cec8d..41cee482 100644
--- a/converter/ppm/ppmtobmp.c
+++ b/converter/ppm/ppmtobmp.c
@@ -138,7 +138,7 @@ parseCommandLine(int argc, const char ** argv,
         cmdlineP->inputFilename = pm_strdup(argv[1]);
     else
         pm_error("Too many arguments.  The only argument accepted "
-                 "is the input file specificaton");
+                 "is the input file specification");
 
     free(option_def);
 }
diff --git a/converter/ppm/ppmtoilbm.c b/converter/ppm/ppmtoilbm.c
index c5fa4d00..ad07f9fb 100644
--- a/converter/ppm/ppmtoilbm.c
+++ b/converter/ppm/ppmtoilbm.c
@@ -73,7 +73,6 @@
 #include "pm_c_util.h"
 #include "mallocvar.h"
 #include "ppm.h"
-#include "ppmfloyd.h"
 #include "pbm.h"
 #include "runlength.h"
 #include "ilbm.h"
@@ -118,13 +117,13 @@
 static unsigned char *coded_rowbuf; /* buffer for uncompressed scanline */
 static unsigned char *compr_rowbuf; /* buffer for compressed scanline */
 static pixel **pixels;  /* PPM image (NULL for row-by-row operation) */
-static pixel *pixrow;   
+static pixel *pixrow;
     /* current row in PPM image (pointer into pixels array, or buffer
-       for row-by-row operation) 
+       for row-by-row operation)
     */
 
 static long viewportmodes = 0;
-static int slicesize = 1; 
+static int slicesize = 1;
     /* rows per slice for multipalette images - NOT USED */
 
 static unsigned char compmethod = DEF_COMPRESSION;   /* default compression */
@@ -155,9 +154,8 @@ static bodyblock *cur_block = &firstblock;
 static char *anno_chunk, *auth_chunk, *name_chunk, *text_chunk, *copyr_chunk;
 
 /* flags */
-static short compr_force = 0;   
+static short compr_force = 0;
     /* force compressed output, even if the image got larger  - NOT USED */
-static short floyd = 0;         /* apply floyd-steinberg error diffusion */
 static short gen_camg = 0;      /* write CAMG chunk */
 
 #define WORSTCOMPR(bytes)       ((bytes) + (bytes)/128 + 1)
@@ -360,7 +358,7 @@ writeCmap(pixel * const colormap,
     pm_writebiglong(stdout, cmapsize);
     if( maxval != MAXCOLVAL ) {
         int *table;
-        pm_message("maxval is not %d - automatically rescaling colors", 
+        pm_message("maxval is not %d - automatically rescaling colors",
                    MAXCOLVAL);
         table = makeValTable(maxval, MAXCOLVAL);
         for( i = 0; i < colors; i++ ) {
@@ -457,7 +455,7 @@ compressRow(unsigned int const bytes) {
                 &compressedByteCt);
             break;
         default:
-            pm_error("compressRow(): unknown compression method %d", 
+            pm_error("compressRow(): unknown compression method %d",
                      compmethod);
     }
     storeBodyrow(compr_rowbuf, compressedByteCt);
@@ -551,35 +549,35 @@ reportTooManyColors(int         const ifmode,
                     int         const hamplanes,
                     DirectColor const dcol,
                     int         const deepbits) {
-    
+
     int const maxcolors = 1 << maxplanes;
 
     switch( ifmode ) {
     case MODE_HAM:
         pm_message("too many colors for %d planes - "
-                   "proceeding to write a HAM%d file", 
+                   "proceeding to write a HAM%d file",
                    maxplanes, hamplanes);
-        pm_message("if you want a non-HAM file, try doing a 'pnmquant %d'", 
+        pm_message("if you want a non-HAM file, try doing a 'pnmquant %d'",
                    maxcolors);
         break;
     case MODE_DCOL:
         pm_message("too many colors for %d planes - "
-                   "proceeding to write a %d:%d:%d direct color ILBM", 
+                   "proceeding to write a %d:%d:%d direct color ILBM",
                    maxplanes, dcol.r, dcol.g, dcol.b);
         pm_message("if you want a non-direct color file, "
                    "try doing a 'pnmquant %d'", maxcolors);
         break;
     case MODE_DEEP:
         pm_message("too many colors for %d planes - "
-                   "proceeding to write a %d-bit \'deep\' ILBM", 
+                   "proceeding to write a %d-bit \'deep\' ILBM",
                    maxplanes, deepbits*3);
         pm_message("if you want a non-deep file, "
-                   "try doing a 'pnmquant %d'", 
+                   "try doing a 'pnmquant %d'",
                    maxcolors);
         break;
     default:
         pm_error("too many colors for %d planes - "
-                 "try doing a 'pnmquant %d'", 
+                 "try doing a 'pnmquant %d'",
                  maxplanes, maxcolors);
         break;
     }
@@ -599,7 +597,7 @@ getIntVal(const char * const string,
         pm_error("option \"%s\" needs integer argument", option);
 
     if (val < bot || val > top)
-        pm_error("option \"%s\" argument value out of range (%d..%d)", 
+        pm_error("option \"%s\" argument value out of range (%d..%d)",
                  option, bot, top);
 
     return val;
@@ -613,10 +611,10 @@ getComprMethod(const char * const string) {
     int retval;
     if( pm_keymatch(string, "none", 1) || pm_keymatch(string, "0", 1) )
         retval = cmpNone;
-    else if( pm_keymatch(string, "byterun1", 1) || 
+    else if( pm_keymatch(string, "byterun1", 1) ||
              pm_keymatch(string, "1", 1) )
         retval = cmpByteRun1;
-    else 
+    else
         pm_error("unknown compression method: %s", string);
     return retval;
 }
@@ -631,12 +629,12 @@ getMaskType(const char * const string) {
     if( pm_keymatch(string, "none", 1) || pm_keymatch(string, "0", 1) )
         retval = mskNone;
     else
-    if( pm_keymatch(string, "plane", 1) || 
+    if( pm_keymatch(string, "plane", 1) ||
         pm_keymatch(string, "maskplane", 1) ||
         pm_keymatch(string, "1", 1) )
         retval = mskHasMask;
     else
-    if( pm_keymatch(string, "transparentcolor", 1) || 
+    if( pm_keymatch(string, "transparentcolor", 1) ||
         pm_keymatch(string, "2", 1) )
         retval = mskHasTransparentColor;
     else
@@ -665,7 +663,7 @@ getHammapMode(const char * const string) {
     else
     if( pm_keymatch(string, "rgb5", 4) )
         retval = HAMMODE_RGB5;
-    else 
+    else
         pm_error("unknown HAM colormap selection mode: %s", string);
     return retval;
 }
@@ -726,7 +724,7 @@ hcmp(const void * const a,
     const hentry * const vaP = a;
     const hentry * const vbP = b;
 
-    return(vbP->count - vaP->count);  
+    return(vbP->count - vaP->count);
 }
 
 
@@ -801,17 +799,17 @@ computeHamCmap(int   const cols,
                     if( dist <= maxdist ) {
                         unsigned int sum = hmap[i].count + hmap[col].count;
 
-                        hmap[i].r = ROUNDDIV(hmap[i].r * hmap[i].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 + 
+                        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 + 
+                        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 */
-                        for( tmp = i-1; 
-                             tmp >= 0 && hmap[tmp].count < hmap[col].count; 
+                        for( tmp = i-1;
+                             tmp >= 0 && hmap[tmp].count < hmap[col].count;
                              tmp-- )
                             hmap[tmp+1] = hmap[tmp];
                         hmap[tmp+1] = hmap[col];
@@ -878,7 +876,6 @@ doHamBody(FILE *  const ifP,
 
     int col, row, i;
     rawtype *raw_rowbuf;
-    ppm_fs_info *fi = NULL;
     colorhash_table cht, cht2;
     long bodysize = 0;
     int *itoh;      /* table image -> ham */
@@ -898,9 +895,6 @@ doHamBody(FILE *  const ifP,
 
     itoh = makeValTable(maxval, hammaxval);
 
-    if( floyd )
-        fi = ppm_fs_init(cols, maxval, 0);
-
     for( row = 0; row < rows; row++ ) {
         int noprev;
         int spr, spg, spb;   /* scaled values of previous pixel */
@@ -909,9 +903,7 @@ doHamBody(FILE *  const ifP,
 
         noprev = 1;
         prow = nextPixrow(ifP, row);
-        for( col = ppm_fs_startrow(fi, prow); 
-             col < cols; 
-             col = ppm_fs_next(fi, col) ) {
+        for( col = 0; col < cols; ++col ) {
 
             pixel const p = prow[col];
 
@@ -930,15 +922,15 @@ doHamBody(FILE *  const ifP,
                 int ucr, ucg, ucb;  /* unscaled values of colormap entry */
 
                 if(  hammapmode == HAMMODE_GRAY ) {
-                    if( maxval <= 255 ) 
-                        /* Use fast approximation to 
+                    if( maxval <= 255 )
+                        /* Use fast approximation to
                            0.299 r + 0.587 g + 0.114 b. */
                         i = (int)ppm_fastlumin(p);
-                    else 
-                        /* Can't use fast approximation, 
-                           so fall back on floats. 
+                    else
+                        /* Can't use fast approximation,
+                           so fall back on floats.
                         */
-                        i = (int)(PPM_LUMIN(p) + 0.5); 
+                        i = (int)(PPM_LUMIN(p) + 0.5);
                             /* -IUW added '+ 0.5' */
                     i = itoh[i];
                 }
@@ -956,8 +948,8 @@ doHamBody(FILE *  const ifP,
                         }
                     }
                 }
-                ucr = PPM_GETR(colormap[i]); 
-                ucg = PPM_GETG(colormap[i]); 
+                ucr = PPM_GETR(colormap[i]);
+                ucg = PPM_GETG(colormap[i]);
                 ucb = PPM_GETB(colormap[i]);
 
                 if( noprev ) {  /* no previous pixel, must use colormap */
@@ -985,21 +977,21 @@ doHamBody(FILE *  const ifP,
                         (sb - scb)*(sb - scb);
 #endif
 
-                    if( di <= dr && di <= dg && di <= db ) {    
+                    if( di <= dr && di <= dg && di <= db ) {
                         /* prefer colormap lookup */
-                        raw_rowbuf[col] = i; 
+                        raw_rowbuf[col] = i;
                         upr = ucr;  upg = ucg;  upb = ucb;
                         spr = scr;  spg = scg;  spb = scb;
                     }
                     else
                     if( db <= dr && db <= dg ) {
-                        raw_rowbuf[col] = sb + hamcode_blue; 
+                        raw_rowbuf[col] = sb + hamcode_blue;
                         spb = sb;
                         upb = ub;
                     }
                     else
                     if( dr <= dg ) {
-                        raw_rowbuf[col] = sr + hamcode_red;  
+                        raw_rowbuf[col] = sr + hamcode_red;
                         spr = sr;
                         upr = ur;
                     }
@@ -1012,19 +1004,17 @@ doHamBody(FILE *  const ifP,
             }
             else {  /* prefect match in cmap */
                 raw_rowbuf[col] = i;    /* + (HAMCODE_CMAP << colbits) */
-                upr = PPM_GETR(colormap[i]); 
-                upg = PPM_GETG(colormap[i]); 
+                upr = PPM_GETR(colormap[i]);
+                upg = PPM_GETG(colormap[i]);
                 upb = PPM_GETB(colormap[i]);
-                spr = itoh[upr];            
-                spg = itoh[upg];            
+                spr = itoh[upr];
+                spg = itoh[upg];
                 spb = itoh[upb];
             }
-            ppm_fs_update3(fi, col, upr, upg, upb);
         }
         bodysize += encodeRow(ofP, raw_rowbuf, cols, nPlanes);
         if( maskmethod == mskHasMask )
             bodysize += encodeMaskrow(ofP, raw_rowbuf, cols);
-        ppm_fs_endrow(fi);
     }
     if( ofP && ODD(bodysize) )
         putByte(0);
@@ -1033,7 +1023,6 @@ doHamBody(FILE *  const ifP,
 
     /* clean up */
     free(raw_rowbuf);
-    ppm_fs_free(fi);
 
     return bodysize;
 }
@@ -1113,12 +1102,12 @@ ppmToHam(FILE *  const ifP,
             }
             break;
             case HAMMODE_RGB4:
-                colormap = computeHamCmap(cols, rows, maxval, hamcolors, 
+                colormap = computeHamCmap(cols, rows, maxval, hamcolors,
                                           &colors, 4);
                 cmapmaxval = 15;
                 break;
             case HAMMODE_RGB5:
-                colormap = computeHamCmap(cols, rows, maxval, 
+                colormap = computeHamCmap(cols, rows, maxval,
                                           hamcolors, &colors, 5);
                 cmapmaxval = 31;
                 break;
@@ -1129,7 +1118,7 @@ ppmToHam(FILE *  const ifP,
     else {
         hammapmode = HAMMODE_MAPFILE;
         if( colors > hamcolors ) {
-            pm_message("colormap too large - using first %d colors", 
+            pm_message("colormap too large - using first %d colors",
                        hamcolors);
             colors = hamcolors;
         }
@@ -1142,9 +1131,9 @@ ppmToHam(FILE *  const ifP,
         newcmap = ppm_allocrow(colors);
         table = makeValTable(cmapmaxval, maxval);
         for( i = 0; i < colors; i++ )
-            PPM_ASSIGN(newcmap[i], 
-                       table[PPM_GETR(colormap[i])], 
-                       table[PPM_GETG(colormap[i])], 
+            PPM_ASSIGN(newcmap[i],
+                       table[PPM_GETR(colormap[i])],
+                       table[PPM_GETG(colormap[i])],
                        table[PPM_GETB(colormap[i])]);
         free(table);
         ppm_freerow(colormap);
@@ -1158,16 +1147,16 @@ ppmToHam(FILE *  const ifP,
 
     bodysize = oldsize = rows * TOTALPLANES(nPlanes) * RowBytes(cols);
     if( DO_COMPRESS ) {
-        bodysize = doHamBody(ifP, NULL, cols, rows, maxval, 
+        bodysize = doHamBody(ifP, NULL, cols, rows, maxval,
                                hammaxval, nPlanes, colormap, colors);
-        /*bodysize = doHamBody(ifP, NULL, cols, 
+        /*bodysize = doHamBody(ifP, NULL, cols,
           rows, maxval, hammaxval, nPlanes, colbits, nocolor);*/
         if( bodysize > oldsize )
             pm_message("warning - %s compression increases BODY size "
-                       "by %ld%%", 
+                       "by %ld%%",
                        cmpNAME[compmethod], 100*(bodysize-oldsize)/oldsize);
         else
-            pm_message("BODY compression (%s): %ld%%", 
+            pm_message("BODY compression (%s): %ld%%",
                        cmpNAME[compmethod], 100*(oldsize-bodysize)/oldsize);
     }
 
@@ -1195,7 +1184,7 @@ ppmToHam(FILE *  const ifP,
     if( DO_COMPRESS )
         writeBodyRows();
     else
-        doHamBody(ifP, stdout, cols, rows, maxval, hammaxval, 
+        doHamBody(ifP, stdout, cols, rows, maxval, hammaxval,
                   nPlanes, colormap, colors);
 }
 
@@ -1210,7 +1199,7 @@ doDeepBody(FILE * const ifP,
            FILE * const ofP,
            int    const cols,
            int    const rows,
-           pixval const maxval, 
+           pixval const maxval,
            int    const bitspercolor) {
 
     int row, col;
@@ -1226,7 +1215,7 @@ doDeepBody(FILE * const ifP,
 
     newmaxval = pm_bitstomaxval(bitspercolor);
     if( maxval != newmaxval ) {
-        pm_message("maxval is not %d - automatically rescaling colors", 
+        pm_message("maxval is not %d - automatically rescaling colors",
                    newmaxval);
         table = makeValTable(maxval, newmaxval);
     }
@@ -1294,7 +1283,7 @@ ppmToDeep(FILE * const ifP,
             pm_message("warning - %s compression increases BODY size by %ld%%",
                        cmpNAME[compmethod], 100*(bodysize-oldsize)/oldsize);
         else
-            pm_message("BODY compression (%s): %ld%%", 
+            pm_message("BODY compression (%s): %ld%%",
                        cmpNAME[compmethod], 100*(oldsize-bodysize)/oldsize);
     }
 
@@ -1335,7 +1324,7 @@ doDcolBody(FILE *        const ifP,
            FILE *        const ofP,
            int           const cols,
            int           const rows,
-           pixval        const maxval, 
+           pixval        const maxval,
            DirectColor * const dcol) {
 
     int row, col;
@@ -1405,10 +1394,10 @@ ppmToDcol(FILE *        const ifP,
         bodysize = doDcolBody(ifP, NULL, cols, rows, maxval, dcol);
         if( bodysize > oldsize )
             pm_message("warning - %s compression increases BODY size by %ld%%",
-                       cmpNAME[compmethod], 
+                       cmpNAME[compmethod],
                        100*(bodysize-oldsize)/oldsize);
         else
-            pm_message("BODY compression (%s): %ld%%", cmpNAME[compmethod], 
+            pm_message("BODY compression (%s): %ld%%", cmpNAME[compmethod],
                        100*(oldsize-bodysize)/oldsize);
     }
 
@@ -1467,35 +1456,30 @@ doStdBody(FILE *  const ifP,
     int row, col, i;
     pixel *pP;
     rawtype *raw_rowbuf;
-    ppm_fs_info *fi = NULL;
     long bodysize = 0;
     int usehash = 1;
     colorhash_table cht;
 
     MALLOCARRAY_NOFAIL(raw_rowbuf, cols);
     cht = ppm_colorrowtocolorhash(colormap, colors);
-    if( floyd )
-        fi = ppm_fs_init(cols, maxval, FS_ALTERNATE);
 
     for( row = 0; row < rows; row++ ) {
         pixel *prow;
         prow = nextPixrow(ifP, row);
 
-        for( col = ppm_fs_startrow(fi, prow); 
-             col < cols; 
-             col = ppm_fs_next(fi, col) ) {
+        for( col = 0; col < cols; ++col ) {
             pP = &prow[col];
 
-            if( maskmethod == mskHasTransparentColor && 
+            if( maskmethod == mskHasTransparentColor &&
                 maskrow[col] == PBM_WHITE )
                 i = transpIndex;
             else {
                 /* Check hash table to see if we have already matched
-                   this color. 
+                   this color.
                 */
                 i = ppm_lookupcolor(cht, pP);
                 if( i == -1 ) {
-                    i = ppm_findclosestcolor(colormap, colors, pP);    
+                    i = ppm_findclosestcolor(colormap, colors, pP);
                         /* No; search colormap for closest match. */
                     if( usehash ) {
                         if( ppm_addtocolorhash(cht, pP, i) < 0 ) {
@@ -1507,12 +1491,10 @@ doStdBody(FILE *  const ifP,
                 }
             }
             raw_rowbuf[col] = i;
-            ppm_fs_update(fi, col, &colormap[i]);
         }
         bodysize += encodeRow(ofP, raw_rowbuf, cols, nPlanes);
         if( maskmethod == mskHasMask )
             bodysize += encodeMaskrow(ofP, raw_rowbuf, cols);
-        ppm_fs_endrow(fi);
     }
     if( ofP && ODD(bodysize) )
         putByte(0);
@@ -1520,7 +1502,6 @@ doStdBody(FILE *  const ifP,
     /* clean up */
     ppm_freecolorhash(cht);
     free(raw_rowbuf);
-    ppm_fs_free(fi);
 
     return bodysize;
 }
@@ -1534,7 +1515,7 @@ ppmToStd(FILE *  const ifP,
          int     const maxval,
          pixel * const colormapArg,
          int     const colorsArg,
-         int     const cmapmaxvalArg, 
+         int     const cmapmaxvalArg,
          int     const maxcolors,
          int     const nPlanes) {
 
@@ -1550,7 +1531,7 @@ ppmToStd(FILE *  const ifP,
 
     if( maskmethod == mskHasTransparentColor ) {
         if( transpColor ) {
-            transpIndex = 
+            transpIndex =
                 ppm_addtocolorrow(colormap, &colors, maxcolors, transpColor);
         }
         else
@@ -1572,9 +1553,9 @@ ppmToStd(FILE *  const ifP,
         newcmap = ppm_allocrow(colors);
         table = makeValTable(cmapmaxval, maxval);
         for (i = 0; i < colors; ++i)
-            PPM_ASSIGN(newcmap[i], 
-                       table[PPM_GETR(colormap[i])], 
-                       table[PPM_GETG(colormap[i])], 
+            PPM_ASSIGN(newcmap[i],
+                       table[PPM_GETR(colormap[i])],
+                       table[PPM_GETG(colormap[i])],
                        table[PPM_GETB(colormap[i])]);
         free(table);
         colormap = newcmap;
@@ -1584,13 +1565,13 @@ ppmToStd(FILE *  const ifP,
 
     bodysize = oldsize = rows * TOTALPLANES(nPlanes) * RowBytes(cols);
     if( DO_COMPRESS ) {
-        bodysize = doStdBody(ifP, NULL, cols, rows, maxval, colormap, 
+        bodysize = doStdBody(ifP, NULL, cols, rows, maxval, colormap,
                              colors, nPlanes);
         if( bodysize > oldsize )
             pm_message("warning - %s compression increases BODY size by %ld%%",
                        cmpNAME[compmethod], 100*(bodysize-oldsize)/oldsize);
         else
-            pm_message("BODY compression (%s): %ld%%", 
+            pm_message("BODY compression (%s): %ld%%",
                        cmpNAME[compmethod], 100*(oldsize-bodysize)/oldsize);
     }
 
@@ -1659,7 +1640,7 @@ ppmToRgb8(FILE * const ifP,
         for( col1 = 0; col1 < cols; col1 = col2 ) {
             col2 = col1 + 1;
             if( maskrow ) {
-                while( col2 < cols && PPM_EQUAL(pP[col1], pP[col2]) && 
+                while( col2 < cols && PPM_EQUAL(pP[col1], pP[col2]) &&
                        maskrow[col1] == maskrow[col2] )
                     col2++;
             }
@@ -1750,7 +1731,7 @@ ppmToRgbn(FILE * const ifP,
         for( col1 = 0; col1 < cols; col1 = col2 ) {
             col2 = col1 + 1;
             if( maskrow ) {
-                while( col2 < cols && PPM_EQUAL(pP[col1], pP[col2]) && 
+                while( col2 < cols && PPM_EQUAL(pP[col1], pP[col2]) &&
                        maskrow[col1] == maskrow[col2] )
                     col2++;
             }
@@ -1782,14 +1763,14 @@ ppmToRgbn(FILE * const ifP,
                 else {
                     ++compr_len;                  /* 3 bit repeat count = 0 */
                     if( count <= 255 )
-                        compr_row[compr_len++] = (unsigned char)count;  
+                        compr_row[compr_len++] = (unsigned char)count;
                             /* byte repeat count */
                     else {
-                        compr_row[compr_len++] = (unsigned char)0;   
+                        compr_row[compr_len++] = (unsigned char)0;
                             /* byte repeat count = 0 */
-                        compr_row[compr_len++] = (count >> 8) & 0xff; 
+                        compr_row[compr_len++] = (count >> 8) & 0xff;
                             /* word repeat count MSB */
-                        compr_row[compr_len++] = count & 0xff;    
+                        compr_row[compr_len++] = count & 0xff;
                             /* word repeat count LSB */
                     }
                 }
@@ -1878,6 +1859,7 @@ main(int argc, char ** argv) {
     pixval cmapmaxval;      /* maxval of colors in cmap */
     const char * mapfile;
     const char * transpname;
+    unsigned int defunctArgs = 0;
 
     ppm_init(&argc, argv);
 
@@ -1902,7 +1884,7 @@ main(int argc, char ** argv) {
         if( pm_keymatch(argv[argn], "-rgbn", 5) )
             forcemode = MODE_RGBN;
         else
-        if( pm_keymatch(argv[argn], "-maxplanes", 4) || 
+        if( pm_keymatch(argv[argn], "-maxplanes", 4) ||
             pm_keymatch(argv[argn], "-mp", 3) ) {
             if( ++argn >= argc )
                 pm_error("-maxplanes requires a value");
@@ -1910,7 +1892,7 @@ main(int argc, char ** argv) {
             fixplanes = 0;
         }
         else
-        if( pm_keymatch(argv[argn], "-fixplanes", 4) || 
+        if( pm_keymatch(argv[argn], "-fixplanes", 4) ||
             pm_keymatch(argv[argn], "-fp", 3) ) {
             if( ++argn >= argc )
                 pm_error("-fixplanes requires a value");
@@ -1935,7 +1917,7 @@ main(int argc, char ** argv) {
                     break;
                 default:
                     pm_error("This program does not know how to handle "
-                             "masking method '%s'", 
+                             "masking method '%s'",
                              mskNAME[maskmethod]);
             }
         }
@@ -2014,7 +1996,7 @@ main(int argc, char ** argv) {
         if( pm_keymatch(argv[argn], "-hambits", 5) ) {
             if( ++argn >= argc )
                 pm_usage("-hambits requires a value");
-            hamplanes = 
+            hamplanes =
                 getIntVal(argv[argn], argv[argn-1], 3, HAMMAXPLANES-2) +2;
         }
         else
@@ -2118,7 +2100,7 @@ main(int argc, char ** argv) {
                 forcemode = MODE_NONE;
         }
         else
-        if( pm_keymatch(argv[argn], "-dcbits", 4) || 
+        if( pm_keymatch(argv[argn], "-dcbits", 4) ||
             pm_keymatch(argv[argn], "-dcplanes", 4) ) {
             if( argc - argn < 4 )
                 pm_error("-dcbits requires 4 arguments");
@@ -2154,13 +2136,9 @@ main(int argc, char ** argv) {
             compmethod = getComprMethod(argv[argn]);
         }
         else
-        if( pm_keymatch(argv[argn], "-floyd", 3) || 
-            pm_keymatch(argv[argn], "-fs", 3) )
-            floyd = 1;
-        else
-        if( pm_keymatch(argv[argn], "-nofloyd", 5) || 
+        if( pm_keymatch(argv[argn], "-nofloyd", 5) ||
             pm_keymatch(argv[argn], "-nofs", 5) )
-            floyd = 0;
+	    defunctArgs++;
         else
         if( pm_keymatch(argv[argn], "-annotation", 3) ) {
             if( ++argn >= argc )
@@ -2230,10 +2208,10 @@ main(int argc, char ** argv) {
         case MODE_CMAP:
             /* Figure out the colormap. */
             pm_message("computing colormap...");
-            colormap = ppm_mapfiletocolorrow(ifP, MAXCOLORS, &colors, 
+            colormap = ppm_mapfiletocolorrow(ifP, MAXCOLORS, &colors,
                                              &cmapmaxval);
             if (colormap == NULL)
-                pm_error("too many colors - try doing a 'pnmquant %d'", 
+                pm_error("too many colors - try doing a 'pnmquant %d'",
                          MAXCOLORS);
             pm_message("%d colors found", colors);
             break;
@@ -2241,11 +2219,11 @@ main(int argc, char ** argv) {
             if (mapfile)
                 initRead(ifP, &cols, &rows, &maxval, &format, 0);
             else {
-                initRead(ifP, &cols, &rows, &maxval, &format, 1);  
+                initRead(ifP, &cols, &rows, &maxval, &format, 1);
                     /* read file into memory */
                 pm_message("computing colormap...");
-                colormap = 
-                    ppm_computecolorrow(pixels, cols, rows, MAXCOLORS, 
+                colormap =
+                    ppm_computecolorrow(pixels, cols, rows, MAXCOLORS,
                                         &colors);
                 if (colormap) {
                     cmapmaxval = maxval;
@@ -2266,7 +2244,7 @@ main(int argc, char ** argv) {
 
         pm_message("reading colormap file...");
         mapfp = pm_openr(mapfile);
-        colormap = ppm_mapfiletocolorrow(mapfp, MAXCOLORS, &colors, 
+        colormap = ppm_mapfiletocolorrow(mapfp, MAXCOLORS, &colors,
                                          &cmapmaxval);
         pm_close(mapfp);
         if (colormap == NULL)
@@ -2302,11 +2280,11 @@ main(int argc, char ** argv) {
         if (DO_COMPRESS)
             pm_rlenc_allocoutbuf(&compr_rowbuf, RowBytes(cols), PM_RLE_PACKBITS);
     }
-    
+
     switch (mode) {
         case MODE_HAM:
             viewportmodes |= vmHAM;
-            ppmToHam(ifP, cols, rows, maxval, 
+            ppmToHam(ifP, cols, rows, maxval,
                      colormap, colors, cmapmaxval, hamplanes);
             break;
         case MODE_DEEP:
@@ -2325,9 +2303,7 @@ main(int argc, char ** argv) {
             ppmToCmap(colormap, colors, cmapmaxval);
             break;
         default:
-            if (mapfile == NULL)
-                floyd = 0;          /* would only slow down conversion */
-            ppmToStd(ifP, cols, rows, maxval, colormap, colors, 
+            ppmToStd(ifP, cols, rows, maxval, colormap, colors,
                      cmapmaxval, MAXCOLORS, nPlanes);
             break;
     }
diff --git a/converter/ppm/ppmtomitsu.c b/converter/ppm/ppmtomitsu.c
index 5b0b3245..50b790d6 100644
--- a/converter/ppm/ppmtomitsu.c
+++ b/converter/ppm/ppmtomitsu.c
@@ -705,7 +705,7 @@ main(int argc, char * argv[]) {
         for (row = 0; row < rows; ++row)
             ppm_readppmrow(ifP, pixels[row], cols, maxval, format);
 
-        /* first check wether we can use the lut transfer */
+        /* first check whether we can use the lut transfer */
 
         table = ppm_computecolorhist(pixels, cols, rows, MAXLUTCOL+1,
                                      &nColor);
diff --git a/converter/ppm/ppmtompeg/LOGIC b/converter/ppm/ppmtompeg/LOGIC
index 8c19dc8d..b346d597 100644
--- a/converter/ppm/ppmtompeg/LOGIC
+++ b/converter/ppm/ppmtompeg/LOGIC
@@ -45,7 +45,7 @@ is ready.
 
 When an encoder server finishes an assignment, it connects to the master
 server TCP listen port and tells the master it is done, and receives over
-the same connetion its next assignment.  If there is no more work to do,
+the same connection its next assignment.  If there is no more work to do,
 the master server instead tells the encoder server just to terminate.
 
 When the master server has told every encoder server to terminate, it
diff --git a/converter/ppm/ppmtompeg/Makefile b/converter/ppm/ppmtompeg/Makefile
index eeab9727..9ad09c77 100644
--- a/converter/ppm/ppmtompeg/Makefile
+++ b/converter/ppm/ppmtompeg/Makefile
@@ -124,7 +124,7 @@ profile: LDFLAGS_TARGET = \
 PERL = perl
 
 # The following stuff is for the Huffman encoding tables.  It's commented-out
-# because you probably don't want to change this.  If you do, then uncommment
+# because you probably don't want to change this.  If you do, then uncomment
 # it.
 #
 # huff.h: huff.c
diff --git a/converter/ppm/ppmtompeg/bsearch.c b/converter/ppm/ppmtompeg/bsearch.c
index c618bbd4..b825ef72 100644
--- a/converter/ppm/ppmtompeg/bsearch.c
+++ b/converter/ppm/ppmtompeg/bsearch.c
@@ -26,7 +26,7 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  */
 
-/*  
+/*
  *  $Header: /n/picasso/project/mpeg/mpeg_dist/mpeg_encode/RCS/bsearch.c,v 1.10 1995/08/07 21:49:01 smoot Exp $
  *  $Log: bsearch.c,v $
  *  Revision 1.10  1995/08/07 21:49:01  smoot
@@ -37,7 +37,7 @@
  *  (B frames which are backward P's at the start of a sequence)
  *
  *  Revision 1.8  1995/03/27 19:17:43  smoot
- *  killed useless type error messge (int32 defiend as int)
+ *  killed useless type error message (int32 defined as int)
  *
  * Revision 1.7  1995/01/19  23:07:20  eyhung
  * Changed copyrights
@@ -194,7 +194,7 @@ FindBestMatchExhaust(const LumBlock * const blockP,
 
     /* maybe should try spiral pattern centered around  prev motion vector? */
 
-    /* try a spiral pattern */    
+    /* try a spiral pattern */
     for (distance = stepSize;
          distance <= searchRange;
          distance += stepSize) {
@@ -212,7 +212,7 @@ FindBestMatchExhaust(const LumBlock * const blockP,
                         m.y = my; m.x = mx;
                         diff = LumAddMotionError(currentBlockP, blockP, prev,
                                                  by, bx, m, bestDiff);
-                        
+
                         if (diff < bestDiff) {
                             *motionP = m;
                             bestDiff = diff;
@@ -237,7 +237,7 @@ FindBestMatchExhaust(const LumBlock * const blockP,
                         diff = LumAddMotionError(currentBlockP, blockP, prev,
                                                  by, bx,
                                                  m, bestDiff);
-                        
+
                         if (diff < bestDiff) {
                             *motionP = m;
                             bestDiff = diff;
@@ -310,7 +310,7 @@ FindBestMatchTwoLevel(const LumBlock * const blockP,
     if (VALID_MOTION(*motionP)) {
         bestDiff = LumAddMotionError(currentBlockP, blockP, prev, by, bx,
                                      *motionP, bestSoFar);
-        
+
         if (bestSoFar < bestDiff)
             bestDiff = bestSoFar;
     } else {
@@ -323,7 +323,7 @@ FindBestMatchTwoLevel(const LumBlock * const blockP,
 
     /* maybe should try spiral pattern centered around  prev motion vector? */
 
-    /* try a spiral pattern */    
+    /* try a spiral pattern */
     for ( distance = 2; distance <= searchRange; distance += 2 ) {
         tempRightMY = MIN(distance, rightMY);
         tempRightMX = MIN(distance, rightMX);
@@ -339,7 +339,7 @@ FindBestMatchTwoLevel(const LumBlock * const blockP,
                         m.y = my; m.x = mx;
                         diff = LumAddMotionError(currentBlockP, blockP, prev,
                                                  by, bx, m, bestDiff);
-                        
+
                         if (diff < bestDiff) {
                             *motionP = m;
                             bestDiff = diff;
@@ -361,7 +361,7 @@ FindBestMatchTwoLevel(const LumBlock * const blockP,
                         m.y = my; m.x = mx;
                         diff = LumAddMotionError(currentBlockP, blockP, prev,
                                                  by, bx, m, bestDiff);
-                        
+
                         if (diff < bestDiff) {
                             *motionP = m;
                             bestDiff = diff;
@@ -423,7 +423,7 @@ trySpacing(int              const spacing,
            MpegFrame *      const prev,
            int              const by,
            int              const bx) {
-           
+
     int tempRightMY, tempRightMX;
     int my;
     int bestDiff;
@@ -435,7 +435,7 @@ trySpacing(int              const spacing,
 
     tempRightMY = MIN(rightMY, center.y + spacing + 1);
     tempRightMX = MIN(rightMX, center.x + spacing + 1);
-    
+
     for (my = center.y - spacing; my < tempRightMY; my += spacing) {
         if (my >= leftMY) {
             int mx;
@@ -446,7 +446,7 @@ trySpacing(int              const spacing,
                     m.y = my; m.x = mx;
                     diff = LumAddMotionError(currentBlockP, blockP, prev,
                                              by, bx, m, bestDiff);
-                    
+
                     if (diff < bestDiff) {
                         /* We have a new best */
                         newCenter = m;
@@ -466,7 +466,7 @@ static void
 chooseNewSpacing(int   const oldSpacing,
                  int   const stepSize,
                  int * const newSpacingP) {
-        
+
     if (stepSize == 2) {  /* make sure spacing is even */
         if (oldSpacing == 2)
             *newSpacingP = 0;
@@ -530,7 +530,7 @@ FindBestMatchLogarithmic(const LumBlock * const blockP,
 
     /* Start at (0,0) */
     center.y = center.x = 0;
-    
+
     while (spacing >= stepSize) {
         trySpacing(spacing, center, bestDiff,
                    &center, &bestDiff,
@@ -580,7 +580,7 @@ FindBestMatchSubSample(const LumBlock * const blockP,
                        int              const searchRange) {
 
     /* too lazy to write the code for this... */
-    
+
     return FindBestMatchExhaust(blockP, currentBlockP, prev,
                                 by, bx, motionP, bestSoFar,
                                 searchRange);
@@ -671,9 +671,9 @@ BMotionSearchNoInterp(const LumBlock * const currentBlockP,
     /* CALL SEARCH PROCEDURE */
     switch(psearchAlg) {
     case PSEARCH_SUBSAMPLE:
-        *forwardErrP = PSubSampleSearch(currentBlockP, prev, by, bx, 
+        *forwardErrP = PSubSampleSearch(currentBlockP, prev, by, bx,
                                         &motionP->fwd,searchRangeB);
-        *backErrP = PSubSampleSearch(currentBlockP, next, by, bx, 
+        *backErrP = PSubSampleSearch(currentBlockP, next, by, bx,
                                      &motionP->bwd, searchRangeB);
         break;
     case PSEARCH_EXHAUSTIVE:
@@ -690,9 +690,9 @@ BMotionSearchNoInterp(const LumBlock * const currentBlockP,
                                      *forwardErrP, searchRangeB);
         break;
     case PSEARCH_LOGARITHMIC:
-        *forwardErrP = PLogarithmicSearch(currentBlockP, prev, by, bx, 
+        *forwardErrP = PLogarithmicSearch(currentBlockP, prev, by, bx,
                                           &motionP->fwd, searchRangeB);
-        *backErrP = PLogarithmicSearch(currentBlockP, next, by, bx, 
+        *backErrP = PLogarithmicSearch(currentBlockP, next, by, bx,
                                        &motionP->bwd, searchRangeB);
         break;
     case PSEARCH_TWOLEVEL:
@@ -731,7 +731,7 @@ BMotionSearchNoInterp(const LumBlock * const currentBlockP,
  * *fmyP,fmxP,bmyP,bmxP are inputs as well as outputs.  We do not update
  * them if it would make the error worse than the existing values.  Otherwise,
  * we update them to the vectors we find to be best.
- * 
+ *
  *===========================================================================*/
 static int
 BMotionSearchSimple(const LumBlock * const currentBlockP,
@@ -750,7 +750,7 @@ BMotionSearchSimple(const LumBlock * const currentBlockP,
     /* STEP 1 */
     BMotionSearchNoInterp(currentBlockP, prev, next, by, bx, motionP,
                           &forwardErr, &backErr, TRUE);
-              
+
     /* STEP 2 */
 
     ComputeBMotionLumBlock(prev, next, by, bx, MOTION_INTERPOLATE,
@@ -799,7 +799,7 @@ BMotionSearchCross2(const LumBlock * const currentBlockP,
                     int              const bx,
                     motion *         const motionP,
                     int              const oldMode) {
-    
+
     int retval;
     LumBlock forwardBlock, backBlock;
     int32   forwardErr, backErr;
@@ -816,19 +816,19 @@ BMotionSearchCross2(const LumBlock * const currentBlockP,
 
     {
         /* STEP 2 */
-        
+
         struct motion motion;
         motion.fwd = motionP->fwd;
         motion.bwd.y = motion.bwd.x = 0;
         ComputeBMotionLumBlock(prev, next, by, bx, MOTION_FORWARD, motion,
                                &forwardBlock);
-        
+
         motion.fwd.y = motion.fwd.x = 0;
         motion.bwd = motionP->bwd;
         ComputeBMotionLumBlock(prev, next, by, bx, MOTION_BACKWARD, motion,
                                &backBlock);
     }
-    /* try a cross-search; total of 4 local searches */    
+    /* try a cross-search; total of 4 local searches */
     newMotion = *motionP;
 
     interpErrF = FindBestMatch(&forwardBlock, currentBlockP,
@@ -934,11 +934,11 @@ BMotionSearchExhaust(const LumBlock * const currentBlockP,
                                            motion, &forwardBlock);
 
                     newMotion = motion.fwd;
-                    
+
                     diff = FindBestMatch(&forwardBlock,
                                          currentBlockP, next, by, bx,
                                          &newMotion, bestDiff, searchRangeB);
-                    
+
                     if (diff < bestDiff) {
                         motionP->fwd = motion.fwd;
                         motionP->bwd = newMotion;
@@ -968,7 +968,7 @@ BMotionSearchExhaust(const LumBlock * const currentBlockP,
  *
  * PRECONDITIONS:   The relevant block in 'current' is valid (it has not
  *          been dct'd).  Thus, the data in 'current' can be
- *          accesed through y_blocks, cr_blocks, and cb_blocks.
+ *          accessed through y_blocks, cr_blocks, and cb_blocks.
  *          This is not the case for the blocks in 'prev' and
  *          'next.'  Therefore, references into 'prev' and 'next'
  *          should be done
@@ -1001,7 +1001,7 @@ BMotionSearch(const LumBlock * const currentBlockP,
         PMotionSearch(currentBlockP, next, by, bx, &motionP->bwd);
         return MOTION_BACKWARD;
     }
-  
+
     /* otherwise simply call the appropriate algorithm, based on user
        preference
     */
diff --git a/converter/ppm/ppmtompeg/docs/template.param b/converter/ppm/ppmtompeg/docs/template.param
index 78ad5300..fb837428 100644
--- a/converter/ppm/ppmtompeg/docs/template.param
+++ b/converter/ppm/ppmtompeg/docs/template.param
@@ -138,7 +138,7 @@ BQSCALE		25
 # this must be ORIGINAL or DECODED
 REFERENCE_FRAME	ORIGINAL
 
-# for parallel parameters see parallel.param in the exmaples subdirectory
+# for parallel parameters see parallel.param in the examples subdirectory
 
 # if you want constant bit-rate mode, specify it as follows (number is bits/sec):
 BIT_RATE  1000000
diff --git a/converter/ppm/ppmtompeg/examples/payam.param b/converter/ppm/ppmtompeg/examples/payam.param
index ce886914..e9287a89 100644
--- a/converter/ppm/ppmtompeg/examples/payam.param
+++ b/converter/ppm/ppmtompeg/examples/payam.param
@@ -16,7 +16,7 @@ kh*.pnm	[1-3]
 END_INPUT
 
 
-# motion vector search paramters
+# motion vector search parameters
 
 # MAD or MSE -- must be upper case
 ERROR		MAD
diff --git a/converter/ppm/ppmtompeg/examples/payam18.param b/converter/ppm/ppmtompeg/examples/payam18.param
index 7f7b767e..95839e83 100644
--- a/converter/ppm/ppmtompeg/examples/payam18.param
+++ b/converter/ppm/ppmtompeg/examples/payam18.param
@@ -15,7 +15,7 @@ kh*.pnm	[1-39]
 END_INPUT
 
 
-# motion vector search paramters
+# motion vector search parameters
 
 # FULL or HALF -- must be upper case
 PIXEL		HALF
diff --git a/converter/ppm/ppmtompeg/examples/template.param b/converter/ppm/ppmtompeg/examples/template.param
index 78ad5300..fb837428 100644
--- a/converter/ppm/ppmtompeg/examples/template.param
+++ b/converter/ppm/ppmtompeg/examples/template.param
@@ -138,7 +138,7 @@ BQSCALE		25
 # this must be ORIGINAL or DECODED
 REFERENCE_FRAME	ORIGINAL
 
-# for parallel parameters see parallel.param in the exmaples subdirectory
+# for parallel parameters see parallel.param in the examples subdirectory
 
 # if you want constant bit-rate mode, specify it as follows (number is bits/sec):
 BIT_RATE  1000000
diff --git a/converter/ppm/ppmtompeg/frame.c b/converter/ppm/ppmtompeg/frame.c
index f5a0d39d..09e35410 100644
--- a/converter/ppm/ppmtompeg/frame.c
+++ b/converter/ppm/ppmtompeg/frame.c
@@ -12,7 +12,7 @@
  *  Frame_AllocYCC                               *
  *  Frame_AllocDecoded                           *
  *  Frame_AllocHalf                                  *
- *  Frame_Resize                                     * 
+ *  Frame_Resize                                     *
  *                                       *
  *===========================================================================*/
 
@@ -52,7 +52,7 @@
  *===========*/
 
 /* The maximum number of B-Frames allowed between reference frames. */
-#define  B_FRAME_RUN  16    
+#define  B_FRAME_RUN  16
 
 /*==================*
  * GLOBAL VARIABLES *
@@ -64,13 +64,13 @@ static unsigned int numOfFrames;
 
 /*====================================================
 * Resize_Array_Width
-*    
+*
 *   This function will resize any array width up
 * or down in size.  The algorithm is based on the
 * least common multiple approach more commonly
 * used in audio frequency adjustments.
 *=====================================================*/
-static void 
+static void
 Resize_Array_Width(uint8 ** const inarray,
                    int      const in_x,
                    int      const in_y,
@@ -86,7 +86,7 @@ Resize_Array_Width(uint8 ** const inarray,
     uint8 pointA,pointB;
     double slope,diff;
 #endif
-    
+
     for (i = 0; i < in_y; ++i) {     /* For each row */
         unsigned int j;
         inptr = &inarray[i][0];
@@ -106,7 +106,7 @@ Resize_Array_Width(uint8 ** const inarray,
                     in_total = in_total - out_x;
                     --inptr;
                 }
-            } else {  
+            } else {
 #ifdef DOING_INTERPOLATION
                 pointA = *inptr;
 #endif
@@ -124,10 +124,10 @@ Resize_Array_Width(uint8 ** const inarray,
                 } else {
                     *outptr = (pointB -
                                (uint8)(slope*(((float)(out_x)) - diff)));
-                } 
+                }
 #endif
                 /* Non-Interpolative solution */
-                *outptr = *inptr;  
+                *outptr = *inptr;
 
                 ++outptr;
                 out_total = out_total + in_x;
@@ -153,7 +153,7 @@ Resize_Array_Width(uint8 ** const inarray,
 * Same as Resize_array_Width except pointer
 * manipulation must change.
 *===============================*/
-static void 
+static void
 Resize_Array_Height(uint8 ** const inarray,
                     int      const in_x,
                     int      const in_y,
@@ -176,7 +176,7 @@ Resize_Array_Height(uint8 ** const inarray,
         out_total = 0;
         k = 0;
         for(j=0; j < out_y; ++j){  /* for each output value */
-            if (in_total == out_total) {  
+            if (in_total == out_total) {
                 outarray[j][i] = inarray[k][i];
                 out_total=out_total+in_y;
                 while(in_total < out_total){
@@ -187,7 +187,7 @@ Resize_Array_Height(uint8 ** const inarray,
                     in_total = in_total - out_y;
                     --k;
                 }
-            } else {  
+            } else {
 #ifdef DOING_INTERPOLATION
                 pointA = inarray[k][i];
                 if (k != (in_y - 1)) {
@@ -210,7 +210,7 @@ Resize_Array_Height(uint8 ** const inarray,
                     in_total = in_total - out_y;
                     --k;
                 }
-            } 
+            }
         }
     }
 }
@@ -220,7 +220,7 @@ Resize_Array_Height(uint8 ** const inarray,
 /*========================================================
 * Resize_Width
 *======================================================*/
-static void  
+static void
 Resize_Width(MpegFrame * const omfrw,
              MpegFrame * const mfrw,
              int         const in_x,
@@ -274,12 +274,12 @@ Resize_Width(MpegFrame * const omfrw,
             free(mfrw->orig_y[i]);
         }
         free(mfrw->orig_y);
-        
+
         for (i = 0; i < in_y / 2; ++i) {
             free(mfrw->orig_cr[i]);
         }
         free(mfrw->orig_cr);
-        
+
         for (i = 0; i < in_y / 2; ++i) {
             free(mfrw->orig_cb[i]);
         }
@@ -300,9 +300,9 @@ Resize_Height(MpegFrame * const omfrh,
               int         const in_x,
               int         const in_y,
               int         const out_y) {
-    
-    unsigned int y; 
-    
+
+    unsigned int y;
+
     Fsize_y = out_y;
 
     /* Allocate new frame memory */
@@ -347,12 +347,12 @@ Resize_Height(MpegFrame * const omfrh,
             free(mfrh->orig_y[i]);
         }
         free(mfrh->orig_y);
-        
+
     for (i = 0; i < in_y / 2; ++i) {
         free(mfrh->orig_cr[i]);
     }
     free(mfrh->orig_cr);
-    
+
     for (i = 0; i < in_y / 2; ++i) {
         free(mfrh->orig_cb[i]);
     }
@@ -386,8 +386,8 @@ Frame_Init(unsigned int const numOfFramesRequested) {
     for (idx = 0; idx < numOfFrames; ++idx) {
         MALLOCVAR(frameMemory[idx]);
         frameMemory[idx]->inUse = FALSE;
-        frameMemory[idx]->orig_y = NULL;    
-        frameMemory[idx]->y_blocks = NULL; 
+        frameMemory[idx]->orig_y = NULL;
+        frameMemory[idx]->y_blocks = NULL;
         frameMemory[idx]->decoded_y = NULL;
         frameMemory[idx]->halfX = NULL;
         frameMemory[idx]->next = NULL;
@@ -458,11 +458,11 @@ FreeFrame(MpegFrame * const frameP) {
             for ( i = 0; i < Fsize_y; ++i )
                 free(frameP->halfX[i]);
             free(frameP->halfX);
-            
+
             for (i = 0; i < Fsize_y-1; ++i)
                 free(frameP->halfY[i]);
             free(frameP->halfY);
-            
+
             for (i = 0; i < Fsize_y-1; ++i)
                 free(frameP->halfBoth[i]);
             free(frameP->halfBoth);
@@ -542,7 +542,7 @@ GetUnusedFrame() {
                 "See the man page for help.\n");
         exit(1);
     }
-    return frameMemory[idx]; 
+    return frameMemory[idx];
 }
 
 
@@ -638,7 +638,7 @@ Frame_AllocBlocks(MpegFrame * const frameP) {
             MALLOCARRAY(frameP->y_blocks[i], dctx);
             ERRCHK(frameP->y_blocks[i], "malloc");
         }
-    
+
         MALLOCARRAY(frameP->cr_blocks, dcty / 2);
         ERRCHK(frameP->cr_blocks, "malloc");
         MALLOCARRAY(frameP->cb_blocks, dcty / 2);
@@ -672,7 +672,7 @@ Frame_AllocYCC(MpegFrame * const frameP) {
         /* already allocated */
     } else {
         unsigned int y;
-    
+
         DBG_PRINT(("ycc_calc:\n"));
         /*
          * first, allocate tons of memory
@@ -755,7 +755,7 @@ Frame_AllocHalf(MpegFrame * const frameP) {
  *
  *  allocate memory for decoded frame for the given frame, if required
  *  if makeReference == TRUE, then makes it reference frame
- * 
+ *
  * RETURNS: nothing
  *
  * SIDE EFFECTS:    none
@@ -781,14 +781,14 @@ Frame_AllocDecoded(MpegFrame * const frameP,
             MALLOCARRAY(frameP->decoded_y[y], Fsize_x);
             ERRCHK(frameP->decoded_y[y], "malloc");
         }
-        
+
         MALLOCARRAY(frameP->decoded_cr, Fsize_y / 2);
         ERRCHK(frameP->decoded_cr, "malloc");
         for (y = 0; y < (Fsize_y / 2); ++y) {
             MALLOCARRAY(frameP->decoded_cr[y], Fsize_x / 2);
             ERRCHK(frameP->decoded_cr[y], "malloc");
         }
-        
+
         MALLOCARRAY(frameP->decoded_cb, Fsize_y / 2);
         ERRCHK(frameP->decoded_cb, "malloc");
         for (y = 0; y < (Fsize_y / 2); ++y) {
@@ -810,7 +810,7 @@ Frame_AllocDecoded(MpegFrame * const frameP,
  *
  * Frame_Resize                  by James Boucher
  *                Boston University Multimedia Communications Lab
- *  
+ *
  *     This function takes the mf input frame, read in READFrame(),
  * and resizes all the input component arrays to the output
  * dimensions specified in the parameter file as OUT_SIZE.
@@ -828,11 +828,11 @@ Frame_Resize(MpegFrame * const omf,
     MpegFrame * frameAP;  /* intermediate frame */
 
     MALLOCVAR_NOFAIL(frameAP);
-    
+
     if (insize_x != outsize_x && insize_y != outsize_y) {
         Resize_Width(frameAP, mf, insize_x, insize_y, outsize_x);
         Resize_Height(omf, frameAP, outsize_x, insize_y, outsize_y);
-    } else 
+    } else
         if (insize_x ==outsize_x && insize_y != outsize_y) {
             Resize_Height(omf, mf, insize_x, insize_y, outsize_y);
         } else
@@ -843,3 +843,5 @@ Frame_Resize(MpegFrame * const omf,
 
     free(frameAP);
 }
+
+
diff --git a/converter/ppm/ppmtompeg/frametype.c b/converter/ppm/ppmtompeg/frametype.c
index 09afa403..debefcdc 100644
--- a/converter/ppm/ppmtompeg/frametype.c
+++ b/converter/ppm/ppmtompeg/frametype.c
@@ -13,7 +13,7 @@
  *	FType_FutureRef	returns the number of the future reference frame     *
  *	FType_PastRef	returns the number of the past reference frame	     *
  *									     *
- * 00.12.07 change malloc from frameTable to calloc to fix bug 
+ * 00.12.07 change malloc from frameTable to calloc to fix bug
  *===========================================================================*/
 
 /*
@@ -86,24 +86,24 @@ FType_Type(unsigned int const frameNum) {
 
     char retval;
 
-    if (use_cache) 
+    if (use_cache)
         return frameTable[frameNum].typ;
-  
+
     if (frameNum+1 == numFrames) {
         /* It's the last frame in the sequence.  If the pattern says it's
            a B, we convert it to I because a B frame makes no sense as the
            last frame of a sequence.
         */
-        if (patternedType == 'b') 
+        if (patternedType == 'b')
             retval = 'i';
-        else 
+        else
             retval = patternedType;
     } else {
         if (specificsOn) {
             static int lastI = -1;
             int newtype;
-      
-            if (lastI > frameNum) 
+
+            if (lastI > frameNum)
                 lastI = -1;
             newtype = SpecTypeLookup(frameNum);
             switch (newtype) {
@@ -119,13 +119,13 @@ FType_Type(unsigned int const frameNum) {
                 break;
             default:
                 if (lastI != -1) {
-                    unsigned int const pretendFrameNumber = 
+                    unsigned int const pretendFrameNumber =
                         (frameNum - lastI + firstI) % framePatternLen;
                     retval = framePattern[pretendFrameNumber];
-                } else 
+                } else
                     retval = patternedType;
             }
-        } else 
+        } else
             retval = patternedType;
     }
     return retval;
@@ -180,7 +180,7 @@ FType_PastRef(currFrameNum)
     } else {
       index = currFrameNum % framePatternLen;
       pastIndex = frameTable[index].prev->number;
-      
+
       return currFrameNum -
 	(((index-pastIndex)+framePatternLen) % framePatternLen);
     }
@@ -227,14 +227,14 @@ SetFramePattern(const char * const pattern) {
     firstI = -1;
     for (index = 0; index < len; index++) {
         switch( SIMPLE_ASCII_UPPER(pattern[index]) ) {
-        case 'I':	
+        case 'I':
             buf[index] = 'i';
             if (firstI == -1) firstI = index;
             break;
-        case 'P':	
-            buf[index] = 'p'; 
+        case 'P':
+            buf[index] = 'p';
             break;
-        case 'B':	
+        case 'B':
             buf[index] = 'b';
             break;
         default:
@@ -248,7 +248,7 @@ SetFramePattern(const char * const pattern) {
 
     framePattern = buf;
     framePatternLen = len;
-    
+
     /* Used to ComputeFrameTable(), but now must wait until param
        parsed. (STDIN or not)
     */
@@ -259,7 +259,7 @@ SetFramePattern(const char * const pattern) {
 void
 ComputeFrameTable(unsigned int const numFramesArg) {
 /*----------------------------------------------------------------------------
-  Compute a table of I, P, B frames to help in determining dependencie
+  Compute a table of I, P, B frames to help in determining dependency
 
   'numFrames' == 0 means number of frames is not known at this time.
 -----------------------------------------------------------------------------*/
@@ -339,7 +339,7 @@ ComputeFrameTable(unsigned int const numFramesArg) {
 	        break;
         }
     }
-    
+
     /* why? SRS */
     frameTable[table_size].number = framePatternLen;
     ptr = firstB;
@@ -362,3 +362,6 @@ ComputeFrameTable(unsigned int const numFramesArg) {
     if (numFrames)
         use_cache = TRUE;
 }
+
+
+
diff --git a/converter/ppm/ppmtompeg/jpeg.c b/converter/ppm/ppmtompeg/jpeg.c
index 24c9ae2d..4540f6f0 100644
--- a/converter/ppm/ppmtompeg/jpeg.c
+++ b/converter/ppm/ppmtompeg/jpeg.c
@@ -1,12 +1,12 @@
 /*===========================================================================*
- * jpeg.c                              
- *                                     
- *  procedures to deal with JPEG files 
- *                                     
- * EXPORTED PROCEDURES:                
- *  JMovie2JPEG                        
- *      ReadJPEG                      
- *                                    
+ * jpeg.c
+ *
+ *  procedures to deal with JPEG files
+ *
+ * EXPORTED PROCEDURES:
+ *  JMovie2JPEG
+ *      ReadJPEG
+ *
  *===========================================================================*/
 
 /* COPYRIGHT INFORMATION IS AT THE END OF THIS FILE */
@@ -20,7 +20,7 @@
 /* With the lossless jpeg patch applied to the Jpeg library
     (ftp://ftp.wizards.dupont.com/pub/ImageMagick/delegates/ljpeg-6b.tar.gz),
     the name of min_DCT_scaled_size changes to min_codec_data_unit,
-    for some reason.  With this macro, we change it back.  
+    for some reason.  With this macro, we change it back.
 */
 #define min_codec_data_unit min_DCT_scaled_size
 #include <jpeglib.h>
@@ -40,7 +40,7 @@
 /* make it happier.... */
 #undef DCTSIZE2
 
-/* jcopy_sample_rows() is an internal routine in the JPEG library, not 
+/* jcopy_sample_rows() is an internal routine in the JPEG library, not
    meant for use by us.  We should figure out what the official interface
    for this is and use it.  The following is copied out of jpegint.h, which
    is part of the JPEG library source code.
@@ -88,7 +88,7 @@ void
 JMovie2JPEG(const char * const infilename,
                 /* input filename string */
             const char * const obase,
-                /* output filename base string=>obase##.jpg */ 
+                /* output filename base string=>obase##.jpg */
             int          const start,
                 /* first frame to be extracted */
             int          const end
@@ -126,154 +126,154 @@ JMovie2JPEG(const char * const infilename,
        for the appending of the jpeg bitstream. It can be
        made smaller if you have a better idea of its expected size
     */
-    static unsigned char inbuffer[300000] = {    
-        0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46,  
+    static unsigned char inbuffer[300000] = {
+        0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46,
         0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01,
-        0x00, 0x01, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x11,  
+        0x00, 0x01, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x11,
         0x08, 0x00, 0xF0, 0x01, 0x40, 0x03, 0x01, 0x21,
-        0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xFF,  
+        0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xFF,
         0xDB, 0x00, 0x84, 0x00, 0x10, 0x0B, 0x0C, 0x0E,
-        0x0C, 0x0A, 0x10, 0x0E, 0x0D, 0x0E, 0x12,  
+        0x0C, 0x0A, 0x10, 0x0E, 0x0D, 0x0E, 0x12,
         0x11, 0x10, 0x13, 0x18, 0x28, 0x1A, 0x18, 0x16,
-        0x16, 0x18, 0x31, 0x23, 0x25, 0x1D, 0x28, 0x3A,  
+        0x16, 0x18, 0x31, 0x23, 0x25, 0x1D, 0x28, 0x3A,
         0x33, 0x3D, 0x3C, 0x39, 0x33, 0x38, 0x37, 0x40,
-        0x48, 0x5C, 0x4E, 0x40, 0x44, 0x57, 0x45, 0x37,  
+        0x48, 0x5C, 0x4E, 0x40, 0x44, 0x57, 0x45, 0x37,
         0x38, 0x50, 0x6D, 0x51, 0x57, 0x5F, 0x62, 0x67,
-        0x68, 0x67, 0x3E, 0x4D, 0x71, 0x79, 0x70, 0x64,  
+        0x68, 0x67, 0x3E, 0x4D, 0x71, 0x79, 0x70, 0x64,
         0x78, 0x5C, 0x65, 0x67, 0x63, 0x01, 0x11, 0x12,
-        0x12, 0x18, 0x15, 0x18, 0x2F, 0x1A, 0x1A, 0x2F,  
+        0x12, 0x18, 0x15, 0x18, 0x2F, 0x1A, 0x1A, 0x2F,
         0x63, 0x42, 0x38, 0x42, 0x63, 0x63, 0x63, 0x63,
-        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,  
-        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,  
-        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,  
-        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,  
-        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,  
+        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
         0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0xFF, 0xC4,
-        0x01, 0xA2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01,  
+        0x01, 0xA2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01,
         0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04,  
+        0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04,
         0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
-        0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04,  
+        0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04,
         0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01,
-        0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05,  
+        0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05,
         0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61,
-        0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1,  
+        0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1,
         0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1,
-        0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09,   
+        0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09,
         0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26,
-        0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37,  
+        0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37,
         0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47,
-        0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57,  
+        0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57,
         0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67,
-        0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77,  
+        0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77,
         0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87,
-        0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96,  
+        0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96,
         0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5,
-        0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4,  
+        0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4,
         0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3,
-        0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2,  
+        0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2,
         0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA,
-        0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8,  
+        0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8,
         0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6,
-        0xF7, 0xF8, 0xF9, 0xFA, 0x01, 0x00, 0x03, 0x01,  
+        0xF7, 0xF8, 0xF9, 0xFA, 0x01, 0x00, 0x03, 0x01,
         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,  
-        0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 
-        0x0A, 0x0B, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04,  
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
+        0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+        0x0A, 0x0B, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04,
         0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00,
-        0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11,  
+        0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11,
         0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51,
-        0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08,  
+        0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08,
         0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23,
-        0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1,   
+        0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1,
         0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17,
-        0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A,  
+        0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A,
         0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44,
-        0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54,  
+        0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54,
         0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64,
-        0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74,  
+        0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74,
         0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83,
-        0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92,  
+        0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92,
         0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A,
-        0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9,  
+        0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9,
         0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8,
-        0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,  
+        0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
         0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
-        0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5,  
+        0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5,
         0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4,
-        0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xDA,  
+        0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xDA,
         0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03,
-        0x11, 0x00, 0x3F, 0x00  
+        0x11, 0x00, 0x3F, 0x00
 
     };
-    
+
     if (start > end) {
         fprintf(stderr,"bad frame numbers\n");
         exit(1);
     }
-    
+
     /* open J_Movie */
     inFile = fopen(infilename, "rb");
     if (inFile == NULL) {
         perror (infilename);
         exit(1);
     }
-    
-    /* get file descriptor */    
+
+    /* get file descriptor */
     fd = fileno(inFile);
-    
+
     /* The following lines parse the jpeg_movie header and recover the */
-    /* relavant information */
+    /* relevant information */
 
     fseek(inFile, 8 * sizeof(char), 0);
-    
+
     if (fread(&ver_no, sizeof(int), 1, inFile) != 1) {
         perror("Error in reading version");
         exit(1);
-    }  
+    }
     if (ver_no != 2) {
         perror("Unrecognized version - Quantization tables may be wrong\n");
     }
     if (fread(&fps, sizeof(int), 1, inFile) != 1) {
         perror("Error in reading fps");
         exit(1);
-    }  
+    }
     if (fread (&no_frames, sizeof(int), 1, inFile) != 1) {
         perror("Error in reading no_frames");
         exit(1);
-    }  
+    }
 
     MALLOCARRAY(inoffsets, no_frames);
-    
+
     if (fread(&width, sizeof(int), 1, inFile) != 1) {
         perror("Error in reading width");
         exit(1);
-    }  
+    }
     /* set image width in JFIF header */
     inbuffer[27] = (char)(0xFF & (width >> 8));
     inbuffer[28] = (char)(0xFF & width);
- 
+
     if (fread(&height, sizeof(int), 1, inFile) != 1) {
         perror("Error in reading height");
         exit(1);
-    }  
+    }
     /* set image height in JFIF header */
     inbuffer[25] = (char)(0xFF & (height >> 8));
     inbuffer[26] = (char)(0xFF & height);
-    
+
     if (fread(&bandwidth, sizeof(int), 1, inFile) != 1) {
         perror("Error in reading bandwidth");
         exit(1);
-    }  
-    
+    }
+
     if (fread(&qfactor, sizeof(int), 1, inFile) != 1) {
         perror("Error in reading qfactor");
         exit(1);
-    }  
+    }
     /* The default quality factor = 100, therefore, if
        our quality factor does not equal 100 we must
        scale the quantization matrices in the JFIF header
-    */    
+    */
     /* Note values are clipped to a max of 255 */
     if (qfactor != 100) {
         for (Temp = 44; Temp < 108; ++Temp) {
@@ -283,13 +283,13 @@ JMovie2JPEG(const char * const infilename,
         for (Temp = 109; Temp < 173; ++Temp) {
             temp = (inbuffer[Temp]*qfactor)/100;
             inbuffer[Temp] = (char)((temp<255) ? temp : 255);
-        }    
+        }
     }
-  
+
     if (fread(&mapsize, sizeof(int), 1, inFile) != 1) {
         perror("Error in reading mapsize");
         exit(1);
-    }  
+    }
     if (fread (&image_offset, sizeof(int), 1, inFile) != 1) {
         perror("Error in reading image offset");
         exit(1);
@@ -298,32 +298,32 @@ JMovie2JPEG(const char * const infilename,
         perror("Error in reading audio tracks");
         exit(1);
     }
-    
+
     fread(junk,sizeof(int),1,inFile);
-    
+
     if (fread (&audiosize, sizeof(int), 1, inFile) != 1) {
         perror("Error in reading audiosize");
         exit(1);
     }
-    
+
     fseek (inFile, image_offset, 0);
-    
+
     last = MIN(end, no_frames-1);
 
     for (i = 0; i < no_frames; ++i)  {
         fread(&(inoffsets[i]), sizeof(int), 1, inFile);
     } /* Reads in the frame sizes into the array */
-    
+
     rewind(inFile);
 
-    /* Extract JFIF files from J_Movie */    
+    /* Extract JFIF files from J_Movie */
     for (i = start; i <= last; ++i) {
         size = inoffsets[i] - inoffsets[i-1]- 5;
-        lseek(fd, inoffsets[i-1], 0); 
+        lseek(fd, inoffsets[i-1], 0);
         read(fd, &(op_code), 1);
         while (op_code !=  0xffffffec) {
             read(fd,junk,audiosize);
-            read(fd, &(op_code), 1);  
+            read(fd, &(op_code), 1);
             size = size - audiosize ;
         } /* To skip the audio bytes in each frame */
         read(fd, jpeg_size, 4);
@@ -331,7 +331,7 @@ JMovie2JPEG(const char * const infilename,
         sprintf(ofname, "%s%d.jpg", obase, i);
         outFile = fopen(ofname, "wb");
         fwrite(inbuffer, (size+607), sizeof(char), outFile);
-        fclose(outFile);        
+        fclose(outFile);
     }
     free(inoffsets);
     fclose(inFile);
@@ -413,50 +413,50 @@ ReadJPEG(MpegFrame * const mf,
             jpeg_stdio_src(&cinfo, fp);
         }
     }
-  
+
     /* specify data source (eg, a file) */
-  
+
     jpeg_stdio_src(&cinfo, fp);
-  
+
     /* read file parameters with jpeg_read_header() */
-  
-  
+
+
     (void) jpeg_read_header(&cinfo, TRUE);
     /* We can ignore the return value from jpeg_read_header since
      *   (a) suspension is not possible with the stdio data source, and
      *   (b) we passed TRUE to reject a tables-only JPEG file as an error.
      */
-  
+
     /* set parameters for decompression */
     cinfo.raw_data_out = TRUE;
     cinfo.out_color_space = JCS_YCbCr;
-  
+
     /* calculate image output dimensions */
     jpeg_calc_output_dimensions(&cinfo);
     /* the above calculation will set these soon */
     /* for now we'll set them ourselves */
-    
+
     /* tell mpeg_encode the size of the JPEG Image*/
     Fsize_Note(mf->id,(int)(cinfo.image_width),(int)(cinfo.image_height));
-  
+
     /* Allocate memory for the raw YCbCr data to occupy*/
     Frame_AllocYCC(mf);      /*allocate space for mpeg frame*/
-  
+
     /* copy pointers to array structure- this make the following
        code more compact
     */
     orig[0] = mf->orig_y;
     orig[1] = mf->orig_cb;
     orig[2] = mf->orig_cr;
-  
+
     /* Note that we can use the info obtained from jpeg_read_header.
      */
-  
+
     /* Start decompressor */
-  
+
     jpeg_start_decompress(&cinfo);
-  
-  
+
+
     /* JSAMPLEs per row in output buffer  */
     /* collect component subsample values*/
     for (cp=0, compptr = cinfo.comp_info;
@@ -470,28 +470,28 @@ ReadJPEG(MpegFrame * const mf,
     max_h_samp = (temp_h<h_samp[2]) ? h_samp[2]:temp_h;
     temp_v = (v_samp[0]<v_samp[1]) ? v_samp[1] : v_samp[0];
     max_v_samp = (temp_v<v_samp[2]) ? v_samp[2]:temp_v;
-  
+
     /* Make an 8-row-high sample array that will go away when done
        with image
     */
     buffer_height = cinfo.max_v_samp_factor * minDctVScaledSize(cinfo);
-  
+
     for(cp=0,compptr = cinfo.comp_info;cp<cinfo.num_components;
         cp++,compptr++) {
         ncols[cp] = (JDIMENSION)((cinfo.image_width*compptr->h_samp_factor)/
                                  max_h_samp);
-    
+
         nrows[cp] = (JDIMENSION)((buffer_height*compptr->v_samp_factor)/
                                  max_v_samp);
-    
+
         scanarray[cp] = (*cinfo.mem->alloc_sarray)
             ((j_common_ptr) &cinfo, JPOOL_IMAGE, ncols[cp], nrows[cp]);
     }
-  
+
     /*  while (scan lines remain to be read)
            jpeg_read_scanlines(...);
     */
-  
+
     /* Here we use the library's state variable cinfo.output_scanline as the
      * loop counter, so that we don't have to keep track ourselves.
      */
@@ -525,29 +525,29 @@ ReadJPEG(MpegFrame * const mf,
             }
         } else
             pm_error("Invalid subsampling ratio");
-    
+
         /* transfer data from jpeg buffer to MPEG frame */
         /* calculate the row we wish to output into */
         for (ci = 0, compptr = cinfo.comp_info;
              ci < cinfo.num_components;
              ++ci, ++compptr) {
             current_row[ci] =((cinfo.output_scanline - buffer_height)*
-                              (v_samp[ci])/max_v_samp);  
-      
+                              (v_samp[ci])/max_v_samp);
+
             jcopy_sample_rows(scanarray[ci],0,(JSAMPARRAY)(orig[ci]),
                               current_row[ci],nrows[ci],ncols[ci]);
         }
-    }  
-  
+    }
+
     /* Step 7: Finish decompression */
-  
+
     (void) jpeg_finish_decompress(&cinfo);
     /* We can ignore the return value since suspension is not possible
      * with the stdio data source.
      */
-  
+
     /* Step 8: Release JPEG decompression object */
-  
+
     /*
     ** DO NOT release the cinfo struct if we are reading from stdin, this
     ** is because the cinfo struct contains the read buffer, and the read
@@ -572,7 +572,7 @@ ReadJPEG(MpegFrame * const mf,
        think that jpeg_destroy can do an error exit, but why assume
        anything...)
     */
-  
+
     /* At this point you may want to check to see whether any corrupt-data
      * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
      * If you prefer to treat corrupt data as a fatal error, override the
diff --git a/converter/ppm/ppmtompeg/mheaders.c b/converter/ppm/ppmtompeg/mheaders.c
index 4cfe49ac..98e1b063 100644
--- a/converter/ppm/ppmtompeg/mheaders.c
+++ b/converter/ppm/ppmtompeg/mheaders.c
@@ -39,7 +39,7 @@
  *  $Header: /n/picasso/project/mpeg/mpeg_dist/mpeg_encode/RCS/mheaders.c,v 1.15 1995/08/07 21:45:19 smoot Exp $
  *  $Log: mheaders.c,v $
  *  Revision 1.15  1995/08/07 21:45:19  smoot
- *  check for illegal MVs (shouldnt ever be called, but....)
+ *  check for illegal MVs (shouldn't ever be called, but....)
  *  fix bug which made us not weite Iframe Qscale changes
  *  warns if writing a size=0 mpeg
  *
@@ -746,7 +746,7 @@ Mhead_GenSequenceHeader(BitBucket *   const bbPtr,
     }
     Bitio_Write(bbPtr, pratio, 4);
 
-    /* Wrtie picture rate, negative values default to 30 fps. */
+    /* Write picture rate, negative values default to 30 fps. */
 
     if (pict_rate < 0) {
         fprintf(stderr, "PROGRAMMER ERROR:  pict_rate = %d\n", pict_rate);
diff --git a/converter/ppm/ppmtompeg/mpeg.c b/converter/ppm/ppmtompeg/mpeg.c
index dd0e0dbc..e67eec1e 100644
--- a/converter/ppm/ppmtompeg/mpeg.c
+++ b/converter/ppm/ppmtompeg/mpeg.c
@@ -91,7 +91,7 @@ static boolean  frameCountsUnknown;
 
 
 /*==================*
- * GLOBAL VARIABLES *   
+ * GLOBAL VARIABLES *
  *==================*/
 
 /* important -- don't initialize anything here */
@@ -142,14 +142,14 @@ ShowRemainingTime(boolean const childProcess) {
         /* nothing */;
     } else if ( numI + numP + numB == 0 ) {
         /* no time left */
-    } else if ( timeMask != 0 ) {   
+    } else if ( timeMask != 0 ) {
         /* haven't encoded all types yet */
     } else {
         static int  lastTime = 0;
         float   total;
         time_t  nowTime;
         float   secondsPerFrame;
-        
+
         time(&nowTime);
         secondsPerFrame = (nowTime-timeStart)/(float)framesOutput;
         total = secondsPerFrame*(float)(numI+numP+numB);
@@ -174,7 +174,7 @@ static void
 initTCTime(unsigned int const firstFrameNumber) {
 
     unsigned int frameNumber;
-    
+
     tc_hrs = 0; tc_min = 0; tc_sec = 0; tc_pict = 0; tc_extra = 0;
     for (frameNumber = 0; frameNumber < firstFrameNumber; ++frameNumber)
         IncrementTCTime();
@@ -201,13 +201,13 @@ IncrementTCTime() {
        otherwise, it is the number of extra 1/1001 frames we've passed by
 
        so far; for example, if fps = 24000/1001, then 24 frames = 24024/24000
-       seconds = 1 second + 24/24000 seconds = 1 + 1/1000 seconds; similary,
+       seconds = 1 second + 24/24000 seconds = 1 + 1/1000 seconds; similarly,
        if fps = 30000/1001, then 30 frames = 30030/30000 = 1 + 1/1000 seconds
        and if fps = 60000/1001, then 60 frames = 1 + 1/1000 seconds
 
        if fps = 24000/1001, then 1/1000 seconds = 24/1001 frames
        if fps = 30000/1001, then 1/1000 seconds = 30/1001 frames
-       if fps = 60000/1001, then 1/1000 seconds = 60/1001 frames     
+       if fps = 60000/1001, then 1/1000 seconds = 60/1001 frames
      */
 
     totalFramesSent++;
@@ -250,7 +250,7 @@ initializeRateControl(bool const wantUnderflowWarning,
         */
     }
 }
-    
+
 
 
 /*===========================================================================*
@@ -294,16 +294,16 @@ finishFrameOutput(MpegFrame * const frameP,
                   boolean     const childProcess,
                   boolean     const remoteIO) {
 
-    if ((referenceFrame == DECODED_FRAME) && 
+    if ((referenceFrame == DECODED_FRAME) &&
         childProcess && NonLocalRefFrame(frameP->id)) {
         if (remoteIO)
             SendDecodedFrame(frameP);
         else
             WriteDecodedFrame(frameP);
-            
+
         NotifyDecodeServerReady(frameP->id);
     }
-    
+
     if (separateFiles) {
         if (remoteIO)
             SendRemoteFrame(frameP->id, bbP);
@@ -314,7 +314,7 @@ finishFrameOutput(MpegFrame * const frameP,
     }
 }
 
-    
+
 
 
 static void
@@ -324,41 +324,41 @@ outputIFrame(MpegFrame * const frameP,
              int         const realEnd,
              MpegFrame * const pastRefFrameP,
              boolean     const separateFiles) {
-      
+
     /* only start a new GOP with I */
     /* don't start GOP if only doing frames */
     if (!separateFiles && currentGOP >= gopSize) {
-        boolean const closed = 
+        boolean const closed =
             (totalFramesSent == frameP->id || pastRefFrameP == NULL);
 
         static int num_gop = 0;
-    
+
         /* first, check to see if closed GOP */
-    
+
         /* new GOP */
-        if (num_gop != 0 && mult_seq_headers && 
+        if (num_gop != 0 && mult_seq_headers &&
             num_gop % mult_seq_headers == 0) {
             if (!realQuiet) {
-                fprintf(stdout, 
+                fprintf(stdout,
                         "Creating new Sequence before GOP %d\n", num_gop);
                 fflush(stdout);
             }
-      
+
             Mhead_GenSequenceHeader(
                 bbP, Fsize_x, Fsize_y,
                 /* pratio */    aspectRatio,
                 /* pict_rate */ frameRate, /* bit_rate */ bit_rate,
                 /* buf_size */  buf_size,  /* c_param_flag */ 1,
-                /* iq_matrix */ customQtable, 
+                /* iq_matrix */ customQtable,
                 /* niq_matrix */ customNIQtable,
                 /* ext_data */ NULL,  /* ext_data_size */ 0,
                 /* user_data */ NULL, /* user_data_size */ 0);
         }
-    
+
         if (!realQuiet)
             pm_message("Creating new GOP (closed = %s) before frame %d\n",
                        closed ? "YES" : "NO", frameP->id);
-    
+
         ++num_gop;
         Mhead_GenGOPHeader(bbP,  /* drop_frame_flag */ 0,
                            tc_hrs, tc_min, tc_sec, tc_pict,
@@ -371,13 +371,13 @@ outputIFrame(MpegFrame * const frameP,
         else
             SetGOPStartTime(pastRefFrameP->id + 1);
     }
-      
+
     if (frameP->id >= realStart && frameP->id <= realEnd)
         GenIFrame(bbP, frameP);
-      
+
     --numI;
     timeMask &= 0x6;
-      
+
     ++currentGOP;
     IncrementTCTime();
 }
@@ -396,7 +396,7 @@ outputPFrame(MpegFrame * const frameP,
 
     --numP;
     timeMask &= 0x5;
-    
+
     ++currentGOP;
     IncrementTCTime();
 }
@@ -464,7 +464,7 @@ getBFrame(int                  const frameNum,
         *bFramePP = bFrameP;
     } else {
         /* As the frame input is serial, we can't read the B frame now.
-           Rather, Caller has already read it and chained it to 
+           Rather, Caller has already read it and chained it to
            the previous reference frame.  So we get that copy now.
         */
         *bFramePP = pastRefFrameP->next;
@@ -510,15 +510,15 @@ processBFrames(MpegFrame *          const pastRefFrameP,
 
     assert(pastRefFrameP != NULL);
     assert(futureRefFrameP != NULL);
-    
-    for (frameNum = MAX(realStart, firstBFrameNum); 
-         frameNum < MIN(realEnd, futureRefFrameP->id); 
+
+    for (frameNum = MAX(realStart, firstBFrameNum);
+         frameNum < MIN(realEnd, futureRefFrameP->id);
          ++frameNum) {
 
         MpegFrame * bFrame;
         BitBucket * bbP;
 
-        getBFrame(frameNum, inputSourceP, pastRefFrameP, childProcess, 
+        getBFrame(frameNum, inputSourceP, pastRefFrameP, childProcess,
                   remoteIO,
                   &bFrame, IOtimeP, framesReadP);
 
@@ -554,7 +554,7 @@ processBFrames(MpegFrame *          const pastRefFrameP,
 
 
 static void
-processRefFrame(MpegFrame *    const frameP, 
+processRefFrame(MpegFrame *    const frameP,
                 BitBucket *    const wholeStreamBbP,
                 int            const realStart,
                 int            const realEnd,
@@ -574,18 +574,18 @@ processRefFrame(MpegFrame *    const frameP,
 -----------------------------------------------------------------------------*/
     if (frameP->id >= realStart && frameP->id <= realEnd) {
         bool const separateFiles = (wholeStreamBbP == NULL);
-  
+
         BitBucket * bbP;
-  
+
         if (separateFiles)
             bbP = bitioNew(outputFileName, frameP->id, remoteIO);
         else
             bbP = wholeStreamBbP;
-  
+
         /* first, output this reference frame */
         switch (frameP->type) {
         case TYPE_IFRAME:
-            outputIFrame(frameP, bbP, realStart, realEnd, pastRefFrameP, 
+            outputIFrame(frameP, bbP, realStart, realEnd, pastRefFrameP,
                          separateFiles);
             break;
         case TYPE_PFRAME:
@@ -595,10 +595,10 @@ processRefFrame(MpegFrame *    const frameP,
         default:
             pm_error("INTERNAL ERROR: non-reference frame passed to "
                      "ProcessRefFrame()");
-        }  
-        
+        }
+
         ++(*framesOutputP);
-        
+
         finishFrameOutput(frameP, bbP, separateFiles, referenceFrame,
                           childProcess, remoteIO);
     }
@@ -620,7 +620,7 @@ countFrames(unsigned int const firstFrame,
 -----------------------------------------------------------------------------*/
     unsigned int numI, numP, numB;
     unsigned int timeMask;
-            
+
     numI = 0; numP = 0; numB = 0;
     timeMask = 0;
     if (stdinUsed) {
@@ -663,7 +663,7 @@ readAndSaveFrame(struct inputSource * const inputSourceP,
    type 'frameType'.
 
    Increment *framesReadP.
-   
+
    Add the time it took to read it, in seconds, to *iotimeP.
 
    Iff we can't read because we hit end of file, return
@@ -672,11 +672,11 @@ readAndSaveFrame(struct inputSource * const inputSourceP,
     /* This really should be part of ReadNthFrame.  The frame should be chained
        to the input object, not the past reference frame.
     */
-       
+
     MpegFrame * p;
     MpegFrame * frameP;
     time_t ioTimeStart, ioTimeEnd;
-    
+
     time(&ioTimeStart);
 
     frameP = Frame_New(frameNumber, frameType);
@@ -687,15 +687,15 @@ readAndSaveFrame(struct inputSource * const inputSourceP,
         Frame_Free(frameP);
     else {
         ++(*framesReadP);
-    
+
         time(&ioTimeEnd);
         *ioTimeP += (ioTimeEnd - ioTimeStart);
 
-        /* Add the B frame to the end of the queue of B-frames 
+        /* Add the B frame to the end of the queue of B-frames
            for later encoding.
         */
         assert(pastRefFrameP != NULL);
-        
+
         p = pastRefFrameP;
         while (p->next != NULL)
             p = p->next;
@@ -726,7 +726,7 @@ doFirstFrameStuff(enum frameContext const context,
 -----------------------------------------------------------------------------*/
     *inputFrameBitsP = 24 * Fsize_x * Fsize_y;
     SetBlocksPerSlice();
-          
+
     if (context == CONTEXT_WHOLESTREAM) {
         int32 const bitstreamMode = getRateMode();
         char * userData;
@@ -742,11 +742,11 @@ doFirstFrameStuff(enum frameContext const context,
             bit_rate = -1;
             buf_size = -1;
         }
-        
+
         if (strlen(userDataFileName) != 0) {
             struct stat statbuf;
             FILE *fp;
-          
+
             stat(userDataFileName,&statbuf);
             userDataSize = statbuf.st_size;
             userData = malloc(userDataSize);
@@ -771,7 +771,7 @@ doFirstFrameStuff(enum frameContext const context,
         } else { /* Put in our UserData Header */
             const char * userDataString;
             time_t now;
-                    
+
             time(&now);
             pm_asprintf(&userDataString,"MPEG stream encoded by UCB Encoder "
                         "(mpeg_encode) v%s on %s.",
@@ -782,11 +782,11 @@ doFirstFrameStuff(enum frameContext const context,
         }
         Mhead_GenSequenceHeader(bbP, Fsize_x, Fsize_y,
                                 /* pratio */ aspectRatio,
-                                /* pict_rate */ frameRate, 
+                                /* pict_rate */ frameRate,
                                 /* bit_rate */ bit_rate,
                                 /* buf_size */ buf_size,
                                 /*c_param_flag */ 1,
-                                /* iq_matrix */ qtable, 
+                                /* iq_matrix */ qtable,
                                 /* niq_matrix */ niqtable,
                                 /* ext_data */ NULL,
                                 /* ext_data_size */ 0,
@@ -844,9 +844,9 @@ getPreviousFrame(unsigned int         const frameStart,
                      separateConversion, slaveConversion, inputConversion,
                      frameP, &endOfStream);
         assert(!endOfStream);  /* Because Stdin causes failure above */
-    }            
+    }
     ++(*framesReadP);
-    
+
     time(&ioTimeEnd);
     *ioTimeP += (ioTimeEnd-ioTimeStart);
 
@@ -858,7 +858,7 @@ getPreviousFrame(unsigned int         const frameStart,
 static void
 computeFrameRange(unsigned int         const frameStart,
                   unsigned int         const frameEnd,
-                  enum frameContext    const context, 
+                  enum frameContext    const context,
                   struct inputSource * const inputSourceP,
                   unsigned int *       const firstFrameP,
                   unsigned int *       const lastFrameP) {
@@ -881,13 +881,13 @@ computeFrameRange(unsigned int         const frameStart,
             *firstFrameP = frameStart;
 
         /* if last frame is B, need to read in P or I frame after it */
-        if ((FType_Type(frameEnd) == 'b') && 
+        if ((FType_Type(frameEnd) == 'b') &&
             (frameEnd != inputSourceP->numInputFiles-1)) {
             /* can't find the next reference frame interactively */
             if (inputSourceP->stdinUsed)
                 pm_error("Cannot encode frames from Standard Input "
                          "when last frame is a B-frame.");
-            
+
             *lastFrameP = FType_FutureRef(frameEnd);
         } else
             *lastFrameP = frameEnd;
@@ -930,11 +930,11 @@ getFrame(MpegFrame **         const framePP,
     time_t ioTimeStart, ioTimeEnd;
     MpegFrame * frameP;
     bool endOfStream;
-    
+
     time(&ioTimeStart);
 
     frameP = Frame_New(frameNumber, frameType);
-            
+
     if ((referenceFrame == DECODED_FRAME) &&
         ((frameNumber < realStart) || (frameNumber > realEnd)) ) {
         WaitForDecodedFrame(frameNumber);
@@ -952,13 +952,13 @@ getFrame(MpegFrame **         const framePP,
         ReadNthFrame(inputSourceP, frameNumber, remoteIO, childProcess,
                      separateConversion, slaveConversion, inputConversion,
                      frameP, &endOfStream);
-    
+
     if (endOfStream) {
         Frame_Free(frameP);
         *framePP = NULL;
     } else {
         ++(*framesReadP);
-            
+
         time(&ioTimeEnd);
         *ioTimeP += (ioTimeEnd - ioTimeStart);
 
@@ -988,9 +988,9 @@ handleBitRate(unsigned int const realEnd,
 static void
 doAFrame(unsigned int         const frameNumber,
          struct inputSource * const inputSourceP,
-         enum frameContext    const context, 
-         unsigned int         const frameStart, 
-         unsigned int         const frameEnd, 
+         enum frameContext    const context,
+         unsigned int         const frameStart,
+         unsigned int         const frameEnd,
          unsigned int         const realStart,
          unsigned int         const realEnd,
          bool                 const childProcess,
@@ -1017,7 +1017,7 @@ doAFrame(unsigned int         const frameNumber,
    output each frame to its own individual file instead.
 -----------------------------------------------------------------------------*/
     char const frameType = FType_Type(frameNumber);
-    
+
     *endOfStreamP = FALSE;  /* initial assumption */
 
     if (frameType == 'b') {
@@ -1026,44 +1026,44 @@ doAFrame(unsigned int         const frameNumber,
            just read it later.
         */
         *newPastRefFramePP = pastRefFrameP;
-        if (inputSourceP->stdinUsed) 
+        if (inputSourceP->stdinUsed)
             readAndSaveFrame(inputSourceP,
                              frameNumber, frameType, inputConversion,
                              pastRefFrameP, framesReadP, &IOtime,
                              endOfStreamP);
     } else {
         MpegFrame * frameP;
-        
+
         getFrame(&frameP, inputSourceP, frameNumber, frameType,
                  realStart, realEnd, referenceFrame, childProcess,
                  remoteIO,
                  separateConversion, slaveConversion, inputConversion,
                  framesReadP, &IOtime);
-        
+
         if (frameP) {
             *endOfStreamP = FALSE;
 
             if (!*firstFrameDoneP) {
                 doFirstFrameStuff(context, userDataFileName, wholeStreamBbP,
                                   Fsize_x, Fsize_y, aspectRatio,
-                                  frameRate, qtable, niqtable, 
+                                  frameRate, qtable, niqtable,
                                   inputFrameBitsP);
-            
+
                 *firstFrameDoneP = TRUE;
             }
             processRefFrame(frameP, wholeStreamBbP, frameStart, frameEnd,
-                            pastRefFrameP, childProcess, outputFileName, 
+                            pastRefFrameP, childProcess, outputFileName,
                             framesReadP, framesOutputP);
-                
+
             if (pastRefFrameP) {
                 processBFrames(pastRefFrameP, frameP, realStart, realEnd,
-                               inputSourceP, remoteIO, childProcess, 
+                               inputSourceP, remoteIO, childProcess,
                                &IOtime, wholeStreamBbP, outputFileName,
                                framesReadP, framesOutputP, &currentGOP);
             }
             if (pastRefFrameP != NULL)
                 Frame_Free(pastRefFrameP);
-        
+
             *newPastRefFramePP = frameP;
         } else
             *endOfStreamP = TRUE;
@@ -1074,13 +1074,13 @@ doAFrame(unsigned int         const frameNumber,
 
 void
 GenMPEGStream(struct inputSource * const inputSourceP,
-              enum frameContext    const context, 
-              unsigned int         const frameStart, 
-              unsigned int         const frameEnd, 
-              int32                const qtable[], 
-              int32                const niqtable[], 
+              enum frameContext    const context,
+              unsigned int         const frameStart,
+              unsigned int         const frameEnd,
+              int32                const qtable[],
+              int32                const niqtable[],
               bool                 const childProcess,
-              FILE *               const ofP, 
+              FILE *               const ofP,
               const char *         const outputFileName,
               bool                 const wantVbvUnderflowWarning,
               bool                 const wantVbvOverflowWarning,
@@ -1129,7 +1129,7 @@ GenMPEGStream(struct inputSource * const inputSourceP,
                  "(%u frames)", frameEnd, inputSourceP->numInputFiles);
 
     if (context == CONTEXT_WHOLESTREAM &&
-        !inputSourceP->stdinUsed && 
+        !inputSourceP->stdinUsed &&
         FType_Type(inputSourceP->numInputFiles-1) == 'b')
         pm_message("WARNING:  "
                    "One or more B-frames at end will not be encoded.  "
@@ -1188,27 +1188,27 @@ GenMPEGStream(struct inputSource * const inputSourceP,
          frameNumber <= lastFrame && !endOfStream;
          ++frameNumber) {
 
-        doAFrame(frameNumber, inputSourceP, context, 
+        doAFrame(frameNumber, inputSourceP, context,
                  frameStart, frameEnd, realStart, realEnd,
                  childProcess, outputFileName,
                  pastRefFrameP, &pastRefFrameP,
                  &framesRead, &framesOutput, &firstFrameDone, streamBbP,
                  inputFrameBitsP, &endOfStream);
     }
-    
+
     if (pastRefFrameP != NULL)
         Frame_Free(pastRefFrameP);
-    
+
     /* SEQUENCE END CODE */
     if (context == CONTEXT_WHOLESTREAM)
         Mhead_GenSequenceEnder(streamBbP);
-    
+
     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 
-           to somthing (anything).  
+           used below, so we need to make sure it's properly initialized
+           to something (anything).
         */
         numBits = 1;
     }
@@ -1272,9 +1272,9 @@ SetGOPSize(size)
  *
  *===========================================================================*/
 void
-PrintStartStats(time_t               const startTime, 
+PrintStartStats(time_t               const startTime,
                 bool                 const specificFrames,
-                unsigned int         const firstFrame, 
+                unsigned int         const firstFrame,
                 unsigned int         const lastFrame,
                 struct inputSource * const inputSourceP) {
 
@@ -1296,7 +1296,7 @@ PrintStartStats(time_t               const startTime,
             fprintf(stdout, "\n\n");
         }
     }
-    
+
     for (i = 0; i < 2; ++i) {
         if ( ( i == 0 ) && (! realQuiet) ) {
             fpointer = stdout;
@@ -1322,15 +1322,15 @@ PrintStartStats(time_t               const startTime,
             fprintf(fpointer, "INPUT FROM FILES:\n");
 
             GetNthInputFileName(inputSourceP, 0, &inputFileName);
-            fprintf(fpointer, "FIRST FILE:  %s/%s\n", 
+            fprintf(fpointer, "FIRST FILE:  %s/%s\n",
                     currentPath, inputFileName);
             pm_strfree(inputFileName);
-            GetNthInputFileName(inputSourceP, inputSourceP->numInputFiles-1, 
+            GetNthInputFileName(inputSourceP, inputSourceP->numInputFiles-1,
                                 &inputFileName);
-            fprintf(fpointer, "LAST FILE:  %s/%s\n", 
+            fprintf(fpointer, "LAST FILE:  %s/%s\n",
                     currentPath, inputFileName);
             pm_strfree(inputFileName);
-        }    
+        }
         fprintf(fpointer, "OUTPUT:  %s\n", outputFileName);
 
         if (resizeFrame)
@@ -1341,15 +1341,15 @@ PrintStartStats(time_t               const startTime,
         fprintf(fpointer, "SLICES PER FRAME:  %d\n", slicesPerFrame);
         if (searchRangeP==searchRangeB)
             fprintf(fpointer, "RANGE:  +/-%d\n", searchRangeP/2);
-        else fprintf(fpointer, "RANGES:  +/-%d %d\n", 
+        else fprintf(fpointer, "RANGES:  +/-%d %d\n",
                      searchRangeP/2,searchRangeB/2);
-        fprintf(fpointer, "PIXEL SEARCH:  %s\n", 
+        fprintf(fpointer, "PIXEL SEARCH:  %s\n",
                 pixelFullSearch ? "FULL" : "HALF");
         fprintf(fpointer, "PSEARCH:  %s\n", PSearchName());
         fprintf(fpointer, "BSEARCH:  %s\n", BSearchName());
-        fprintf(fpointer, "QSCALE:  %d %d %d\n", qscaleI, 
+        fprintf(fpointer, "QSCALE:  %d %d %d\n", qscaleI,
                 GetPQScale(), GetBQScale());
-        if (specificsOn) 
+        if (specificsOn)
             fprintf(fpointer, "(Except as modified by Specifics file)\n");
         if ( referenceFrame == DECODED_FRAME ) {
             fprintf(fpointer, "REFERENCE FRAME:  DECODED\n");
@@ -1386,22 +1386,22 @@ NonLocalRefFrame(int const id) {
     boolean retval;
 
     int const lastIPid = FType_PastRef(id);
-    
+
     /* might be accessed by B-frame */
-    
+
     if (lastIPid+1 < realStart)
         retval = TRUE;
     else {
         unsigned int const nextIPid = FType_FutureRef(id);
-        
+
         /* if B-frame is out of range, then current frame can be
-           ref'd by it 
+           ref'd by it
         */
-        
+
         /* might be accessed by B-frame */
         if (nextIPid > realEnd+1)
             retval = TRUE;
-        
+
         /* might be accessed by P-frame */
         if ((nextIPid > realEnd) && (FType_Type(nextIPid) == 'p'))
             retval = TRUE;
@@ -1410,7 +1410,7 @@ NonLocalRefFrame(int const id) {
 }
 
 
- 
+
 /*===========================================================================*
  *
  * SetFrameRate
@@ -1508,9 +1508,9 @@ ComputeDHMSTime(someTime, timeText)
 
 
 void
-ComputeGOPFrames(int            const whichGOP, 
-                 unsigned int * const firstFrameP, 
-                 unsigned int * const lastFrameP, 
+ComputeGOPFrames(int            const whichGOP,
+                 unsigned int * const firstFrameP,
+                 unsigned int * const lastFrameP,
                  unsigned int   const numFrames) {
 /*----------------------------------------------------------------------------
    Figure out which frames are in GOP number 'whichGOP'.
@@ -1537,7 +1537,7 @@ ComputeGOPFrames(int            const whichGOP,
         if (gopNum == whichGOP) {
             foundGop = TRUE;
             firstFrame = frameNum;
-        }           
+        }
 
         /* go past one gop */
         /* must go past at least one frame */
@@ -1551,7 +1551,7 @@ ComputeGOPFrames(int            const whichGOP,
                 ++frameNum;
                 ++passedB;
             }
-        } while ((frameNum < numFrames) && 
+        } while ((frameNum < numFrames) &&
                  ((FType_Type(frameNum) != 'i') || (currGOP < gopSize)));
 
         currGOP -= gopSize;
@@ -1583,7 +1583,7 @@ doEndStats(FILE *       const fpointer,
 
     fprintf(fpointer, "TIME COMPLETED:  %s", ctime(&endTime));
     fprintf(fpointer, "%s\n\n", timeText);
-        
+
     ShowIFrameSummary(inputFrameBits, totalBits, fpointer);
     ShowPFrameSummary(inputFrameBits, totalBits, fpointer);
     ShowBFrameSummary(inputFrameBits, totalBits, fpointer);
@@ -1595,7 +1595,7 @@ doEndStats(FILE *       const fpointer,
     if (diffTime > 0) {
         fprintf(fpointer, "Total Frames Per Sec Elapsed:  %f (%ld mps)\n",
                 (float)framesOutput/(float)diffTime,
-                (long)((float)framesOutput * 
+                (long)((float)framesOutput *
                        (float)inputFrameBits /
                        (256.0*24.0*(float)diffTime)));
     } else {
@@ -1613,7 +1613,7 @@ doEndStats(FILE *       const fpointer,
             frameRateRounded, frameRateRounded*totalBits/framesOutput);
     fprintf(fpointer, "MPEG file created in :  %s\n", outputFileName);
     fprintf(fpointer, "\n\n");
-        
+
     if ( computeMVHist ) {
         ShowPMVHistogram(fpointer);
         ShowBBMVHistogram(fpointer);
@@ -1637,7 +1637,7 @@ doEndStats(FILE *       const fpointer,
 void
 PrintEndStats(time_t       const startTime,
               time_t       const endTime,
-              unsigned int const inputFrameBits, 
+              unsigned int const inputFrameBits,
               unsigned int const totalBits) {
 
     float   totalCPU;
@@ -1652,7 +1652,7 @@ PrintEndStats(time_t       const startTime,
         doEndStats(stdout, startTime, endTime, inputFrameBits,
                    totalBits, totalCPU);
     }
-    
+
     if (statFile) {
         doEndStats(statFile, startTime, endTime, inputFrameBits,
                    totalBits, totalCPU);
@@ -1664,7 +1664,7 @@ PrintEndStats(time_t       const startTime,
 
 
 void
-ReadDecodedRefFrame(MpegFrame *  const frameP, 
+ReadDecodedRefFrame(MpegFrame *  const frameP,
                     unsigned int const frameNumber) {
 
     FILE    *fpointer;
@@ -1689,7 +1689,7 @@ ReadDecodedRefFrame(MpegFrame *  const frameP,
         }}
 
     Frame_AllocDecoded(frameP, TRUE);
-    
+
     for ( y = 0; y < height; y++ ) {
         size_t bytesRead;
 
@@ -1697,7 +1697,7 @@ ReadDecodedRefFrame(MpegFrame *  const frameP,
         if (bytesRead != width)
             pm_error("Could not read enough bytes from '%s;", fileName);
     }
-    
+
     for (y = 0; y < (height >> 1); y++) {           /* U */
         size_t const bytesToRead = width/2;
         size_t bytesRead;
@@ -1706,7 +1706,7 @@ ReadDecodedRefFrame(MpegFrame *  const frameP,
         if (bytesRead != bytesToRead)
             pm_message("Could not read enough bytes from '%s'", fileName);
     }
-    
+
     for (y = 0; y < (height >> 1); y++) {           /* V */
         size_t const bytesToRead = width/2;
         size_t bytesRead;
@@ -1724,7 +1724,7 @@ static void
 OpenBitRateFile() {
     bitRateFile = fopen(bitRateFileName, "w");
     if ( bitRateFile == NULL ) {
-        pm_message("ERROR:  Could not open bit rate file:  '%s'", 
+        pm_message("ERROR:  Could not open bit rate file:  '%s'",
                    bitRateFileName);
         showBitRatePerFrame = FALSE;
     }
@@ -1736,3 +1736,6 @@ static void
 CloseBitRateFile() {
     fclose(bitRateFile);
 }
+
+
+
diff --git a/converter/ppm/ppmtompeg/opts.c b/converter/ppm/ppmtompeg/opts.c
index 553e29d0..6f5f9816 100644
--- a/converter/ppm/ppmtompeg/opts.c
+++ b/converter/ppm/ppmtompeg/opts.c
@@ -1,29 +1,29 @@
 /*===========================================================================*
- * opts.c								     *
- *									     *
+ * opts.c                                                                    *
+ *                                                                           *
  *      Special C code to handle TUNEing options                             *
- *									     *
- * EXPORTED PROCEDURES:							     *
+ *                                                                           *
+ * EXPORTED PROCEDURES:                                                      *
  *      Tune_Init                                                            *
  *      CollectQuantStats                                                    *
- *									     *
+ *                                                                           *
  *===========================================================================*/
 
 
 /*
  * 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
@@ -95,9 +95,9 @@ boolean BSkipBlocks = TRUE;
  *
  * SkipSpacesTabs
  *
- *	skip all spaces and tabs
+ *      skip all spaces and tabs
  *
- * RETURNS:	point to next character not a space or tab
+ * RETURNS:     point to next character not a space or tab
  *
  * SIDE EFFECTS:    none
  *
@@ -120,12 +120,12 @@ SkipSpacesTabs(const char * const start) {
  *
  *     Setup variables to collect statistics on quantization values
  *
- * RETURNS:	nothing
+ * RETURNS:     nothing
  *
  * SIDE EFFECTS:    sets collect_quant and collect_quant_fp
  *
  *===========================================================================*/
-static void 
+static void
 SetupCollectQuantStats(const char * const charPtr)
 {
   char fname[256];
@@ -164,23 +164,23 @@ SetupCollectQuantStats(const char * const charPtr)
  *
  *     Do a transform on small lum values
  *
- * RETURNS:	nothing
+ * RETURNS:     nothing
  *
  * SIDE EFFECTS:    sets kill_dim, kill_dim_break, kill_dim_end
  *
  *===========================================================================*/
-static void 
+static void
 SetupKillDimAreas(const char * const charPtr)
 {
   int items_scanned;
 
   kill_dim = TRUE;
-  items_scanned = sscanf(charPtr, "%d %d %f", 
-			 &kill_dim_break, &kill_dim_end, &kill_dim_slope);
+  items_scanned = sscanf(charPtr, "%d %d %f",
+                         &kill_dim_break, &kill_dim_end, &kill_dim_slope);
   if (items_scanned != 3) {
     kill_dim_slope = 0.25;
-    items_scanned = sscanf(charPtr, "%d %d", 
-			   &kill_dim_break, &kill_dim_end);
+    items_scanned = sscanf(charPtr, "%d %d",
+                           &kill_dim_break, &kill_dim_end);
     if (items_scanned != 2) {
       /* Use defaults */
       kill_dim_break = 20;
@@ -206,12 +206,12 @@ SetupKillDimAreas(const char * const charPtr)
  *
  *     Setup encoder to squash small changes in Y or Cr/Cb values
  *
- * RETURNS:	nothing
+ * RETURNS:     nothing
  *
- * SIDE EFFECTS:    sets squash_max_differences SquashMaxLum SquashMaxChr 
+ * SIDE EFFECTS:    sets squash_max_differences SquashMaxLum SquashMaxChr
  *
  *===========================================================================*/
-static void 
+static void
 SetupSquashSmall(const char * const charPtr)
 {
   squash_small_differences = TRUE;
@@ -229,13 +229,13 @@ SetupSquashSmall(const char * const charPtr)
  *
  *     Setup encoder to use DCT for rate-distortion estimat ein Psearches
  *
- * RETURNS:	nothing
+ * RETURNS:     nothing
  *
  * SIDE EFFECTS:    sets SearchCompareMode and
  *                        can change LocalDCTRateScale, LocalDCTDistortScale
  *
  *===========================================================================*/
-static void 
+static void
 SetupLocalDCT(const char * const charPtr)
 {
   int num_scales=0;
@@ -260,12 +260,12 @@ SetupLocalDCT(const char * const charPtr)
  *
  *     Setup encoder to find distribution for I-frames, and use for -snr
  *
- * RETURNS:	nothing
+ * RETURNS:     nothing
  *
  * SIDE EFFECTS:    sets DoLaplace, L1, L2, and Lambdas
  *
  *===========================================================================*/
-static void 
+static void
 SetupLaplace()
 {
   int i;
@@ -339,18 +339,18 @@ SetupWriteDistortions(const char * const charPtr)
     default:
       fprintf(stderr, "Unknown TUNE parameter setting format %s\n", cp);
     }}
-}  
+}
 
 /*=====================*
  * EXPORTED PROCEDURES *
  *=====================*/
 
-void 
+void
 CalcLambdas(void) {
 
   int i,j,n;
   double var;
-  
+
   n = LaplaceNum;
   for (i = 0;   i < 3;  i++) {
     for (j = 0;  j < 64;  j++) {
@@ -365,10 +365,10 @@ CalcLambdas(void) {
  *
  * Mpost_UnQuantZigBlockLaplace
  *
- *	unquantize and zig-zag (decode) a single block, using the distrib to get vals
+ *      unquantize and zig-zag (decode) a single block, using the distrib to get vals
  *      Iblocks only now
  *
- * RETURNS:	nothing
+ * RETURNS:     nothing
  *
  * SIDE EFFECTS:    none
  *
@@ -381,22 +381,22 @@ Mpost_UnQuantZigBlockLaplace(in, out, qscale, iblock)
     boolean iblock;
 {
     register int index;
-    int	    position;
-    register int	    qentry;
-    int	    level, coeff;
+    int     position;
+    register int            qentry;
+    int     level, coeff;
     double low, high;
     double mid,lam;
 
     /* qtable[0] must be 8 */
     out[0][0] = (int16)(in[0] * 8);
-    
+
     for ( index = 1;  index < DCTSIZE_SQ;  index++ ) {
       position = ZAG[index];
       level = in[index];
-      
+
       if (level == 0) {
-	((int16 *)out)[position] = 0;
-	continue;
+        ((int16 *)out)[position] = 0;
+        continue;
       }
       qentry = qtable[position] * qscale;
       coeff = (level*qentry)/8;
@@ -406,25 +406,25 @@ Mpost_UnQuantZigBlockLaplace(in, out, qscale, iblock)
       mid = (1.0/lam) * log(0.5*(exp(-lam*low)+exp(-lam*high)));
       mid = ABS(mid);
       if (mid - floor(mid) > .4999) {
-	mid = ceil(mid);
+        mid = ceil(mid);
       } else {
-	mid = floor(mid);
+        mid = floor(mid);
       }
       if (level<0) {mid = -mid;}
 /*printf("(%2.1lf-%2.1lf): old: %d vs %d\n",low,high,coeff,(int) mid);*/
       coeff = mid;
       if ( (coeff & 1) == 0 ) {
-	if ( coeff < 0 ) {
-	  coeff++;
-	} else if ( coeff > 0 ) {
-	  coeff--;
-	}
+        if ( coeff < 0 ) {
+          coeff++;
+        } else if ( coeff > 0 ) {
+          coeff--;
+        }
       }
       ((int16 *)out)[position] = coeff;
     }
 }
 
-int 
+int
 mse(Block blk1, Block blk2)
 {
   register int index, error, tmp;
@@ -449,7 +449,7 @@ mse(Block blk1, Block blk2)
  *
  *     Do any setup needed before coding stream
  *
- * RETURNS:	nothing
+ * RETURNS:     nothing
  *
  * SIDE EFFECTS:  varies
  *
@@ -458,7 +458,7 @@ void Tune_Init()
 {
   int i;
 
-  /* Just check for each, and do whats needed */
+  /* Just check for each, and do what's needed */
   if (collect_quant) {
     if (!pureDCT) {
       pureDCT = TRUE;
@@ -467,14 +467,14 @@ void Tune_Init()
     }
     fprintf(collect_quant_fp, "# %s\n", outputFileName);
     fprintf(collect_quant_fp, "#");
-    for (i=0; i<64; i++) 
+    for (i=0; i<64; i++)
       fprintf(collect_quant_fp, " %d", qtable[i]);
     fprintf(collect_quant_fp, "\n#");
-    for (i=0; i<64; i++) 
+    for (i=0; i<64; i++)
       fprintf(collect_quant_fp, " %d", niqtable[i]);
-    fprintf(collect_quant_fp, "\n# %d %d %d\n\n", 
-	    GetIQScale(), GetPQScale(), GetBQScale());
-    
+    fprintf(collect_quant_fp, "\n# %d %d %d\n\n",
+            GetIQScale(), GetPQScale(), GetBQScale());
+
   }
 
   if (DoLaplace) {
@@ -486,7 +486,7 @@ void Tune_Init()
     decodeRefFrames = TRUE;
     printSNR = TRUE;
   }
-    
+
 }
 
 /*===========================================================================*
@@ -495,7 +495,7 @@ void Tune_Init()
  *
  *     Handle the strings following TUNE
  *
- * RETURNS:	nothing
+ * RETURNS:     nothing
  *
  * SIDE EFFECTS:  varies
  *
@@ -503,7 +503,7 @@ void Tune_Init()
 void ParseTuneParam(const char * const charPtr)
 {
   switch (ASCII_TOUPPER(*charPtr)) {
-  case 'B': 
+  case 'B':
     if (1 != sscanf(charPtr+2, "%d", &block_bound)) {
       fprintf(stderr, "Invalid tuning parameter (b) in parameter file.\n");
     }
diff --git a/converter/ppm/ppmtompeg/parallel.c b/converter/ppm/ppmtompeg/parallel.c
index e3bcec1a..0fe635ed 100644
--- a/converter/ppm/ppmtompeg/parallel.c
+++ b/converter/ppm/ppmtompeg/parallel.c
@@ -1,8 +1,8 @@
 /*===========================================================================*
- * parallel.c              
- *                         
- *  Procedures to make encoder run in parallel   
- *                             
+ * parallel.c
+ *
+ *  Procedures to make encoder run in parallel
+ *
  *===========================================================================*/
 
 /* COPYRIGHT INFORMATION IS AT THE END OF THIS FILE */
@@ -13,8 +13,8 @@
  *==============*/
 
 #define _XOPEN_SOURCE 500 /* Make sure stdio.h contains pclose() */
-/* _ALL_SOURCE is needed on AIX to make the C library include the 
-   socket services (e.g. define struct sockaddr) 
+/* _ALL_SOURCE is needed on AIX to make the C library include the
+   socket services (e.g. define struct sockaddr)
 
    Note that AIX standards.h actually sets feature declaration macros such
    as _XOPEN_SOURCE, unless they are already set.
@@ -93,7 +93,8 @@ struct scheduler {
  * CONSTANTS        *
  *==================*/
 
-#define TERMINATE_PID_SIGNAL    SIGTERM  /* signal used to terminate forked childs */
+#define TERMINATE_PID_SIGNAL    SIGTERM
+  /* signal used to terminate forked children */
 #ifndef MAXARGS
 #define MAXARGS     1024   /* Max Number of arguments in safe_fork command */
 #endif
@@ -187,8 +188,8 @@ errorExit(const char format[], ...) {
 
 
 static void
-TransmitPortNum(const char * const hostName, 
-                int          const portNum, 
+TransmitPortNum(const char * const hostName,
+                int          const portNum,
                 int          const newPortNum) {
 /*----------------------------------------------------------------------------
    Transmit the port number 'newPortNum' to the master on port 'portNum'
@@ -196,15 +197,15 @@ TransmitPortNum(const char * const hostName,
 -----------------------------------------------------------------------------*/
     int clientSocket;
     const char * error;
-    
+
     ConnectToSocket(hostName, portNum, &hostEntry, &clientSocket, &error);
-    
+
     if (error)
         errorExit("Can't connect in order to transmit port number.  %s",
                   error);
 
     WriteInt(clientSocket, newPortNum);
-    
+
     close(clientSocket);
 }
 
@@ -215,19 +216,19 @@ readYUVDecoded(int          const socketFd,
                unsigned int const Fsize_x,
                unsigned int const Fsize_y,
                MpegFrame *  const frameP) {
-    
+
     unsigned int y;
-    
+
     for (y = 0; y < Fsize_y; ++y)         /* Y */
-        ReadBytes(socketFd, 
+        ReadBytes(socketFd,
                   (unsigned char *)frameP->decoded_y[y], Fsize_x);
-    
+
     for (y = 0; y < (Fsize_y >> 1); ++y)  /* U */
-        ReadBytes(socketFd, 
+        ReadBytes(socketFd,
                   (unsigned char *)frameP->decoded_cb[y], (Fsize_x >> 1));
-    
+
     for (y = 0; y < (Fsize_y >> 1); ++y)  /* V */
-        ReadBytes(socketFd, 
+        ReadBytes(socketFd,
                   (unsigned char *)frameP->decoded_cr[y], (Fsize_x >> 1));
 }
 
@@ -238,19 +239,19 @@ writeYUVDecoded(int          const socketFd,
                 unsigned int const Fsize_x,
                 unsigned int const Fsize_y,
                 MpegFrame *  const frameP) {
-    
+
     unsigned int y;
-    
+
     for (y = 0; y < Fsize_y; ++y)         /* Y */
-        WriteBytes(socketFd, 
+        WriteBytes(socketFd,
                   (unsigned char *)frameP->decoded_y[y], Fsize_x);
-    
+
     for (y = 0; y < (Fsize_y >> 1); ++y)  /* U */
-        WriteBytes(socketFd, 
+        WriteBytes(socketFd,
                    (unsigned char *)frameP->decoded_cb[y], (Fsize_x >> 1));
-    
+
     for (y = 0; y < (Fsize_y >> 1); ++y)  /* V */
-        WriteBytes(socketFd, 
+        WriteBytes(socketFd,
                    (unsigned char *)frameP->decoded_cr[y], (Fsize_x >> 1));
 }
 
@@ -261,19 +262,19 @@ writeYUVOrig(int          const socketFd,
              unsigned int const Fsize_x,
              unsigned int const Fsize_y,
              MpegFrame *  const frameP) {
-    
+
     unsigned int y;
-    
+
     for (y = 0; y < Fsize_y; ++y)         /* Y */
-        WriteBytes(socketFd, 
+        WriteBytes(socketFd,
                   (unsigned char *)frameP->orig_y[y], Fsize_x);
-    
+
     for (y = 0; y < (Fsize_y >> 1); ++y)  /* U */
-        WriteBytes(socketFd, 
+        WriteBytes(socketFd,
                    (unsigned char *)frameP->orig_cb[y], (Fsize_x >> 1));
-    
+
     for (y = 0; y < (Fsize_y >> 1); ++y)  /* V */
-        WriteBytes(socketFd, 
+        WriteBytes(socketFd,
                    (unsigned char *)frameP->orig_cr[y], (Fsize_x >> 1));
 }
 
@@ -284,19 +285,19 @@ readYUVOrig(int          const socketFd,
             unsigned int const Fsize_x,
             unsigned int const Fsize_y,
             MpegFrame *  const frameP) {
-    
+
     unsigned int y;
-    
+
     for (y = 0; y < Fsize_y; ++y)         /* Y */
-        ReadBytes(socketFd, 
+        ReadBytes(socketFd,
                   (unsigned char *)frameP->orig_y[y], Fsize_x);
-    
+
     for (y = 0; y < (Fsize_y >> 1); ++y)  /* U */
-        ReadBytes(socketFd, 
+        ReadBytes(socketFd,
                   (unsigned char *)frameP->orig_cb[y], (Fsize_x >> 1));
-    
+
     for (y = 0; y < (Fsize_y >> 1); ++y)  /* V */
-        ReadBytes(socketFd, 
+        ReadBytes(socketFd,
                   (unsigned char *)frameP->orig_cr[y], (Fsize_x >> 1));
 }
 
@@ -340,20 +341,20 @@ NotifyDecodeServerReady(int const id) {
     int   clientSocket;
     time_t  tempTimeStart, tempTimeEnd;
     const char * error;
-    
+
     time(&tempTimeStart);
-    
+
     ConnectToSocket(IOhostName, decodePortNumber, &hostEntry, &clientSocket,
                     &error);
-    
+
     if (error)
         errorExit("CHILD: Can't connect to decode server to tell it a frame "
                 "is ready.  %s", error);
-    
+
     WriteInt(clientSocket, id);
-    
+
     close(clientSocket);
-    
+
     time(&tempTimeEnd);
     IOtime += (tempTimeEnd-tempTimeStart);
 }
@@ -461,23 +462,23 @@ SendDecodedFrame(MpegFrame * const frameP) {
    Send frame *frameP to the decode server.
 -----------------------------------------------------------------------------*/
     int const negativeTwo = -2;
-    
+
     int clientSocket;
     const char * error;
-    
+
     /* send to IOServer */
     ConnectToSocket(IOhostName, ioPortNumber, &hostEntry,
                     &clientSocket, &error);
     if (error)
         errorExit("CHILD: Can't connect to decode server to "
                   "give it a decoded frame.  %s", error);
-    
+
     WriteInt(clientSocket, negativeTwo);
-    
+
     WriteInt(clientSocket, frameP->id);
 
     writeYUVDecoded(clientSocket, Fsize_x, Fsize_y, frameP);
-    
+
     close(clientSocket);
 }
 
@@ -490,11 +491,11 @@ SendDecodedFrame(MpegFrame * const frameP) {
  *
  * RETURNS: nothing
  *
- * SIDE EFFECTS:   
+ * SIDE EFFECTS:
  *
  *===========================================================================*/
 void
-GetRemoteDecodedRefFrame(MpegFrame * const frameP, 
+GetRemoteDecodedRefFrame(MpegFrame * const frameP,
                          int         const frameNumber) {
 /*----------------------------------------------------------------------------
    Get decoded frame number 'frameNumber' *frameP from the decode server.
@@ -551,7 +552,7 @@ static void cleanup_fork( dummy )       /* try to kill all child processes */
 #endif
 
     if (kill(ClientPid[i], TERMINATE_PID_SIGNAL)) {
-      fprintf(stderr, "cleanup_fork: killed PID=%d failed (errno %d)\n", 
+      fprintf(stderr, "cleanup_fork: killed PID=%d failed (errno %d)\n",
           ClientPid[i], errno);
     }
   }
@@ -574,24 +575,24 @@ static int safe_fork(command)       /* fork child process and remember its PID *
   static int init=0;
   char *argis[MAXARGS];
   register int i=1;
-  
+
   if (!(argis[0] = strtok(command, " \t"))) return(0); /* tokenize */
   while ((argis[i] = strtok(NULL, " \t")) && i < MAXARGS) ++i;
   argis[i] = NULL;
-  
+
 #ifdef DEBUG_FORK
-  {register int i=0; 
+  {register int i=0;
    fprintf(stderr, "Command %s becomes:\n", command);
    while(argis[i]) {fprintf(stderr, "--%s--\n", argis[i]); ++i;} }
 #endif
-  
+
   if (!init) {          /* register clean-up routine */
     signal (SIGQUIT, cleanup_fork);
     signal (SIGTERM, cleanup_fork);
     signal (SIGINT , cleanup_fork);
     init=1;
   }
-  
+
   if (-1 == (ClientPid[current_max_forked_pid] = fork()) )  {
     perror("safe_fork: fork failed ");
     return(-1);
@@ -682,25 +683,25 @@ decodedFrameToDisk(int const otherSock) {
     MpegFrame * frameP;
 
     ReadInt(otherSock, &frameNumber);
-    
+
     if (debugSockets) {
-        fprintf(stdout, "INPUT SERVER:  GETTING DECODED FRAME %d\n", 
+        fprintf(stdout, "INPUT SERVER:  GETTING DECODED FRAME %d\n",
                 frameNumber);
         fflush(stdout);
     }
 
     /* should read frame from socket, then write to disk */
     frameP = Frame_New(frameNumber, 'i');
-    
+
     Frame_AllocDecoded(frameP, TRUE);
-    
+
     readYUVDecoded(otherSock, Fsize_x, Fsize_y, frameP);
 
     /* now output to disk */
     WriteDecodedFrame(frameP);
 
     Frame_Free(frameP);
-}        
+}
 
 
 
@@ -708,12 +709,12 @@ static void
 decodedFrameFromDisk(int const otherSock) {
 
     /* request for decoded frame from disk */
-            
+
     int frameNumber;
     MpegFrame * frameP;
 
     ReadInt(otherSock, &frameNumber);
-    
+
     if (debugSockets) {
         fprintf(stdout, "INPUT SERVER:  READING DECODED FRAME %d "
                 "from DISK\n", frameNumber);
@@ -722,15 +723,15 @@ decodedFrameFromDisk(int const otherSock) {
 
     /* should read frame from disk, then write to socket */
     frameP = Frame_New(frameNumber, 'i');
-    
+
     Frame_AllocDecoded(frameP, TRUE);
-    
+
     ReadDecodedRefFrame(frameP, frameNumber);
-    
+
     writeYUVDecoded(otherSock, Fsize_x, Fsize_y, frameP);
-    
+
     Frame_Free(frameP);
-}        
+}
 
 
 
@@ -762,10 +763,10 @@ routeFromSocketToDisk(int              const otherSock,
 
         MALLOCARRAY_NOFAIL(bigBuffer, bigBufferSize);
     }
-    
+
     /* now read in the bytes */
     ReadBytes(otherSock, bigBuffer, numBytes);
-    
+
     /* open file to output this stuff to */
     pm_asprintf(&fileName, "%s.frame.%d", outputFileName, frameNumber);
     filePtr = fopen(fileName, "wb");
@@ -777,9 +778,9 @@ routeFromSocketToDisk(int              const otherSock,
 
     /* now write the bytes here */
     fwrite(bigBuffer, sizeof(char), numBytes, filePtr);
-    
+
     fclose(filePtr);
-    
+
     if (debugSockets) {
         fprintf(stdout, "====I/O SERVER:  WROTE FRAME %d to disk\n",
                 frameNumber);
@@ -788,7 +789,7 @@ routeFromSocketToDisk(int              const otherSock,
 
     *bigBufferP     = bigBuffer;
     *bigBufferSizeP = bigBufferSize;
-}        
+}
 
 
 
@@ -803,7 +804,7 @@ readConvertWriteToSocket(struct inputSource * const inputSourceP,
    the "base format" result to socket 'otherSock'.
 -----------------------------------------------------------------------------*/
     FILE * convertedFileP;
-    
+
     convertedFileP = ReadIOConvert(inputSourceP, frameNumber);
     if (convertedFileP) {
         bool eof;
@@ -811,21 +812,21 @@ readConvertWriteToSocket(struct inputSource * const inputSourceP,
         while (!eof) {
             unsigned char buffer[1024];
             unsigned int numBytes;
-            
+
             numBytes = fread(buffer, 1, sizeof(buffer), convertedFileP);
-            
+
             if (numBytes > 0) {
                 WriteInt(otherSock, numBytes);
                 WriteBytes(otherSock, buffer, numBytes);
             } else
                 eof = TRUE;
         }
-        
+
         if (strcmp(ioConversion, "*") == 0 )
             fclose(convertedFileP);
         else
             pclose(convertedFileP);
-        
+
         *endOfStreamP = FALSE;
     } else
         *endOfStreamP = TRUE;
@@ -848,13 +849,13 @@ readWriteYuvToSocket(struct inputSource * const inputSourceP,
     MpegFrame * frameP;
 
     frameP = Frame_New(frameNumber, 'i');
-    
+
     ReadFrame(frameP, inputSourceP, frameNumber, inputConversion,
               endOfStreamP);
-    
+
     if (!*endOfStreamP) {
         writeYUVOrig(otherSock, Fsize_x, Fsize_y, frameP);
-        
+
         {
             /* Make sure we don't leave until other processor read
                everything
@@ -907,7 +908,7 @@ processNextConnection(int                  const serverSocket,
     int          otherSock;
     int          command;
     const char * error;
-    
+
     AcceptConnection(serverSocket, &otherSock, &error);
     if (error)
         errorExit("I/O SERVER: Failed to accept next connection.  %s", error);
@@ -948,12 +949,12 @@ processNextConnection(int                  const serverSocket,
     }
     close(otherSock);
 }
- 
+
 
 
 void
 IoServer(struct inputSource * const inputSourceP,
-         const char *         const parallelHostName, 
+         const char *         const parallelHostName,
          int                  const portNum) {
 /*----------------------------------------------------------------------------
    Execute an I/O server.
@@ -979,7 +980,7 @@ IoServer(struct inputSource * const inputSourceP,
 
     bigBufferSize = 0;  /* Start with no buffer */
     bigBuffer = NULL;
-    
+
     /* once we get IO port num, should transmit it to parallel server */
 
     CreateListeningSocket(&serverSocket, &ioPortNum, &error);
@@ -1043,12 +1044,12 @@ SendRemoteFrame(int const frameNumber, BitBucket * const bb) {
     WriteInt(clientSocket, negativeFour);
 
     WriteInt(clientSocket, frameNumber);
-    
+
     if (frameNumber != -1) {
         /* send number of bytes */
-        
+
         WriteInt(clientSocket, (bb->totalbits+7)>>3);
-    
+
         /* now send the bytes themselves */
         Bitio_WriteToSocket(bb, clientSocket);
     }
@@ -1062,11 +1063,11 @@ SendRemoteFrame(int const frameNumber, BitBucket * const bb) {
 
 
 void
-GetRemoteFrame(MpegFrame * const frameP, 
+GetRemoteFrame(MpegFrame * const frameP,
                int         const frameNumber) {
 /*----------------------------------------------------------------------------
    Get a frame from the I/O server.
-   
+
    This is intended for use by a child.
 -----------------------------------------------------------------------------*/
     int           clientSocket;
@@ -1084,7 +1085,7 @@ GetRemoteFrame(MpegFrame * const frameP,
                     &clientSocket, &error);
 
     if (error)
-        errorExit("CHILD: Can't connect to I/O server to get a frame.  %s", 
+        errorExit("CHILD: Can't connect to I/O server to get a frame.  %s",
                   error);
 
     WriteInt(clientSocket, frameNumber);
@@ -1104,7 +1105,7 @@ GetRemoteFrame(MpegFrame * const frameP,
 
                 if (numBytes > sizeof(buffer))
                     errorExit("Invalid message received: numBytes = %d, "
-                              "which is greater than %u", 
+                              "which is greater than %u",
                               numBytes, (unsigned)sizeof(numBytes));
                 ReadBytes(clientSocket, buffer, numBytes);
 
@@ -1162,9 +1163,9 @@ getAndProcessACombineConnection(int const outputServerSocket) {
     if (error)
         errorExit("COMBINE SERVER: "
                   "Failed to accept next connection.  %s", error);
-    
+
     ReadInt(otherSock, &command);
-    
+
     if (command == -2) {
         /* this is notification from non-remote process that a
            frame is done.
@@ -1173,7 +1174,7 @@ getAndProcessACombineConnection(int const outputServerSocket) {
 
         ReadInt(otherSock, &frameStart);
         ReadInt(otherSock, &frameEnd);
-            
+
         machineDebug("COMBINE_SERVER: Frames %d - %d done",
                      frameStart, frameEnd);
         {
@@ -1199,7 +1200,7 @@ openInputFile(const char * const fileName,
 
     FILE * inputFileP;
     unsigned int attempts;
-    
+
     inputFileP = NULL;
     attempts = 0;
 
@@ -1207,14 +1208,14 @@ openInputFile(const char * const fileName,
         inputFileP = fopen(fileName, "rb");
         if (inputFileP == NULL) {
             pm_message("ERROR  Couldn't read frame file '%s' errno = %d (%s)"
-                       "attempt %d", 
+                       "attempt %d",
                        fileName, errno, strerror(errno), attempts);
             pm_sleep(1000);
         }
         ++attempts;
     }
     if (inputFileP == NULL)
-        pm_error("Unable to open file '%s' after %d attempts.", 
+        pm_error("Unable to open file '%s' after %d attempts.",
                  fileName, attempts);
 
     *inputFilePP = inputFileP;
@@ -1239,7 +1240,7 @@ waitForOutputFile(void *        const inputHandle,
         const char * fileName;
 
         while (!frameDone[frameNumber]) {
-            machineDebug("COMBINE_SERVER: Waiting for frame %u done", 
+            machineDebug("COMBINE_SERVER: Waiting for frame %u done",
                          frameNumber);
 
             getAndProcessACombineConnection(outputServerSocket);
@@ -1274,8 +1275,8 @@ unlinkFile(void *       const inputHandle,
 
 
 void
-CombineServer(int          const numFrames, 
-              const char * const masterHostName, 
+CombineServer(int          const numFrames,
+              const char * const masterHostName,
               int          const masterPortNum,
               const char * const outputFileName) {
 /*----------------------------------------------------------------------------
@@ -1287,17 +1288,17 @@ CombineServer(int          const numFrames,
   FILE * ofP;
   const char * error;
   struct combineControl combineControl;
-  
+
   /* once we get Combine port num, should transmit it to parallel server */
-  
+
   CreateListeningSocket(&outputServerSocket, &combinePortNum, &error);
   if (error)
       errorExit("Unable to create socket on which to listen.  %s", error);
 
   machineDebug("COMBINE SERVER: LISTENING ON PORT %d", combinePortNum);
-  
+
   TransmitPortNum(masterHostName, masterPortNum, combinePortNum);
-  
+
   MALLOCARRAY_NOFAIL(frameDone, numFrames);
   {
       unsigned int i;
@@ -1305,16 +1306,16 @@ CombineServer(int          const numFrames,
           frameDone[i] = FALSE;
   }
   ofP = pm_openw(outputFileName);
-  
+
   combineControl.numFrames = numFrames;
 
   FramesToMPEG(ofP, &combineControl, &waitForOutputFile, &unlinkFile);
 
   machineDebug("COMBINE SERVER: Shutting down");
-  
+
   /* tell Master server we are done */
   TransmitPortNum(masterHostName, masterPortNum, combinePortNum);
-  
+
   close(outputServerSocket);
 
   fclose(ofP);
@@ -1340,18 +1341,18 @@ startCombineServer(const char * const encoderName,
     int          otherSock;
     const char * error;
 
-    pm_snprintf(command, sizeof(command), 
+    pm_snprintf(command, sizeof(command),
                 "%s %s -max_machines %d -output_server %s %d %d %s",
-                encoderName, 
+                encoderName,
                 debugMachines ? "-debug_machines" : "",
-                numMachines, masterHostName, masterPortNum, 
+                numMachines, masterHostName, masterPortNum,
                 numInputFiles, paramFileName);
-    
+
     machineDebug("MASTER: Starting combine server with shell command '%s'",
                  command);
 
     safe_fork(command);
-    
+
     machineDebug("MASTER: Listening for connection back from "
                  "new Combine server");
 
@@ -1382,9 +1383,9 @@ startDecodeServer(const char * const encoderName,
     int          otherSock;
     const char * error;
 
-    pm_snprintf(command, sizeof(command), 
+    pm_snprintf(command, sizeof(command),
                 "%s %s -max_machines %d -decode_server %s %d %d %s",
-                encoder_name, 
+                encoder_name,
                 debugMachines ? "-debug_machines" : "",
                 numMachines, masterHostName, masterPortNum,
                 numInputFiles, paramFileName);
@@ -1404,9 +1405,9 @@ startDecodeServer(const char * const encoderName,
                   "decode server.  %s", error);
 
     ReadInt(otherSock, decodePortNumP);
-    
+
     close(otherSock);
-    
+
     machineDebug("MASTER:  Decode port number = %d", *decodePortNumP);
 }
 
@@ -1420,11 +1421,11 @@ startIoServer(const char *   const encoderName,
               int            const masterSocket,
               const char *   const paramFileName,
               int *          const ioPortNumP) {
-              
+
     char         command[1024];
     int          otherSock;
     const char * error;
-    
+
     sprintf(command, "%s -max_machines %d -io_server %s %d %s",
             encoderName, numChildren, masterHostName, masterPortNum,
             paramFileName);
@@ -1433,7 +1434,7 @@ startIoServer(const char *   const encoderName,
                  command);
 
     safe_fork(command);
-    
+
     machineDebug("MASTER: Listening for connection back from "
                  "new I/O server");
 
@@ -1442,14 +1443,14 @@ startIoServer(const char *   const encoderName,
         errorExit("MASTER SERVER: "
                   "Failed to accept connection back from the new "
                   "I/O server.  %s", error);
-    
+
     ReadInt(otherSock, ioPortNumP);
     close(otherSock);
-    
+
     machineDebug("MASTER:  I/O port number = %d", *ioPortNumP);
-}    
-    
-    
+}
+
+
 
 static void
 extendToEndOfPattern(unsigned int * const nFramesP,
@@ -1458,7 +1459,7 @@ extendToEndOfPattern(unsigned int * const nFramesP,
                      unsigned int   const numFramesInStream) {
 
     assert(framePatternLen >= 1);
-        
+
     while (startFrame + *nFramesP < numFramesInStream &&
            (startFrame + *nFramesP) % framePatternLen != 0)
         ++(*nFramesP);
@@ -1478,7 +1479,7 @@ allocateInitialFrames(struct scheduler * const schedulerP,
 /*----------------------------------------------------------------------------
    Choose which frames, to hand out to the new child numbered 'childNum'.
 -----------------------------------------------------------------------------*/
-    unsigned int const framesPerChild = 
+    unsigned int const framesPerChild =
         MAX(1, ((schedulerP->numFramesInJob - schedulerP->nextFrame) /
                 (schedulerP->numMachines - childNum)));
 
@@ -1507,7 +1508,7 @@ allocateInitialFrames(struct scheduler * const schedulerP,
 static float
 taperedGoalTime(struct childState const childState[],
                 unsigned int      const remainingFrameCount) {
-        
+
     float        goalTime;
     float        allChildrenFPS;
     float        remainingJobTime;
@@ -1515,9 +1516,9 @@ taperedGoalTime(struct childState const childState[],
     float        sum;
     int          numMachinesToEstimate;
     unsigned int childNum;
-    
+
     /* frames left = lastFrameInStream - startFrame + 1 */
-    for (childNum = 0, sum = 0.0, numMachinesToEstimate = 0; 
+    for (childNum = 0, sum = 0.0, numMachinesToEstimate = 0;
          childNum < numMachines; ++childNum) {
         if (!childState[childNum].finished) {
             if (childState[childNum].fps < 0.0 )
@@ -1526,12 +1527,12 @@ taperedGoalTime(struct childState const childState[],
                 sum += childState[childNum].fps;
         }
     }
-    
+
     allChildrenFPS = (float)numMachines *
         (sum/(float)(numMachines-numMachinesToEstimate));
-    
+
     remainingJobTime = (float)remainingFrameCount/allChildrenFPS;
-    
+
     goalTime = MAX(5.0, remainingJobTime/2);
 
     return goalTime;
@@ -1575,23 +1576,23 @@ allocateMoreFrames(struct scheduler * const schedulerP,
 
     if (!goalTimeSpecified) {
         goalTime = taperedGoalTime(childState,
-                                   schedulerP->numFramesInJob - 
+                                   schedulerP->numFramesInJob -
                                    schedulerP->nextFrame);
-    
+
         pm_message("MASTER: ASSIGNING %s %.2f seconds of work",
                    machineName[childNum], goalTime);
     } else
         goalTime = goalTimeArg;
-    
+
     if (childState[childNum].numSeconds != 0)
-        avgFps = (float)childState[childNum].numFrames / 
+        avgFps = (float)childState[childNum].numFrames /
             childState[childNum].numSeconds;
     else
         avgFps = 0.1;       /* arbitrary small value */
 
     nFrames = MAX(1u, (unsigned int)(goalTime * avgFps + 0.5));
-    
-    nFrames = MIN(nFrames, 
+
+    nFrames = MIN(nFrames,
                   schedulerP->numFramesInJob - schedulerP->nextFrame);
 
     if (forceIalign)
@@ -1648,7 +1649,7 @@ startChildren(struct scheduler *   const schedulerP,
     MALLOCARRAY_NOFAIL(childState, schedulerP->numMachines);
 
     childrenLeftCurrentIoServer = 0;  /* No current I/O server yet */
-    
+
     numIoServers = 0;  /* None created yet */
 
     for (childNum = 0; childNum < schedulerP->numMachines; ++childNum) {
@@ -1669,17 +1670,17 @@ startChildren(struct scheduler *   const schedulerP,
                          machineName[childNum]);
         } else {
             childState[childNum].finished   = FALSE;
-        
+
             if (remote[childNum]) {
                 if (childrenLeftCurrentIoServer == 0) {
-                    startIoServer(encoderName, schedulerP->numMachines, 
+                    startIoServer(encoderName, schedulerP->numMachines,
                                   masterHostName, masterPortNum, masterSocket,
                                   paramFileName, &ioPortNum[numIoServers++]);
-                    
+
                     childrenLeftCurrentIoServer = SOMAXCONN;
                 }
                 --childrenLeftCurrentIoServer;
-            } 
+            }
             pm_snprintf(command, sizeof(command),
                         "%s %s -l %s %s "
                         "%s %s -child %s %d %d %d %d %d %d "
@@ -1689,22 +1690,22 @@ startChildren(struct scheduler *   const schedulerP,
                         beNice ? "nice" : "",
                         executable[childNum],
                         debugMachines ? "-debug_machines" : "",
-                        masterHostName, masterPortNum, 
+                        masterHostName, masterPortNum,
                         remote[childNum] ? ioPortNum[numIoServers-1] : 0,
                         combinePortNum, decodePortNum, childNum,
                         remote[childNum] ? 1 : 0,
                         startFrame, startFrame + nFrames - 1,
-                        remote[childNum] ? 
+                        remote[childNum] ?
                           remoteParamFile[childNum] : paramFileName
                 );
-        
+
             machineDebug("MASTER: Starting child server "
                          "with shell command '%s'", command);
 
             safe_fork(command);
 
             machineDebug("MASTER: Frames %d-%d assigned to new child %s",
-                         startFrame, startFrame + nFrames - 1, 
+                         startFrame, startFrame + nFrames - 1,
                          machineName[childNum]);
         }
         childState[childNum].startFrame = startFrame;
@@ -1720,7 +1721,7 @@ startChildren(struct scheduler *   const schedulerP,
 static void
 noteFrameDone(const char * const combineHostName,
               int          const combinePortNum,
-              unsigned int const frameStart, 
+              unsigned int const frameStart,
               unsigned int const frameEnd) {
 /*----------------------------------------------------------------------------
    Tell the Combine server that frames 'frameStart' through 'frameEnd'
@@ -1738,7 +1739,7 @@ noteFrameDone(const char * const combineHostName,
 
     ConnectToSocket(combineHostName, combinePortNum, &hostEntP,
                     &clientSocket, &error);
-    
+
     if (error)
         errorExit("MASTER: Can't connect to Combine server to tell it frames "
                   "are done.  %s", error);
@@ -1775,7 +1776,7 @@ feedTheChildren(struct scheduler * const schedulerP,
    As children finish assignments, inform the combine server at
    'combineHostName':'combinePortNum' of such.
 
-   Note that the children got initial assigments when they were created.
+   Note that the children got initial assignments when they were created.
    So the first thing we do is wait for them to finish those.
 -----------------------------------------------------------------------------*/
     unsigned int numFinished;
@@ -1808,7 +1809,7 @@ feedTheChildren(struct scheduler * const schedulerP,
         ReadInt(otherSock, &seconds);
 
         csP = &childState[childNum];
-        
+
         csP->numSeconds += seconds;
         csP->fps = (float)csP->numFrames / (float)csP->numSeconds;
 
@@ -1818,7 +1819,7 @@ feedTheChildren(struct scheduler * const schedulerP,
             framesPerSecond = (float)csP->lastNumFrames * 2.0;
 
         machineDebug("MASTER: Child %s FINISHED ASSIGNMENT.  "
-                     "%f frames per second", 
+                     "%f frames per second",
                      machineName[childNum], framesPerSecond);
 
         noteFrameDone(combineHostName, combinePortNum, csP->startFrame,
@@ -1855,7 +1856,7 @@ feedTheChildren(struct scheduler * const schedulerP,
         close(otherSock);
 
         machineDebug("MASTER: %d/%d DONE; %d ARE ASSIGNED",
-                     framesDone, schedulerP->numFramesInJob, 
+                     framesDone, schedulerP->numFramesInJob,
                      schedulerP->nextFrame - framesDone);
     }
 }
@@ -1898,7 +1899,7 @@ waitForCombineServerToTerminate(int const masterSocket) {
     }
     close(otherSock);
 }
-    
+
 
 
 static void
@@ -1932,46 +1933,46 @@ printFinalStats(FILE *            const statfileP,
                     (unsigned int)(startUpEnd - startUpBegin));
             fprintf(fileP, "SHUT DOWN TIME:  %u seconds\n",
                     (unsigned int)(shutDownEnd - shutDownBegin));
-            
-            fprintf(fileP, 
+
+            fprintf(fileP,
                     "%14.14s %8.8s %8.8s %12.12s %9.9s\n",
                     "MACHINE", "Frames", "Seconds", "Frames/Sec",
                     "Self Time");
 
-            fprintf(fileP, 
+            fprintf(fileP,
                     "%14.14s %8.8s %8.8s %12.12s %9.9s\n",
                     "--------------", "--------", "--------", "------------",
                     "---------");
 
             totalFPS = 0.0;
             for (childNum = 0; childNum < numChildren; ++childNum) {
-                float const localFPS = 
+                float const localFPS =
                     (float)childState[childNum].numFrames /
                     childState[childNum].numSeconds;
                 fprintf(fileP, "%14.14s %8u %8u %12.4f %8u\n",
-                        machineName[childNum], 
-                        childState[childNum].numFrames, 
+                        machineName[childNum],
+                        childState[childNum].numFrames,
                         childState[childNum].numSeconds,
-                        localFPS, 
+                        localFPS,
                         (unsigned int)((float)numFrames/localFPS));
                 totalFPS += localFPS;
             }
 
-            fprintf(fileP, 
+            fprintf(fileP,
                     "%14.14s %8.8s %8.8s %12.12s %9.9s\n",
                     "--------------", "--------", "--------", "------------",
                     "---------");
 
-            fprintf(fileP, "%14s %8.8s %8u %12.4f\n", 
-                    "OPTIMAL", "", 
+            fprintf(fileP, "%14s %8.8s %8u %12.4f\n",
+                    "OPTIMAL", "",
                     (unsigned int)((float)numFrames/totalFPS),
                     totalFPS);
-            
+
             {
                 unsigned int const diffTime = shutDownEnd - startUpBegin;
-                
-                fprintf(fileP, "%14s %8.8s %8u %12.4f\n", 
-                        "ACTUAL", "", diffTime, 
+
+                fprintf(fileP, "%14s %8.8s %8u %12.4f\n",
+                        "ACTUAL", "", diffTime,
                         (float)numFrames / diffTime);
             }
             fprintf(fileP, "\n\n");
@@ -1983,7 +1984,7 @@ printFinalStats(FILE *            const statfileP,
 
 void
 MasterServer(struct inputSource * const inputSourceP,
-             const char *         const paramFileName, 
+             const char *         const paramFileName,
              const char *         const outputFileName) {
 /*----------------------------------------------------------------------------
    Execute the master server function.
@@ -2025,21 +2026,21 @@ MasterServer(struct inputSource * const inputSourceP,
         fprintf(stdout, "---MASTER USING PORT %d\n", portNum);
 
     startCombineServer(encoder_name, numMachines, hostName, portNum,
-                       inputSourceP->numInputFiles, 
-                       paramFileName, masterSocket, 
+                       inputSourceP->numInputFiles,
+                       paramFileName, masterSocket,
                        &combinePortNum);
 
     if (referenceFrame == DECODED_FRAME)
         startDecodeServer(encoder_name, numMachines, hostName, portNum,
-                          inputSourceP->numInputFiles, 
+                          inputSourceP->numInputFiles,
                           paramFileName, masterSocket,
                           &decodePortNum);
 
     startChildren(&scheduler, encoder_name, hostName, portNum,
                   paramFileName, parallelPerfect, forceIalign,
-                  framePatternLen, parallelTestFrames, 
+                  framePatternLen, parallelTestFrames,
                   niceProcesses,
-                  masterSocket, combinePortNum, decodePortNum, 
+                  masterSocket, combinePortNum, decodePortNum,
                   ioPortNum, &numIoServers,
                   &childState);
 
@@ -2076,10 +2077,10 @@ MasterServer(struct inputSource * const inputSourceP,
 
 
 void
-NotifyMasterDone(const char * const masterHostName, 
-                 int          const masterPortNum, 
+NotifyMasterDone(const char * const masterHostName,
+                 int          const masterPortNum,
                  int          const childNum,
-                 unsigned int const seconds, 
+                 unsigned int const seconds,
                  boolean *    const moreWorkToDoP,
                  int *        const nextFrameStartP,
                  int *        const nextFrameEndP) {
@@ -2098,11 +2099,11 @@ NotifyMasterDone(const char * const masterHostName,
     time_t tempTimeStart, tempTimeEnd;
     const char * error;
 
-    machineDebug("CHILD: NOTIFYING MASTER Machine %d assignment complete", 
+    machineDebug("CHILD: NOTIFYING MASTER Machine %d assignment complete",
                  childNum);
 
     time(&tempTimeStart);
-    
+
     ConnectToSocket(masterHostName, masterPortNum, &hostEntry,
                     &clientSocket, &error);
     if (error)
@@ -2132,9 +2133,9 @@ NotifyMasterDone(const char * const masterHostName,
 
 
 void
-DecodeServer(int          const numInputFiles, 
-             const char * const decodeFileName, 
-             const char * const masterHostName, 
+DecodeServer(int          const numInputFiles,
+             const char * const decodeFileName,
+             const char * const masterHostName,
              int          const masterPortNum) {
 /*----------------------------------------------------------------------------
    Execute the decode server.
@@ -2220,7 +2221,7 @@ DecodeServer(int          const numInputFiles,
             }
         } else {
             frameDone[frameReady] = TRUE;
-            
+
             machineDebug("DECODE SERVER:  FRAME %d READY", frameReady);
 
             if ( waitMachine[frameReady] ) {
@@ -2233,7 +2234,7 @@ DecodeServer(int          const numInputFiles,
                                     &clientSocket, &error);
                     if (error)
                         errorExit("DECODE SERVER: "
-                                  "Can't connect to child machine.  %s", 
+                                  "Can't connect to child machine.  %s",
                                   error);
                     close(clientSocket);
                     waitPtr = waitList[waitPtr]-1;
@@ -2243,7 +2244,7 @@ DecodeServer(int          const numInputFiles,
 
         close(otherSock);
     }
-    
+
     machineDebug("DECODE SERVER:  Shutting down");
 
     /* tell Master server we are done */
diff --git a/converter/ppm/ppmtompeg/param.c b/converter/ppm/ppmtompeg/param.c
index ce2cadf1..9499b4ea 100644
--- a/converter/ppm/ppmtompeg/param.c
+++ b/converter/ppm/ppmtompeg/param.c
@@ -1,8 +1,8 @@
 /*===========================================================================*
- * param.c              
- *                      
- *  Procedures to read in parameter file  
- *                                    
+ * param.c
+ *
+ *  Procedures to read in parameter file
+ *
  *===========================================================================*/
 
 /* COPYRIGHT INFORMATION IS AT THE END OF THIS FILE */
@@ -10,9 +10,9 @@
 #define _DEFAULT_SOURCE 1
     /* New name for SVID & BSD source defines */
 #define _XOPEN_SOURCE 500
-    /* This makes sure popen() is in stdio.h.  In GNU libc 2.1.3, 
+    /* This makes sure popen() is in stdio.h.  In GNU libc 2.1.3,
      _POSIX_C_SOURCE = 2 is sufficient, but on AIX 4.3, the higher level
-     _XOPEN_SOURCE is required.  2000.09.09 
+     _XOPEN_SOURCE is required.  2000.09.09
 
      This also makes sure strdup() is in string.h.
     */
@@ -125,11 +125,6 @@ int mult_seq_headers = 0;  /* 0 for none, N for header/N GOPs */
 
 extern char currentPath[MAXPATHLEN];
 
-static const char * const optionText[LAST_OPTION+1] = { 
-    "GOP_SIZE", "PATTERN", "PIXEL", "PQSCALE",
-    "OUTPUT", "RANGE", "PSEARCH_ALG", "IQSCALE", "INPUT_DIR",
-    "INPUT_CONVERT", "INPUT", "BQSCALE", "BASE_FILE_FORMAT",
-    "SLICES_PER_FRAME", "BSEARCH_ALG", "REFERENCE_FRAME"};
 static bool optionSeen[NUM_OPTIONS+1];
     /* optionSeen[x] means we have seen option x in the parameter file we've
        been reading.
@@ -250,7 +245,7 @@ ReadMachineNames(FILE * const fpointer)
  *
  * GetFrameRate
  *
- * take a character string with the input frame rate 
+ * take a character string with the input frame rate
  * and return the correct frame rate code for use in the Sequence header
  *
  * RETURNS: frame rate code as per MPEG-I spec
@@ -292,7 +287,7 @@ mergeInputSource(struct inputSource *       const baseSourceP,
     unsigned int i;
 
     baseSourceP->ifArraySize += addedSourceP->numInputFileEntries;
-    REALLOCARRAY_NOFAIL(baseSourceP->inputFileEntries, 
+    REALLOCARRAY_NOFAIL(baseSourceP->inputFileEntries,
                         baseSourceP->ifArraySize);
     for (i = 0; i < addedSourceP->numInputFileEntries; ++i)
         baseSourceP->inputFileEntries[baseSourceP->numInputFileEntries++] =
@@ -303,7 +298,7 @@ mergeInputSource(struct inputSource *       const baseSourceP,
 
 /* Forward declaration for recursively called function */
 static void
-ReadInputFileNames(FILE *               const fpointer, 
+ReadInputFileNames(FILE *               const fpointer,
                    const char *         const endInput,
                    struct inputSource * const inputSourceP);
 
@@ -355,11 +350,11 @@ expandBackTickLine(const char *         const input,
 
 
 static void
-ReadInputFileNames(FILE *               const fpointer, 
+ReadInputFileNames(FILE *               const fpointer,
                    const char *         const endInput,
                    struct inputSource * const inputSourceP) {
 /*----------------------------------------------------------------------------
-   Read a list of input file names from the parameter file.  Add 
+   Read a list of input file names from the parameter file.  Add
    the information to *inputSourceP.
 
    If inputSourceP == NULL, read off the list, but ignore it.
@@ -384,7 +379,7 @@ ReadInputFileNames(FILE *               const fpointer,
         else {
             if (strncmp(input, endInput, strlen(endInput)) == 0)
                 endStatementRead = TRUE;
-            else if ((input[0] == '#') || (input[0] == '\n')) { 
+            else if ((input[0] == '#') || (input[0] == '\n')) {
                 /* It's a comment or blank line.  Ignore it */
             } else if (input[0] == '`' ) {
                 expandBackTickLine(input, inputSourceP);
@@ -405,7 +400,7 @@ static void
 initOptionSeen(void) {
 
     unsigned int index;
-    
+
     for (index = FIRST_OPTION; index < NUM_OPTIONS; ++index)
         optionSeen[index] = FALSE;
 }
@@ -477,7 +472,7 @@ verifyNoMissingCombineFramesOption(void) {
 static void
 verifyNoMissingOption(int  const function) {
 /*----------------------------------------------------------------------------
-  Verify that the parameter file contains every option it is supposed to. 
+  Verify that the parameter file contains every option it is supposed to.
   Abort program if not.
 -----------------------------------------------------------------------------*/
     switch(function) {
@@ -515,7 +510,7 @@ processIqtable(FILE * const fpointer) {
                         &qtable[row*8+2],  &qtable[row*8+3],
                         &qtable[row*8+4],  &qtable[row*8+5],
                         &qtable[row*8+6],  &qtable[row*8+7])) {
-            pm_error("Line %d of IQTABLE doesn't have 8 elements!", 
+            pm_error("Line %d of IQTABLE doesn't have 8 elements!",
                      row);
         }
         for (col = 0; col < 8; ++col) {
@@ -528,7 +523,7 @@ processIqtable(FILE * const fpointer) {
             }
         }
     }
-            
+
     if (qtable[0] != 8) {
         pm_message("Warning:  IQTable Element 1,1 reset to 8, "
                    "since it must be 8.");
@@ -593,15 +588,15 @@ removeTrailingWhite(const char *  const rawLine,
         pm_error("Unable to get memory to process parameter file");
 
     p = buffer + strlen(buffer) - 1;  /* Point to last character */
-    
+
     /* Position p to just before the trailing white space (might be one
        character before beginning of string!)
     */
     while (p >= buffer && isspace(*p))
         --p;
-    
+
     ++p;  /* Move to first trailing whitespace character */
-    
+
     *p = '\0';  /* Chop off all the trailing whitespace */
 
     *editedLineP = buffer;
@@ -622,7 +617,7 @@ readNiqTable(FILE * const fpointer) {
                         &niqtable[row*8+2],  &niqtable[row*8+3],
                         &niqtable[row*8+4],  &niqtable[row*8+5],
                         &niqtable[row*8+6],  &niqtable[row*8+7])) {
-            pm_error("Line %d of NIQTABLE doesn't have 8 elements!", 
+            pm_error("Line %d of NIQTABLE doesn't have 8 elements!",
                      row);
         }
         for ( col = 0; col < 8; col++ ) {
@@ -675,7 +670,7 @@ processParamLine(char const input[],
             optionSeen[OPTION_ASPECT_RATIO] = TRUE;
         }
         break;
-        
+
     case 'B':
         if (strneq(input, "BQSCALE", 7)) {
             SetBQScale(atoi(SkipSpacesTabs(&input[7])));
@@ -694,7 +689,7 @@ processParamLine(char const input[],
             optionSeen[OPTION_BIT_RATE] = TRUE;
         } else if (strneq(input, "BUFFER_SIZE", 11)) {
             setBufferSize(SkipSpacesTabs(&input[11]));
-            optionSeen[OPTION_BUFFER_SIZE] = TRUE;                  
+            optionSeen[OPTION_BUFFER_SIZE] = TRUE;
         }
         break;
 
@@ -717,8 +712,8 @@ processParamLine(char const input[],
 
             strcpy(currentFramePath, arg);
         } else if (strneq(input, "FRAME_INPUT", 11)) {
-            ReadInputFileNames(fpointer, "FRAME_END_INPUT", 
-                               frameInputSourceP->stdinUsed ? 
+            ReadInputFileNames(fpointer, "FRAME_END_INPUT",
+                               frameInputSourceP->stdinUsed ?
                                NULL : frameInputSourceP);
             optionSeen[OPTION_FRAME_INPUT] = TRUE;
         } else if (strneq(input, "FORCE_I_ALIGN", 13)) {
@@ -726,7 +721,7 @@ processParamLine(char const input[],
         } 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.  
+               encode all the frames.  Now we just do that all the time.
                Why wouldn't we?
             */
         } else if (strneq(input, "FRAME_RATE", 10)) {
@@ -737,7 +732,7 @@ processParamLine(char const input[],
             optionSeen[OPTION_FRAME_RATE] = TRUE;
         }
         break;
-        
+
     case 'G':
         if (strneq(input, "GOP_SIZE", 8)) {
             SetGOPSize(atoi(SkipSpacesTabs(&input[8])));
@@ -749,8 +744,8 @@ processParamLine(char const input[],
 
             strcpy(currentGOPPath, arg);
         } else if (strneq(input, "GOP_INPUT", 9)) {
-            ReadInputFileNames(fpointer, "GOP_END_INPUT", 
-                               gopInputSourceP->stdinUsed ? 
+            ReadInputFileNames(fpointer, "GOP_END_INPUT",
+                               gopInputSourceP->stdinUsed ?
                                NULL : gopInputSourceP);
             optionSeen[OPTION_GOP_INPUT] = TRUE;
         } else if (strneq(input, "GAMMA", 5)) {
@@ -759,7 +754,7 @@ processParamLine(char const input[],
             optionSeen[OPTION_GAMMA] = TRUE;
         }
         break;
-        
+
     case 'I':
         if (strneq(input, "IQSCALE", 7)) {
             SetIQScale(atoi(SkipSpacesTabs(&input[7])));
@@ -774,7 +769,7 @@ processParamLine(char const input[],
             strcpy(inputConversion, SkipSpacesTabs(&input[13]));
             optionSeen[OPTION_INPUT_CONVERT] = TRUE;
         } else if (streq(input, "INPUT")) {
-            ReadInputFileNames(fpointer, "END_INPUT", 
+            ReadInputFileNames(fpointer, "END_INPUT",
                                inputSourceP->stdinUsed ?
                                NULL : inputSourceP);
             optionSeen[OPTION_INPUT] = TRUE;
@@ -792,7 +787,7 @@ processParamLine(char const input[],
         if (strneq(input, "KEEP_TEMP_FILES", 15))
             keepTempFiles = TRUE;
         break;
-        
+
     case 'N':
       if (strneq(input, "NIQTABLE", 8)) {
           readNiqTable(fpointer);
@@ -808,11 +803,11 @@ processParamLine(char const input[],
                 strcpy(outputFileName, arg);
             else
                 sprintf(outputFileName, "%s.gop.%d", arg, whichGOP);
-            
+
             optionSeen[OPTION_OUTPUT] = TRUE;
         }
         break;
-        
+
     case 'P':
         if (strneq(input, "PATTERN", 7)) {
             SetFramePattern(SkipSpacesTabs(&input[7]));
@@ -842,7 +837,7 @@ processParamLine(char const input[],
             optionSeen[OPTION_PARALLEL] = TRUE;
         }
         break;
-        
+
     case 'R':
         if (strneq(input, "RANGE", 5)) {
             processRanges(SkipSpacesTabs(&input[5]));
@@ -900,14 +895,14 @@ processParamLine(char const input[],
             optionSeen[OPTION_USER_DATA] = TRUE;
         }
         break;
-        
+
     case 'W':
         if (strneq(input, "WARN_UNDERFLOW", 14))
             paramP->warnUnderflow = TRUE;
         if (strneq(input, "WARN_OVERFLOW", 13))
             paramP->warnOverflow = TRUE;
         break;
-        
+
     case 'Y':
         if (strneq(input, "YUV_SIZE", 8)) {
             const char * const arg = SkipSpacesTabs(&input[8]);
@@ -934,7 +929,7 @@ processParamLine(char const input[],
 
 
 void
-ReadParamFile(const char *         const fileName, 
+ReadParamFile(const char *         const fileName,
               majorProgramFunction const function,
               struct params *      const paramP) {
 /*----------------------------------------------------------------------------
@@ -1014,7 +1009,7 @@ ReadParamFile(const char *         const fileName,
   if (yuvUsed) {
       if (!optionSeen[OPTION_YUV_SIZE])
           pm_error("YUV format used but YUV_SIZE not given");
-      
+
       if (!optionSeen[OPTION_YUV_FORMAT]) {
           strcpy (yuvConversion, "EYUV");
           pm_message("WARNING:  YUV format not specified; "
@@ -1031,7 +1026,7 @@ ReadParamFile(const char *         const fileName,
   if (optionSeen[OPTION_IO_CONVERT] != optionSeen[OPTION_SLAVE_CONVERT])
       pm_error("Must have either both IO_SERVER_CONVERT and SLAVE_CONVERT "
                "or neither");
-      
+
   if (optionSeen[OPTION_DEFS_SPECIFICS] && !optionSeen[OPTION_SPECIFICS])
       pm_error("Does not make sense to define Specifics file options, "
                "but no specifics file!");
diff --git a/converter/ppm/ppmtompeg/parse_huff.pl b/converter/ppm/ppmtompeg/parse_huff.pl
index 1fc6466c..633e5877 100644
--- a/converter/ppm/ppmtompeg/parse_huff.pl
+++ b/converter/ppm/ppmtompeg/parse_huff.pl
@@ -51,7 +51,7 @@
 #    composed of 1, 0, space, and 's'.  Spaces are ignored, and
 #    s corresponds to the sign bit.  In the output of this program,
 #    We'll completely right-shift the data, with a 0 for the sign
-#    bit.  The encoder will make appropriate changes before outputing.
+#    bit.  The encoder will make appropriate changes before outputting.
 
 
 open(HUFFC, "> huff.c") || die "Can't write huff.c: $!\n";
diff --git a/converter/ppm/ppmtompeg/psearch.c b/converter/ppm/ppmtompeg/psearch.c
index 3cca1241..e350137e 100644
--- a/converter/ppm/ppmtompeg/psearch.c
+++ b/converter/ppm/ppmtompeg/psearch.c
@@ -58,7 +58,7 @@ int psearchAlg;
  *
  * PRECONDITIONS:   The relevant block in 'current' is valid (it has not
  *          been dct'd).  Thus, the data in 'current' can be
- *          accesed through y_blocks, cr_blocks, and cb_blocks.
+ *          accessed through y_blocks, cr_blocks, and cb_blocks.
  *          This is not the case for the blocks in 'prev.'
  *          Therefore, references into 'prev' should be done
  *          through the struct items ref_y, ref_cr, ref_cb
diff --git a/converter/ppm/ppmtompeg/psocket.c b/converter/ppm/ppmtompeg/psocket.c
index 6a50dc27..aac61022 100644
--- a/converter/ppm/ppmtompeg/psocket.c
+++ b/converter/ppm/ppmtompeg/psocket.c
@@ -10,15 +10,15 @@
 ============================================================================*/
 
 #define _XOPEN_SOURCE 500 /* Make sure stdio.h contains pclose() */
-/* _ALL_SOURCE is needed on AIX to make the C library include the 
-   socket services (e.g. define struct sockaddr) 
+/* _ALL_SOURCE is needed on AIX to make the C library include the
+   socket services (e.g. define struct sockaddr)
 
    Note that AIX standards.h actually sets feature declaration macros such
    as _XOPEN_SOURCE, unless they are already set.
 */
 #define _ALL_SOURCE
 #define __EXTENSIONS__
-  /* __EXTENSIONS__ is for a broken Sun C library (uname SunOS kosh 5.8 
+  /* __EXTENSIONS__ is for a broken Sun C library (uname SunOS kosh 5.8
      generic_108528-16 sun4u sparc).  When you define _XOPEN_SOURCE,
      it's vnode.h and resource.h fail to define some data types that they
      need (e.g. timestruct_t).  But with __EXTENSIONS__, they declare the
@@ -126,8 +126,8 @@ unmarshallInt(unsigned char const buffer[],
 
 
 static void
-safeRead(int             const fd, 
-         unsigned char * const buf, 
+safeRead(int             const fd,
+         unsigned char * const buf,
          unsigned int    const nbyte) {
 /*----------------------------------------------------------------------------
     Safely read from file 'fd'.  Keep reading until we get
@@ -144,7 +144,7 @@ safeRead(int             const fd,
             errorExit("read (of %u bytes (total %u) ) returned "
                       "errno %d (%s)",
                       nbyte-numRead, nbyte, errno, strerror(errno));
-        else 
+        else
             numRead += result;
     }
 }
@@ -203,8 +203,8 @@ marshallInt(int              const value,
 
 
 static void
-safeWrite(int             const fd, 
-          unsigned char * const buf, 
+safeWrite(int             const fd,
+          unsigned char * const buf,
           unsigned int    const nbyte) {
 /*----------------------------------------------------------------------------
   Safely write to file 'fd'.  Keep writing until we write 'nbyte'
@@ -217,7 +217,7 @@ safeWrite(int             const fd,
     while (numWritten < nbyte) {
         int const result = write(fd, &buf[numWritten], nbyte-numWritten);
 
-        if (result == -1) 
+        if (result == -1)
             errorExit("write (of %u bytes (total %u) ) returned "
                       "errno %d (%s)",
                       nbyte-numWritten, nbyte, errno, strerror(errno));
@@ -251,8 +251,8 @@ WriteInt(int const socketFd,
 
 
 void
-ConnectToSocket(const char *      const machineName, 
-                int               const portNum, 
+ConnectToSocket(const char *      const machineName,
+                int               const portNum,
                 struct hostent ** const hostEnt,
                 int *             const socketFdP,
                 const char **     const errorP) {
@@ -266,7 +266,7 @@ ConnectToSocket(const char *      const machineName,
    **hostEnt.
 -----------------------------------------------------------------------------*/
     int rc;
-    
+
     *errorP = NULL;  /* initial value */
 
     if ((*hostEnt) == NULL) {
@@ -277,15 +277,15 @@ ConnectToSocket(const char *      const machineName,
     if (!*errorP) {
         rc = socket(AF_INET, SOCK_STREAM, 0);
         if (rc < 0)
-            pm_asprintf(errorP, "socket() failed with errno %d (%s)", 
+            pm_asprintf(errorP, "socket() failed with errno %d (%s)",
                         errno, strerror(errno));
         else {
             int const socketFd = rc;
-            
+
             int rc;
             unsigned short tempShort;
             struct sockaddr_in  nameEntry;
-            
+
             nameEntry.sin_family = AF_INET;
             memset((void *) nameEntry.sin_zero, 0, 8);
             memcpy((void *) &(nameEntry.sin_addr.s_addr),
@@ -293,12 +293,12 @@ ConnectToSocket(const char *      const machineName,
                    (size_t) (*hostEnt)->h_length);
             tempShort = portNum;
             nameEntry.sin_port = htons(tempShort);
-            
+
             rc = connect(socketFd, (struct sockaddr *) &nameEntry,
                          sizeof(struct sockaddr));
-            
+
             if (rc != 0)
-                pm_asprintf(errorP, 
+                pm_asprintf(errorP,
                             "connect() to host '%s', port %d failed with "
                             "errno %d (%s)",
                             machineName, portNum, errno, strerror(errno));
@@ -317,7 +317,7 @@ ConnectToSocket(const char *      const machineName,
 static bool
 portInUseErrno(int const testErrno) {
 /*----------------------------------------------------------------------------
-   Return TRUE iff 'testErrno' is what a bind() would return if one requestd
+   Return TRUE iff 'testErrno' is what a bind() would return if one requested
    a port number that is unavailable (but other port numbers might be).
 -----------------------------------------------------------------------------*/
     bool retval;
@@ -340,19 +340,19 @@ static void
 bindToUnusedPort(int              const socketFd,
                  unsigned short * const portNumP,
                  const char **    const errorP) {
-    
+
     bool foundPort;
     unsigned short trialPortNum;
 
     *errorP = NULL;  /* initial value */
 
-    for (foundPort = FALSE, trialPortNum = 2048; 
-         !foundPort && trialPortNum < 16384 && !*errorP; 
+    for (foundPort = FALSE, trialPortNum = 2048;
+         !foundPort && trialPortNum < 16384 && !*errorP;
          ++trialPortNum) {
-        
+
         struct sockaddr_in nameEntry;
         int rc;
-        
+
         memset((char *) &nameEntry, 0, sizeof(nameEntry));
         nameEntry.sin_family = AF_INET;
         nameEntry.sin_port   = htons(trialPortNum);
@@ -365,10 +365,10 @@ bindToUnusedPort(int              const socketFd,
             *portNumP = trialPortNum;
         } else if (!portInUseErrno(errno))
             pm_asprintf(errorP, "bind() of TCP port number %hu failed "
-                        "with errno %d (%s)", 
+                        "with errno %d (%s)",
                         trialPortNum, errno, strerror(errno));
     }
-    
+
     if (!*errorP && !foundPort)
         pm_asprintf(errorP, "Unable to find a free port.  Every TCP port "
                     "in the range 2048-16383 is in use");
@@ -389,7 +389,7 @@ CreateListeningSocket(int *         const socketP,
    partner can connect).
 -----------------------------------------------------------------------------*/
     int rc;
-    
+
     rc = socket(AF_INET, SOCK_STREAM, 0);
     if (rc < 0)
         pm_asprintf(errorP,
@@ -415,7 +415,7 @@ CreateListeningSocket(int *         const socketP,
             rc = listen(socketFd, SOMAXCONN);
             if (rc != 0)
                 pm_asprintf(errorP, "Unable to listen on TCP socket.  "
-                            "listen() fails with errno %d (%s)", 
+                            "listen() fails with errno %d (%s)",
                             errno, strerror(errno));
         }
         if (*errorP)
@@ -433,11 +433,11 @@ AcceptConnection(int           const listenSocketFd,
     struct sockaddr otherSocket;
     socklenx_t      otherSize;
         /* This is an ugly dual-meaning variable.  As input to accept(),
-           it is the storage size of 'otherSocket'.  As output, it is the 
+           it is the storage size of 'otherSocket'.  As output, it is the
            data length of 'otherSocket'.
         */
     int             rc;
-    
+
     otherSize = sizeof(otherSocket);
 
     rc = accept(listenSocketFd, &otherSocket, &otherSize);
@@ -450,3 +450,6 @@ AcceptConnection(int           const listenSocketFd,
         *errorP = NULL;
     }
 }
+
+
+
diff --git a/converter/ppm/ppmtompeg/rate.c b/converter/ppm/ppmtompeg/rate.c
index 6ec330cf..3fa41102 100644
--- a/converter/ppm/ppmtompeg/rate.c
+++ b/converter/ppm/ppmtompeg/rate.c
@@ -1,6 +1,6 @@
 /*============================================================================*
  * rate.c								      *
- *									      * 
+ *									      *
  *	Procedures concerned with rate control                                *
  *									      *
  * EXPORTED PROCEDURES:							      *
@@ -75,7 +75,7 @@
 
 #define MAX_BIT_RATE 104857600		/* 18 digit number in units of 400 */
 #define MAX_BUFFER_SIZE 16760832        /* 10 digit number in units of 16k */
-#define DEFAULT_BUFFER_SIZE 327680      /* maximun for "constrained" bitstream */
+#define DEFAULT_BUFFER_SIZE 327680      /* maximum for "constrained" bitstream */
 #define DEFAULT_VBV_FULLNESS 3          /* wait till 1/3 full */
 #define DEFAULT_PICT_RATE_CODE 5        /* code for 30 Frames/sec */
 #define DEFAULT_PICT_RATE 30            /* 30 frames per second */
@@ -92,7 +92,7 @@ static bool wantVbvUnderflowWarning;
 static bool wantVbvOverflowWarning;
 
 /*   Variables for the VBV buffer defined in MPEG specs */
-static unsigned int VBV_remainingDelay; 
+static unsigned int VBV_remainingDelay;
     /* delay in units of 1/90000 seconds */
 static int32 VBV_buffer = 0;	  /* fullness of the theoretical VBV buffer */
 static int32 bufferFillRate = 0;    /* constant rate at which buffer filled */
@@ -104,7 +104,7 @@ static int Xi, Xp, Xb;  /*  Global complexity measure  */
 static int Si, Sp, Sb;  /*  Total # bits for last pict of type (Overhead?) */
 
 static float Qi, Qp, Qb; /* avg quantizaton for last picture of type  */
-     
+
 /*  Target bit allocations for each type of picture*/
 int Ti, Tp, Tb;
 
@@ -175,24 +175,6 @@ static int Qscale;	       /* Clipped, truncated quantization value */
 static FILE *RC_FILE;
 #endif
 
-static const char * const Frame_header1 = 
-"  Fm         #     Bit      GOP                    V                ";
-static const char * const Frame_header2 = 
-"   #  type   MBs   Alloc    left  Ni Np Nb  N_act  buff   Q_rc Qscale";
-static const char * const Frame_header3 = 
-"----     -  ----  ------ -------  -- -- --  -----  ------ ----   ----";
-static const char * const Frame_trailer1 = 
-"                      avg          virt     %    GOP      %     VBV";
-static const char * const Frame_trailer2 = 
-"    Sx    Qx      Xx  act N_act  buffer alloc    left  left     buf  delay";
-static const char * const Frame_trailer3 = 
-"------ --.-- -------  --- --.-- -------   --- -------   --- ------- ------";
-
-static const char * const MB_header1 = 
-"MB#  #bits  Q mqt     Dj  Q_j   actj  N_act  totbits b/MB %alloc %done";
-static const char * const MB_header2 = 
-"---  ----- -- --- ------  ---  -----  --.--   ------ ----    ---   ---";
-
 static char rc_buffer[101];
 
 /*	EXTERNAL Variables  */
@@ -211,8 +193,8 @@ void checkSpatialActivity (Block blk0, Block blk1, Block blk2, Block blk3);
 void incNumBlocks (int num);
 void calculateVBVDelay (int num);
 int BlockExperiments  (int16 *OrigBlock, int16 *NewBlock, int control);
-     
-     
+
+
 
 static void
 analyzePattern(const char *  const framePattern,
@@ -226,10 +208,10 @@ analyzePattern(const char *  const framePattern,
     unsigned int i;
 
     /*  Initialize Pattern info */
-    *gop_xP = framePatternLen;    
+    *gop_xP = framePatternLen;
 
     for (i = 0, *gop_iP = 0, *gop_pP = 0, *gop_bP = 0, *errorP = NULL;
-         i < framePatternLen && !*errorP; 
+         i < framePatternLen && !*errorP;
          ++i) {
         switch(framePattern[i]) {
         case 'i': ++*gop_iP; break;
@@ -241,7 +223,7 @@ analyzePattern(const char *  const framePattern,
     }
     assert(*gop_xP == *gop_iP + *gop_pP + *gop_bP);
 }
-  
+
 
 
 /*===========================================================================*
@@ -252,7 +234,7 @@ analyzePattern(const char *  const framePattern,
  *
  * RETURNS:	nothing
  *
- * SIDE EFFECTS:   many global variables 
+ * SIDE EFFECTS:   many global variables
  *
  * NOTES:  Get rid of the redundant pattern stuff!!
  *===========================================================================*/
@@ -266,7 +248,7 @@ initRateControl(bool const wantUnderflowWarning,
     wantVbvOverflowWarning  = wantOverflowWarning;
 
     DBG_PRINT(("Initializing Allocation Data\n"));
-  
+
 #ifdef RC_STATS_FILE
     RC_FILE = fopen("RC_STATS_FILE", "w");
     if ( RC_FILE  == NULL) {
@@ -278,7 +260,7 @@ initRateControl(bool const wantUnderflowWarning,
 #endif
 
     VBV_remainingDelay = 0;
-  
+
     analyzePattern(framePattern, framePatternLen,
                    &GOP_X, &GOP_I, &GOP_P, &GOP_B, &error);
 
@@ -291,46 +273,46 @@ initRateControl(bool const wantUnderflowWarning,
     }
 
 
-    /* Initializing GOP bit allocation */	
+    /* Initializing GOP bit allocation */
     rc_R = 0;
     rc_G = (bit_rate * GOP_X/frameRateRounded);
-  
+
     /*   Initialize the "global complexity measures" */
     Xi = (160 * bit_rate/115);
     Xp = (60 * bit_rate/115);
     Xb = (42 * bit_rate/115);
-  
+
     /*   Initialize MB counters */
     rc_totalMBBits= rc_bitsThisMB= rc_totalFrameBits=rc_totalOverheadBits = 0;
     rc_numBlocks = rc_totalQuant = 0;
-  
+
     /*   init virtual buffers  */
     reactionParameter = (2 * bit_rate / frameRateRounded);
     d0_i = (10 * reactionParameter / 31);
     d0_p = (Kp * d0_i);
     d0_b = (Kb * d0_i);
-  
+
     lastFrameVirtBuf = d0_i;	/*  start with I Frame */
     rc_Q = lastFrameVirtBuf  * 31 / reactionParameter;
-  
+
     /*   init spatial activity measures */
     avg_act = 400;		/* Suggested initial value */
     N_act = 1;
-  
+
     mquant = rc_Q * N_act;
-  
+
     frameDelayIncrement = (90000 / frameRateRounded);
         /* num of "delay" units per frame */
-    bufferFillRate = bit_rate / frameRateRounded; 
+    bufferFillRate = bit_rate / frameRateRounded;
         /* VBV buf fills at constant rate */
     VBV_buffer = buffer_size;
     DBG_PRINT(("VBV- delay: %d, fill rate: %d, delay/Frame: %d units, "
                "buffer size: %d\n",
-               VBV_remainginDelay, bufferFillRate, frameDelayIncrement, 
+               VBV_remainginDelay, bufferFillRate, frameDelayIncrement,
                buffer_size));
-  
+
     result = initGOPRateControl();
-  
+
     return result;
 }
 
@@ -343,21 +325,21 @@ initRateControl(bool const wantUnderflowWarning,
  *
  * RETURNS:	nothing
  *
- * SIDE EFFECTS:   many global variables 
+ * SIDE EFFECTS:   many global variables
  *
  *===========================================================================*/
 int
 initGOPRateControl()
 {
     DBG_PRINT(("Initializing new GOP\n"));
-  
+
     Nx = GOP_X;
     Ni = GOP_I;
     Np = GOP_P;
     Nb = GOP_B;
-  
+
     rc_R += rc_G;
-  
+
     DBG_PRINT(("bufsize: %d, bitrate: %d, pictrate: %d, GOP bits: %d\n",
                buffer_size, bit_rate, frameRateRounded, rc_R));
     DBG_PRINT(("Xi: %d, Xp: %d, Xb: %d Nx: %d, Ni: %d, Np: %d, Nb: %d\n",
@@ -389,20 +371,20 @@ targetRateControl(MpegFrame * const frame) {
     float tempX, tempY, tempZ;
     int result;
     int frameType;
-  
+
     minimumBits = (bit_rate / (8 * frameRateRounded));
-  
+
     /*   Check if new GOP */
     if (Nx == 0) {
         initGOPRateControl();
     }
-  
+
     if (MB_cnt < 0) {MB_cnt = determineMBCount();}
-  
+
     switch (frame->type) {
     case TYPE_IFRAME:
         frameType = 'I';
-    
+
         tempX = ( (Np * Ki * Xp) / (Xi * Kp) );
         tempY = ( (Nb * Ki * Xb) / (Xi*Kb) );
         tempZ = Ni + tempX + tempY;
@@ -411,7 +393,7 @@ targetRateControl(MpegFrame * const frame) {
         current_Tx = Ti = result;
         lastFrameVirtBuf = d0_i;
         break;
-    
+
     case TYPE_PFRAME:
         frameType = 'P';
         tempX =  ( (Ni * Kp * Xi) / (Ki * Xp) );
@@ -422,7 +404,7 @@ targetRateControl(MpegFrame * const frame) {
         current_Tx = Tp = result;
         lastFrameVirtBuf = d0_p;
         break;
-    
+
     case TYPE_BFRAME:
         frameType = 'B';
         tempX =  ( (Ni * Kb * Xi) / (Ki * Xb) );
@@ -433,17 +415,17 @@ targetRateControl(MpegFrame * const frame) {
         current_Tx = Tb = result;
         lastFrameVirtBuf = d0_b;
         break;
-    
+
     default:
         frameType = 'X';
     }
-  
+
     N_act = 1;
     rc_Q = lastFrameVirtBuf  * 31 / reactionParameter;
     mquant = rc_Q * N_act;
     Qscale = (mquant > 31 ? 31 : mquant);
     Qscale = (Qscale < 1 ? 1 : Qscale);
-  
+
 #ifdef HEINOUS_DEBUG_MODE
     {
         const char * strPtr;
@@ -459,15 +441,15 @@ targetRateControl(MpegFrame * const frame) {
     /*   Print Frame info */
     sprintf(rc_buffer, "%4d     %1c  %4d  %6d %7d  "
             "%2d %2d %2d   %2.2f  %6d %4d    %3d",
-            frame->id,frameType,MB_cnt,current_Tx,rc_R,Ni,Np,Nb, 
+            frame->id,frameType,MB_cnt,current_Tx,rc_R,Ni,Np,Nb,
             N_act, lastFrameVirtBuf, rc_Q, Qscale);
-  
+
 #ifdef RC_STATS_FILE
     fprintf(RC_FILE,"%s\n", rc_buffer);
     fflush(RC_FILE);
 #endif
     DBG_PRINT(("%s\n",rc_buffer));
-  
+
     /*  Print headers for Macroblock info */
     if (RC_MB_SAMPLE_RATE) {
 #ifdef HEINOUS_DEBUG_MODE
@@ -483,7 +465,7 @@ targetRateControl(MpegFrame * const frame) {
 
 
 
-static void 
+static void
 updateVBVBuffer(int const frameBits) {
 /*----------------------------------------------------------------------------
   Update the VBV buffer after each frame.  This theoretical buffer is
@@ -532,11 +514,11 @@ updateRateControl(int const type) {
     pctAllocUsed = (totalBits *100 / current_Tx);
     rc_R -= totalBits;
     pctGOPUsed = (rc_R *100/ rc_G);
-  
+
     avg_act = (total_act_j / MB_cnt);
-  
+
     updateVBVBuffer(totalBits);
-  
+
     switch (type) {
     case TYPE_IFRAME:
         Ti = current_Tx;
@@ -563,9 +545,9 @@ updateRateControl(int const type) {
         Xb = frameComplexity;
         break;
     }
-  
+
 #ifdef HEINOUS_DEBUG_MODE
-    {  
+    {
         /*  Print Frame info */
         const char * strPtr;
         strPtr = Frame_trailer1;
@@ -575,26 +557,26 @@ updateRateControl(int const type) {
         strPtr = Frame_trailer3;
         DBG_PRINT(("%s\n",strPtr));
     }
-#endif  
+#endif
     sprintf(rc_buffer, "%6d  %2.2f  %6d  %3d  %2.2f %7d   "
             "%3d %7d   %3d  %6d %6d",
-            totalBits, avgQuant, frameComplexity, avg_act, N_act, 
-            currentVirtBuf, pctAllocUsed, rc_R, pctGOPUsed, 
+            totalBits, avgQuant, frameComplexity, avg_act, N_act,
+            currentVirtBuf, pctAllocUsed, rc_R, pctGOPUsed,
             VBV_buffer, VBV_remainingDelay);
 #ifdef RC_STATS_FILE
     fprintf(RC_FILE,"%s\n", rc_buffer);
     fflush(RC_FILE);
 #endif
     DBG_PRINT(("%s\n",rc_buffer));
-  
+
     Nx--;
     rc_totalMBBits= rc_bitsThisMB= rc_totalFrameBits=rc_totalOverheadBits = 0;
     rc_numBlocks = rc_totalQuant = total_act_j = currentVirtBuf = 0;
-  
+
     DBG_PRINT(("GOP now has %d bits remaining (%3d%%) for %d frames .. , "
-               "Ni= %d, Np= %d, Nb= %d\n", 
+               "Ni= %d, Np= %d, Nb= %d\n",
                rc_R, (rc_R*100/rc_G), (Ni+Np+Nb), Ni, Np, Nb));
-  
+
 }
 
 
@@ -622,21 +604,21 @@ int type;
   int pctUsed, pctDone;
   int bitsThisMB;
   int bitsPerMB;
-  
+
   bitsThisMB = rc_bitsThisMB;
   totalBits = rc_totalFrameBits;
-  bitsPerMB = (totalBits / rc_numBlocks); 
-  pctDone = (rc_numBlocks * 100/ MB_cnt); 
+  bitsPerMB = (totalBits / rc_numBlocks);
+  pctDone = (rc_numBlocks * 100/ MB_cnt);
   pctUsed = (totalBits *100/current_Tx);
-  
+
   sprintf(rc_buffer, "%3d  %5d %2d %3d %6d  %3d %6d   %2.2f   %6d %4d    %3d   %3d\n",
-	  (rc_numBlocks - 1), bitsThisMB, Qscale, mquant, currentVirtBuf, 
+	  (rc_numBlocks - 1), bitsThisMB, Qscale, mquant, currentVirtBuf,
 	  rc_Q, act_j, N_act, totalBits, bitsPerMB, pctUsed, pctDone);
 #ifdef RC_STATS_FILE
   fprintf(RC_FILE, "%s", rc_buffer);
   fflush(RC_FILE);
 #endif
-  
+
   if ( (RC_MB_SAMPLE_RATE) && ((rc_numBlocks -1) % RC_MB_SAMPLE_RATE)) {
     DBG_PRINT(("%s\n", rc_buffer));
   } else {
@@ -695,7 +677,7 @@ void incMacroBlockBits(num)
  *
  * RETURNS:     new Qscale
  *
- * SIDE EFFECTS:   
+ * SIDE EFFECTS:
  *
  *===========================================================================*/
 int needQScaleChange(oldQScale, blk0, blk1, blk2, blk3)
@@ -705,19 +687,19 @@ int needQScaleChange(oldQScale, blk0, blk1, blk2, blk3)
      Block blk2;
      Block blk3;
 {
-  
+
   /*   One more MacroBlock seen */
   rc_numBlocks++;		/* this notes each block num in MB */
-  
+
   checkBufferFullness(oldQScale);
-  
+
   checkSpatialActivity(blk0, blk1, blk2, blk3);
-  
+
   mquant = rc_Q * N_act;
   Qscale = (mquant > 31 ? 31 : mquant);
   Qscale = (Qscale < 1 ? 1 : Qscale);
   rc_totalQuant += Qscale;
-  
+
   if (oldQScale == Qscale)
     return -1;
   else
@@ -727,7 +709,7 @@ int needQScaleChange(oldQScale, blk0, blk1, blk2, blk3)
 
 /*===========================================================================*
  *
- * determineMBCount() 
+ * determineMBCount()
  *
  *      Determines number of Macro Blocks in frame from the frame sizes
  *	passed.
@@ -741,7 +723,7 @@ int
   determineMBCount ()
 {
   int y,x;
-  
+
   x = (Fsize_x +15)/16;
   y = (Fsize_y +15)/16;
   return  (x * y);
@@ -769,11 +751,11 @@ void checkBufferFullness (oldQScale)
      int oldQScale;
 {
   int temp;
-  
+
   temp = lastFrameVirtBuf + rc_totalFrameBits;
   temp -=  (current_Tx * rc_numBlocks / MB_cnt);
   currentVirtBuf = temp;
-  
+
   rc_Q = (currentVirtBuf * 31 / reactionParameter);
   return;
 }
@@ -783,8 +765,8 @@ void checkBufferFullness (oldQScale)
  *
  * void checkSpatialActivity()
  *
- *      Calcualtes the spatial activity for the four luminance blocks of the
- *	macroblock.  Along with the normalized reference quantization parameter 
+ *      Calculates the spatial activity for the four luminance blocks of the
+ *	macroblock.  Along with the normalized reference quantization parameter
  *  (rc_Q) , it determines the quantization factor for the next macroblock.
  *
  * RETURNS:     nothing
@@ -801,19 +783,19 @@ void checkSpatialActivity(blk0, blk1, blk2, blk3)
      Block blk3;
 {
   int temp;
-  int16 *blkArray[4]; 
+  int16 *blkArray[4];
   int16 *curBlock;
   int16 *blk_ptr;
   int var[4];
   int i, j;
-  
-  
+
+
   blkArray[0] = (int16 *) blk0;
   blkArray[1] = (int16 *) blk1;
   blkArray[2] = (int16 *) blk2;
   blkArray[3] = (int16 *) blk3;
-  
-  
+
+
   for (i =0; i < 4; i++) {	/* Compute the activity in each block */
     curBlock = blkArray[i];
     blk_ptr = curBlock;
@@ -821,14 +803,14 @@ void checkSpatialActivity(blk0, blk1, blk2, blk3)
     /*  Find the mean pixel value */
     for (j=0; j < DCTSIZE_SQ; j ++) {
       P_mean += *(blk_ptr++);
-      /*			P_mean += curBlock[j]; 
+      /*			P_mean += curBlock[j];
 				if (curBlock[j] != *(blk_ptr++)) {
 				printf("ARRAY ERROR: block %d\n", j);
 				}
 				*/
     }
     P_mean /= DCTSIZE_SQ;
-    
+
     /*  Now find the variance  */
     curBlock = blkArray[i];
     blk_ptr = curBlock;
@@ -839,25 +821,25 @@ void checkSpatialActivity(blk0, blk1, blk2, blk3)
 	printf("ARRAY ERROR: block %d\n", j);
       }
       temp = curBlock[j] - P_mean;
-#endif      
+#endif
       temp = *(blk_ptr++) - P_mean;
       var[i] += (temp * temp);
     }
     var[i] /= DCTSIZE_SQ;
   }
-  
+
   /*  Choose the minimum variance from the 4 blocks and use as the activity */
   var_sblk  = var[0];
   for (i=1; i < 4; i++) {
     var_sblk = (var_sblk < var[i] ? var_sblk : var[i]);
   }
-  
-  
+
+
   act_j = 1 + var_sblk;
   total_act_j += act_j;
   temp = (2 * act_j + avg_act);
   N_act = ( (float) temp / (float) (act_j + 2*avg_act) );
-  
+
   return;
 }
 
@@ -900,7 +882,7 @@ int getRateMode()
 void setBitRate (const char * const charPtr)
 {
   int rate, rnd;
-  
+
   rate = atoi(charPtr);
   if (rate > 0) {
     RateControlMode = FIXED_RATE;
@@ -915,7 +897,7 @@ void setBitRate (const char * const charPtr)
   rate = (rate > MAX_BIT_RATE ? MAX_BIT_RATE : rate);
   bit_rate = rate;
   DBG_PRINT(("Bit rate is: %d\n", bit_rate));
-} 
+}
 
 
 
@@ -957,7 +939,7 @@ int getBitRate ()
 void setBufferSize (const char * const charPtr)
 {
   int size;
-  
+
   size = atoi(charPtr);
   size = (size > MAX_BUFFER_SIZE ? MAX_BUFFER_SIZE : size);
   if (size > 0) {
diff --git a/converter/ppm/ppmtompeg/readframe.c b/converter/ppm/ppmtompeg/readframe.c
index 2a359b2f..dcc02052 100644
--- a/converter/ppm/ppmtompeg/readframe.c
+++ b/converter/ppm/ppmtompeg/readframe.c
@@ -1,13 +1,13 @@
 /*===========================================================================*
- * readframe.c                    
- *                                
- *  procedures to read in frames  
- *                                
- * EXPORTED PROCEDURES:           
- *  ReadFrame                     
- *  SetFileType                   
- *  SetFileFormat                 
- *                                
+ * readframe.c
+ *
+ *  procedures to read in frames
+ *
+ * EXPORTED PROCEDURES:
+ *  ReadFrame
+ *  SetFileType
+ *  SetFileFormat
+ *
  *===========================================================================*/
 
 /* COPYRIGHT INFORMATION IS AT THE END OF THIS FILE */
@@ -62,7 +62,7 @@ struct YuvLine {
 #ifdef __OS2__
   #define popen _popen
 #endif
-   
+
 
 /*==================*
  * Global VARIABLES *
@@ -100,7 +100,7 @@ static void DoKillDim (MpegFrame *mf, int w, int h);
 
 
 
-void    
+void
 SetResize(bool const set) {
     resizeFrame = set;
 }
@@ -134,7 +134,7 @@ ReadPNM(MpegFrame * const mpegFrameP,
 static void
 openFile(struct inputSource * const inputSourceP,
          unsigned int         const frameNumber,
-         const char *         const conversion, 
+         const char *         const conversion,
          FILE **              const ifPP) {
 
     if (inputSourceP->stdinUsed) {
@@ -145,24 +145,24 @@ openFile(struct inputSource * const inputSourceP,
                 "INPUT_CONVERTER * in the parameter file or supply the "
                 "frames in files by specifying a directory with "
                 "INPUT_DIRECTORY in the parameter file.");
-        
+
         *ifPP = stdin;
     } else {
         const char * fileName;
         const char * fullFileName;
-        
+
         GetNthInputFileName(inputSourceP, frameNumber, &fileName);
-        
+
         pm_asprintf(&fullFileName, "%s/%s", currentPath, fileName);
-        
+
         CurrFile = fullFileName;
-        
+
         if (fileType == ANY_FILE_TYPE) {
             char command[1024];
             const char * convertPtr;
             char * commandPtr;
             const char * charPtr;
-            
+
             /* replace every occurrence of '*' with fullFileName */
             convertPtr = conversion;
             commandPtr = command;
@@ -172,7 +172,7 @@ openFile(struct inputSource * const inputSourceP,
                     ++commandPtr;
                     ++convertPtr;
                 }
-                
+
                 if (*convertPtr == '*') {
                     /* copy fullFileName */
                     charPtr = fullFileName;
@@ -185,7 +185,7 @@ openFile(struct inputSource * const inputSourceP,
                 }
             }
             *commandPtr = '\0';
-            
+
             *ifPP = popen(command, "r");
             if (*ifPP == NULL) {
                 pm_message(
@@ -201,7 +201,7 @@ openFile(struct inputSource * const inputSourceP,
             *ifPP = fopen(fullFileName, "rb");
             if (*ifPP == NULL)
                 pm_error("Couldn't open input file '%s'", fullFileName);
-            
+
             if (baseFormat == JMOVIE_FILE_TYPE)
                 unlink(fullFileName);
         }
@@ -238,7 +238,7 @@ fileIsAtEnd(FILE * const ifP) {
 
     c = getc(ifP);
     if (c == EOF) {
-        if (feof(ifP)) 
+        if (feof(ifP))
             eof = TRUE;
         else
             pm_error("File error on getc() to position to image");
@@ -248,7 +248,7 @@ fileIsAtEnd(FILE * const ifP) {
         eof = FALSE;
 
         rc = ungetc(c, ifP);
-        if (rc == EOF) 
+        if (rc == EOF)
             pm_error("File error doing ungetc() to position to image.");
     }
     return eof;
@@ -262,14 +262,11 @@ ReadFrameFile(MpegFrame *  const frameP,
               const char * const conversion,
               bool *       const eofP) {
 /*----------------------------------------------------------------------------
-   Read a frame from the file 'ifP'.
+   Read a frame from the file 'ifP', doing adjustments as indicated.
 
    Return *eofP == TRUE iff we encounter EOF before we can get the
    frame.
 -----------------------------------------------------------------------------*/
-    MpegFrame   tempFrame;
-    MpegFrame * framePtr;
-
     /* To make this code fit Netpbm properly, we should remove handling
        of all types except PNM and use pm_nextimage() to handle sensing
        of end of stream.
@@ -278,53 +275,59 @@ ReadFrameFile(MpegFrame *  const frameP,
     if (fileIsAtEnd(ifP))
         *eofP = TRUE;
     else {
+        MpegFrame   preResizeFrame;
+            /* The frame object that holds the frame before resizing */
+        MpegFrame * rawFrameP;
+            /* The frame object with which we read in the raw frame */
+
         *eofP = FALSE;
 
         if (resizeFrame) {
-            tempFrame.inUse = FALSE;
-            tempFrame.orig_y = NULL;
-            tempFrame.y_blocks = NULL;
-            tempFrame.decoded_y = NULL;
-            tempFrame.halfX = NULL;
-            framePtr = &tempFrame;
+            preResizeFrame.inUse = FALSE;
+            preResizeFrame.orig_y = NULL;
+            preResizeFrame.y_blocks = NULL;
+            preResizeFrame.decoded_y = NULL;
+            preResizeFrame.halfX = NULL;
+            rawFrameP = &preResizeFrame;
         } else
-            framePtr = frameP;
+            rawFrameP = frameP;
 
         switch(baseFormat) {
         case YUV_FILE_TYPE:
 
             /* Encoder YUV */
             if ((strncmp (yuvConversion, "EYUV", 4) == 0) ||
-                (strncmp (yuvConversion, "UCB", 3) == 0)) 
+                (strncmp (yuvConversion, "UCB", 3) == 0))
 
-                ReadEYUV(framePtr, ifP, realWidth, realHeight);
+                ReadEYUV(rawFrameP, ifP, realWidth, realHeight);
 
             else
                 /* Abekas-type (interlaced) YUV */
-                ReadAYUV(framePtr, ifP, realWidth, realHeight);
+                ReadAYUV(rawFrameP, ifP, realWidth, realHeight);
 
             break;
         case Y_FILE_TYPE:
-            ReadY(framePtr, ifP, realWidth, realHeight);
+            ReadY(rawFrameP, ifP, realWidth, realHeight);
             break;
         case PNM_FILE_TYPE:
-            ReadPNM(framePtr, ifP);
+            ReadPNM(rawFrameP, ifP);
             break;
         case SUB4_FILE_TYPE:
-            ReadSub4(framePtr, ifP, yuvWidth, yuvHeight);
+            ReadSub4(rawFrameP, ifP, yuvWidth, yuvHeight);
             break;
         case JPEG_FILE_TYPE:
         case JMOVIE_FILE_TYPE:
-            ReadJPEG(framePtr, ifP);
+            ReadJPEG(rawFrameP, ifP);
             break;
         default:
             break;
         }
 
-        if (resizeFrame)
-            Frame_Resize(frameP, &tempFrame, Fsize_x, Fsize_y, 
+        if (resizeFrame) {
+            assert(rawFrameP == &preResizeFrame);
+            Frame_Resize(frameP, &preResizeFrame, Fsize_x, Fsize_y,
                          outputWidth, outputHeight);
-    
+        }
         if (GammaCorrection)
             DoGamma(frameP, Fsize_x, Fsize_y);
 
@@ -338,7 +341,7 @@ ReadFrameFile(MpegFrame *  const frameP,
 
 
 void
-ReadFrame(MpegFrame *          const frameP, 
+ReadFrame(MpegFrame *          const frameP,
           struct inputSource * const inputSourceP,
           unsigned int         const frameNumber,
           const char *         const conversion,
@@ -693,7 +696,7 @@ SeparateLine(fpointer, lineptr, width)
         fprintf(stderr, "       or any even-length string consisting of the letters U, V, and Y.\n");
             exit(1);
         }
-    
+
     }
 
 }
@@ -738,7 +741,7 @@ ReadY(mf, fpointer, width, height)
     for (y = Fsize_y; y < height; y++) {
     safe_fread(junk, 1, width, fpointer);
     }
-    
+
     for (y = 0 ; y < (Fsize_y >> 1); y++) {
       memset(mf->orig_cb[y], 128, (Fsize_x>>1));
       memset(mf->orig_cr[y], 128, (Fsize_x>>1));
@@ -830,7 +833,7 @@ int w,h;
   int i,j;
 
   if (!init_done) {
-    for(i=0; i<256; i++) 
+    for(i=0; i<256; i++)
       GammaVal[i]=(unsigned char) (pow(((double) i)/255.0,GammaValue)*255.0+0.5);
     init_done=TRUE;
   }
@@ -871,7 +874,7 @@ int w,h;
                         ^ kill_dim_break
                              ^kill_dim_end
               kill_dim_slope gives the slope (y = kill_dim_slope * x +0)
-              from 0 to kill_dim_break                      
+              from 0 to kill_dim_break
  *
  *===========================================================================*/
 
@@ -930,7 +933,7 @@ int w,h;
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  */
 
-/*  
+/*
  *  $Header: /n/picasso/project/mpeg/mpeg_dist/mpeg_encode/RCS/readframe.c,v 1.27 1995/08/14 22:31:40 smoot Exp $
  *  $Log: readframe.c,v $
  *  Revision 1.27  1995/08/14 22:31:40  smoot
diff --git a/converter/ppm/ppmtompeg/specifics.c b/converter/ppm/ppmtompeg/specifics.c
index a8a48af3..bd74e805 100644
--- a/converter/ppm/ppmtompeg/specifics.c
+++ b/converter/ppm/ppmtompeg/specifics.c
@@ -41,6 +41,7 @@
 
 #include "netpbm/mallocvar.h"
 #include "netpbm/nstring.h"
+#include "netpbm/pm_system.h"
 
 #include "all.h"
 #include "mtypes.h"
@@ -67,7 +68,7 @@ void Parse_Specifics_File_v1 (FILE *fp);
 void Parse_Specifics_File_v2 (FILE *fp);
 FrameSpecList *MakeFslEntry (void);
 void AddSlc (FrameSpecList *c,int snum, int qs);
-Block_Specifics *AddBs (FrameSpecList *c,int bnum, 
+Block_Specifics *AddBs (FrameSpecList *c,int bnum,
 				    boolean rel, int qs);
 FrameSpecList *MakeFslEntry (void);
 #define my_upper(c) (((c>='a') && (c<='z')) ? (c-'a'+'A') : c)
@@ -144,7 +145,7 @@ static char version = -1;
  *   Cpp's and reads in the specifics file.  Creates fsl data structure.
  *
  *   Returns: nothing
- * 
+ *
  *   Modifies: fsl, file specificsFile".cpp"
  *
  *================================================================
@@ -152,38 +153,37 @@ static char version = -1;
 void
 Specifics_Init() {
 
-    FILE *specificsFP;
-  
-    {
-        const char * command;
-        pm_asprintf(&command, "rm -f %s.cpp", specificsFile);
-        system(command);
-        pm_strfree(command);
-    }
+    /* 'specificsFile' is a global variable whose value is the name of the
+       specifics file, given by the parameter file.
+    */
+
+    FILE *       specificsFP;
+    const char * preprocessedFileNm;
+
+    pm_message("Specifics file: %s", specificsFile);
+
+    pm_asprintf(&preprocessedFileNm, "%s.cpp", specificsFile);
+
+    pm_system_lp("rm", NULL, NULL, NULL, NULL, "-f", preprocessedFileNm);
+
     {
         const char * command;
-        pm_asprintf(&command, "cpp -P %s %s %s.cpp",
-                    specificsDefines, specificsFile, specificsFile);
-        system(command);
+        pm_asprintf(&command, "cpp -P %s '%s' -o '%s'",
+                    specificsDefines, specificsFile, preprocessedFileNm);
+        pm_system(NULL, NULL, NULL, NULL, command);
         pm_strfree(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);
+
+    specificsFP = pm_openr(preprocessedFileNm);
+
+    pm_system_lp("rm", NULL, NULL, NULL, NULL, "-f", preprocessedFileNm);
 
     Parse_Specifics_File(specificsFP);
-    {
-        const char * command;
-        pm_asprintf(&command, "rm -f %s.cpp", specificsFile);
-        system(command);
-        pm_strfree(command);
-    }
-}
 
+    pm_close(specificsFP);
+
+    pm_strfree(preprocessedFileNm);
+}
 
 
 
@@ -244,7 +244,7 @@ FILE *fp;
       fprintf(stderr, "Specifics file: What? *%s*\n", line);
       break;
     }}
-  
+
 }
 
 /* Version 1 */
@@ -253,7 +253,7 @@ FILE *fp;
 {
   char line[1024],*lp;
   FrameSpecList *current, *new;
-  char typ; 
+  char typ;
   int fnum,snum, bnum, qs, newqs;
 
   fsl = MakeFslEntry();
@@ -301,7 +301,7 @@ FILE *fp;
       fprintf(stderr," What? *%s*\n", line);
       break;
     }}
-  
+
 }
 
 
@@ -382,7 +382,7 @@ Parse_Specifics_File_v2(FILE * const fP) {
                 } else {
                     numScanned =
                         2 + sscanf(lp, "%s %d %d %d %d",
-                                   kind, &fx, &fy, &sx, &sy); 
+                                   kind, &fx, &fy, &sx, &sy);
                 }
 
                 qs = newqs;
@@ -573,7 +573,7 @@ int start_qs;
   FrameSpecList *tmp;
   boolean found_it;
   static int leftovers = 0;  /* Used in case of forced movement into 1..31 range */
-  
+
   *info = (BlockMV * )NULL;
   if (last == (FrameSpecList *) NULL){
     /* No cache, try to find number fn */
@@ -590,7 +590,7 @@ int start_qs;
   } else {
     if (last->framenum != fn) { /* cache miss! */
       /* first check if it is next */
-      if ((last->next != (FrameSpecList *) NULL) && 
+      if ((last->next != (FrameSpecList *) NULL) &&
 	  (last->next->framenum == fn)) {
 	last = last->next;
       } else {
@@ -617,13 +617,13 @@ int start_qs;
     fprintf(stderr, "PROGRAMMER ERROR: last has wrong number!\n");
     return -1; /* no data on it */
   }
-  
+
   switch(typ) {
   case 0: /* Frame: num is ignored */
     leftovers = 0;
 #ifdef BLEAH
     printf("QSchange frame %d to %d\n", fn, last->qscale);
-#endif 
+#endif
     return last->qscale;
     break;
 
@@ -683,8 +683,8 @@ int start_qs;
   /* no luck */
   return -1;
 }
-     
-    
+
+
 /*================================================================
  *
  *  SpecTypeLookup
diff --git a/converter/ppm/ppmtopcx.c b/converter/ppm/ppmtopcx.c
index fa68edc5..5b7e1003 100644
--- a/converter/ppm/ppmtopcx.c
+++ b/converter/ppm/ppmtopcx.c
@@ -12,7 +12,7 @@
 **
 ** 11/Dec/94: first version
 ** 12/Dec/94: added handling of "packed" format (16 colors or less)
-** 
+**
 ** ZSoft PCX File Format Technical Reference Manual
 ** http://bespin.org/~qz/pc-gpe/pcx.txt
 ** http://web.archive.org/web/20100206055706/http://www.qzx.com/pc-gpe/pcx.txt
@@ -31,13 +31,13 @@
 #define PCX_MAXVAL      (pixval)255
 
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    const char *inputFilespec;  /* '-' if stdin */
+    const char * inputFilespec;  /* '-' if stdin */
     unsigned int truecolor;   /* -24bit option */
-    unsigned int use_8_bit; /* -8bit option */
+    unsigned int use8Bit; /* -8bit option */
     unsigned int planes;    /* zero means minimum */
     unsigned int packed;
     unsigned int verbose;
@@ -49,16 +49,16 @@ struct cmdlineInfo {
 
 
 
-struct pcxCmapEntry {
+struct PcxCmapEntry {
     unsigned char r;
     unsigned char g;
     unsigned char b;
 };
 
-static struct pcxCmapEntry
+static struct PcxCmapEntry
 pcxCmapEntryFromPixel(pixel const colorPixel) {
 
-    struct pcxCmapEntry retval;
+    struct PcxCmapEntry retval;
 
     retval.r = PPM_GETR(colorPixel);
     retval.g = PPM_GETG(colorPixel);
@@ -70,11 +70,11 @@ pcxCmapEntryFromPixel(pixel const colorPixel) {
 
 
 static void
-parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo * const cmdlineP) {
+parseCommandLine(int argc, const 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.  
+   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.
@@ -82,7 +82,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;
+    optEntry * option_def;
         /* Instructions to pm_optParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
@@ -94,15 +94,15 @@ parseCommandLine(int argc, char ** argv,
     MALLOCARRAY(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENT3 */
-    OPTENT3(0, "24bit",     OPT_FLAG,   NULL,                  
+    OPTENT3(0, "24bit",     OPT_FLAG,   NULL,
             &cmdlineP->truecolor,    0);
-    OPTENT3(0, "8bit",      OPT_FLAG,   NULL,    
-            &cmdlineP->use_8_bit,    0);
-    OPTENT3(0, "planes",    OPT_UINT,   &cmdlineP->planes, 
+    OPTENT3(0, "8bit",      OPT_FLAG,   NULL,
+            &cmdlineP->use8Bit,    0);
+    OPTENT3(0, "planes",    OPT_UINT,   &cmdlineP->planes,
             &planesSpec,             0);
-    OPTENT3(0, "packed",    OPT_FLAG,   NULL,                  
+    OPTENT3(0, "packed",    OPT_FLAG,   NULL,
             &cmdlineP->packed,       0);
-    OPTENT3(0, "verbose",   OPT_FLAG,   NULL,                  
+    OPTENT3(0, "verbose",   OPT_FLAG,   NULL,
             &cmdlineP->verbose,      0);
     OPTENT3(0, "stdpalette", OPT_FLAG,  NULL,
             &cmdlineP->stdpalette,   0);
@@ -115,7 +115,7 @@ parseCommandLine(int argc, char ** argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
+    pm_optParseOptions3( &argc, (char **)argv, opt, sizeof(opt), 0 );
         /* Uses and sets argc, argv, and some of *cmdline_p and others. */
 
     if (!xposSpec)
@@ -141,17 +141,17 @@ parseCommandLine(int argc, char ** argv,
             pm_error("-planes is meaningless with -packed.");
         if (cmdlineP->truecolor)
             pm_error("-planes is meaningless with -24bit");
-        if (cmdlineP->use_8_bit)
+        if (cmdlineP->use8Bit)
             pm_error("-planes is meaningless with -8bit");
     }
-    
+
     if (paletteSpec && cmdlineP->stdpalette)
         pm_error("You can't specify both -palette and -stdpalette");
 
     if (!paletteSpec)
         cmdlineP->palette = NULL;
 
-    if (cmdlineP->use_8_bit && cmdlineP->truecolor) 
+    if (cmdlineP->use8Bit && cmdlineP->truecolor)
         pm_error("You cannot specify both -8bit and -truecolor");
 
     if (argc-1 < 1)
@@ -172,11 +172,11 @@ parseCommandLine(int argc, char ** argv,
  * Write out a two-byte little-endian word to the PCX file
  */
 static void
-Putword(int    const w, 
-        FILE * const fp) {
+putword(unsigned int const w,
+        FILE *       const fp) {
 
     int rc;
-    
+
     rc = pm_writelittleshort(fp, w);
 
     if (rc != 0)
@@ -189,26 +189,24 @@ Putword(int    const w,
  * Write out a byte to the PCX file
  */
 static void
-Putbyte(int    const b, 
-        FILE * const fp) {
+putbyte(unsigned int const b,
+        FILE *       const ofP) {
 
     int rc;
 
-    rc = fputc(b & 0xff, fp);
+    rc = fputc(b & 0xff, ofP);
+
     if (rc == EOF)
         pm_error("Error writing byte to output file.");
 }
 
 
 
-static const unsigned char bitmask[] = {1, 2, 4, 8, 16, 32, 64, 128};
-
-
 static void
-extractPlane(unsigned char * const rawrow, 
-             int             const cols, 
-             unsigned char * const buf, 
-             int             const plane) {
+extractPlane(unsigned char * const rawrow,
+             unsigned int    const cols,
+             unsigned char * const buf,
+             unsigned int    const plane) {
 /*----------------------------------------------------------------------------
    From the image row 'rawrow', which is an array of 'cols' palette indices
    (as unsigned 8 bit integers), extract plane number 'plane' and return
@@ -223,12 +221,10 @@ extractPlane(unsigned char * const rawrow,
     int cbit;  /* Significance of bit representing current column in output */
     unsigned char *cp;  /* Ptr to next output byte to fill */
     unsigned char byteUnderConstruction;
-    
+
     cp = buf;  /* initial value */
 
-    cbit = 7;
-    byteUnderConstruction = 0x00;
-    for (col = 0; col < cols; ++col) {
+    for (col = 0, cbit = 7, byteUnderConstruction = 0x00; col < cols; ++col) {
         if (rawrow[col] & planeMask)
             byteUnderConstruction |= (1 << cbit);
 
@@ -250,14 +246,17 @@ extractPlane(unsigned char * const rawrow,
 
 
 static void
-PackBits(unsigned char * const rawrow, 
-         int             const width, 
-         unsigned char * const buf, 
-         int             const bits) {
+packBits(unsigned char * const rawrow,
+         unsigned int    const width,
+         unsigned char * const buf,
+         unsigned int    const bits) {
 
-    int x, i, shift;
+    unsigned int x;
+    int i;
+    int shift;
 
-    shift = i = -1;
+    shift = -1;
+    i = -1;
 
     for (x = 0; x < width; ++x) {
         if (shift < 0) {
@@ -273,71 +272,73 @@ PackBits(unsigned char * const rawrow,
 
 
 static void
-write_header(FILE *              const fp, 
-             int                 const cols, 
-             int                 const rows, 
-             int                 const BitsPerPixel, 
-             int                 const Planes, 
-             struct pcxCmapEntry const cmap16[],
-             unsigned int        const xPos, 
-             unsigned int        const yPos) {
-
-    int i, BytesPerLine;
-
-    Putbyte(PCX_MAGIC, fp);        /* .PCX magic number            */
-    Putbyte(0x05, fp);             /* PC Paintbrush version        */
-    Putbyte(0x01, fp);             /* .PCX run length encoding     */
-    Putbyte(BitsPerPixel, fp);     /* bits per pixel               */
-    
-    Putword(xPos, fp);             /* x1   - image left            */
-    Putword(yPos, fp);             /* y1   - image top             */
-    Putword(xPos+cols-1, fp);      /* x2   - image right           */
-    Putword(yPos+rows-1, fp);      /* y2   - image bottom          */
-
-    Putword(cols, fp);             /* horizontal resolution        */
-    Putword(rows, fp);             /* vertical resolution          */
+writeHeader(FILE *              const ofP,
+            unsigned int        const cols,
+            unsigned int        const rows,
+            unsigned int        const bitsPerPixel,
+            unsigned int        const planes,
+            struct PcxCmapEntry const cmap16[],
+            unsigned int        const xPos,
+            unsigned int        const yPos) {
+
+    unsigned int bytesPerLine;
+
+    putbyte(PCX_MAGIC, ofP);        /* .PCX magic number            */
+    putbyte(0x05, ofP);             /* PC Paintbrush version        */
+    putbyte(0x01, ofP);             /* .PCX run length encoding     */
+    putbyte(bitsPerPixel, ofP);     /* bits per pixel               */
+
+    putword(xPos, ofP);             /* x1   - image left            */
+    putword(yPos, ofP);             /* y1   - image top             */
+    putword(xPos+cols-1, ofP);      /* x2   - image right           */
+    putword(yPos+rows-1, ofP);      /* y2   - image bottom          */
+
+    putword(cols, ofP);             /* horizontal resolution        */
+    putword(rows, ofP);             /* vertical resolution          */
 
     /* Write out the Color Map for images with 16 colors or less */
-    if (cmap16)
+    if (cmap16) {
+        unsigned int i;
         for (i = 0; i < 16; ++i) {
-            Putbyte(cmap16[i].r, fp);
-            Putbyte(cmap16[i].g, fp);
-            Putbyte(cmap16[i].b, fp);
+            putbyte(cmap16[i].r, ofP);
+            putbyte(cmap16[i].g, ofP);
+            putbyte(cmap16[i].b, ofP);
         }
-    else {
+    } else {
         unsigned int i;
         for (i = 0; i < 16; ++i) {
-            Putbyte(0, fp);
-            Putbyte(0, fp);
-            Putbyte(0, fp);
+            putbyte(0, ofP);
+            putbyte(0, ofP);
+            putbyte(0, ofP);
         }
     }
-    Putbyte(0, fp);                /* reserved byte                */
-    Putbyte(Planes, fp);           /* number of color planes       */
+    putbyte(0, ofP);                /* reserved byte                */
+    putbyte(planes, ofP);           /* number of color planes       */
 
-    BytesPerLine = ((cols * BitsPerPixel) + 7) / 8;
-    Putword(BytesPerLine, fp);    /* number of bytes per scanline */
+    bytesPerLine = ((cols * bitsPerPixel) + 7) / 8;
+    putword(bytesPerLine, ofP);    /* number of bytes per scanline */
 
-    Putword(1, fp);                /* palette info                 */
+    putword(1, ofP);                /* palette info                 */
 
     {
         unsigned int i;
         for (i = 0; i < 58; ++i)        /* fill to end of header        */
-            Putbyte(0, fp);
+            putbyte(0, ofP);
     }
 }
 
 
 
 static void
-PCXEncode(FILE *                const fp, 
-          const unsigned char * const buf, 
-          int                   const Size) {
+pcxEncode(FILE *                const ofP,
+          const unsigned char * const buf,
+          unsigned int          const size) {
 
-    const unsigned char * const end = buf + Size;
+    const unsigned char * const end = buf + size;
 
     const unsigned char * currentP;
-    int previous, count;
+    unsigned int          previous;
+    unsigned int          count;
 
     currentP = buf;
     previous = *currentP++;
@@ -350,19 +351,19 @@ PCXEncode(FILE *                const fp,
         else {
             if (count > 1 || (previous & 0xc0) == 0xc0) {
                 count |= 0xc0;
-                Putbyte ( count , fp );
+                putbyte ( count , ofP );
             }
-            Putbyte(previous, fp);
+            putbyte(previous, ofP);
             previous = c;
-            count   = 1;
+            count = 1;
         }
     }
 
     if (count > 1 || (previous & 0xc0) == 0xc0) {
         count |= 0xc0;
-        Putbyte ( count , fp );
+        putbyte(count, ofP);
     }
-    Putbyte(previous, fp);
+    putbyte(previous, ofP);
 }
 
 
@@ -377,10 +378,10 @@ indexOfColor(colorhash_table const cht,
 -----------------------------------------------------------------------------*/
 
     int const rc = ppm_lookupcolor(cht, &color);
-            
+
     if (rc < 0)
         pm_error("Image contains color which is not "
-                 "in the palette: %u/%u/%u", 
+                 "in the palette: %u/%u/%u",
                  PPM_GETR(color), PPM_GETG(color), PPM_GETB(color));
 
     return rc;
@@ -389,61 +390,46 @@ indexOfColor(colorhash_table const cht,
 
 
 static void
-ppmTo16ColorPcx(pixel **            const pixels, 
-                int                 const cols, 
-                int                 const rows, 
-                struct pcxCmapEntry const pcxcmap[], 
-                int                 const colors, 
-                colorhash_table     const cht, 
-                bool                const packbits,
-                unsigned int        const planesRequested,
-                unsigned int        const xPos,
-                unsigned int        const yPos) {
+writeRaster16Color(FILE * const ofP,
+                   pixel **            const pixels,
+                   unsigned int        const cols,
+                   unsigned int        const rows,
+                   unsigned int        const planes,
+                   colorhash_table     const cht,
+                   bool                const packbits,
+                   unsigned int        const bitsPerPixel) {
+
+    unsigned int const bytesPerLine = ((cols * bitsPerPixel) + 7) / 8;
+
+    unsigned char * indexRow;  /* malloc'ed */
+    /* indexRow[x] is the palette index of the pixel at column x of
+       the row currently being processed
+    */
+    unsigned char * planesrow; /* malloc'ed */
+    /* This is the input for a single row to the compressor */
 
-    int Planes, BytesPerLine, BitsPerPixel;
-    unsigned char *indexRow;  /* malloc'ed */
-        /* indexRow[x] is the palette index of the pixel at column x of
-           the row currently being processed
-        */
-    unsigned char *planesrow; /* malloc'ed */
-        /* This is the input for a single row to the compressor */
-    int row;
+    unsigned int row;
 
-    if (packbits) {
-        Planes = 1;
-        if (colors > 4)        BitsPerPixel = 4;
-        else if (colors > 2)   BitsPerPixel = 2;
-        else                   BitsPerPixel = 1;
-    } else {
-        BitsPerPixel = 1;
-        if (planesRequested)
-            Planes = planesRequested;
-        else {
-            if (colors > 8)        Planes = 4;
-            else if (colors > 4)   Planes = 3;
-            else if (colors > 2)   Planes = 2;
-            else                   Planes = 1;
-        }
-    }
-    BytesPerLine = ((cols * BitsPerPixel) + 7) / 8;
     MALLOCARRAY_NOFAIL(indexRow, cols);
-    MALLOCARRAY_NOFAIL(planesrow, BytesPerLine);
+    MALLOCARRAY(planesrow, bytesPerLine);
+
+    if (!planesrow)
+        pm_error("Failed to allocate buffer for a line of %u bytes",
+                 bytesPerLine);
 
-    write_header(stdout, cols, rows, BitsPerPixel, Planes, pcxcmap, 
-                 xPos, yPos);
     for (row = 0; row < rows; ++row) {
-        int col;
+        unsigned int col;
         for (col = 0; col < cols; ++col)
             indexRow[col] = indexOfColor(cht, pixels[row][col]);
 
         if (packbits) {
-            PackBits(indexRow, cols, planesrow, BitsPerPixel);
-            PCXEncode(stdout, planesrow, BytesPerLine);
+            packBits(indexRow, cols, planesrow, bitsPerPixel);
+            pcxEncode(ofP, planesrow, bytesPerLine);
         } else {
             unsigned int plane;
-            for (plane = 0; plane < Planes; ++plane) {
+            for (plane = 0; plane < planes; ++plane) {
                 extractPlane(indexRow, cols, planesrow, plane);
-                PCXEncode(stdout, planesrow, BytesPerLine);
+                pcxEncode(stdout, planesrow, bytesPerLine);
             }
         }
     }
@@ -454,83 +440,142 @@ ppmTo16ColorPcx(pixel **            const pixels,
 
 
 static void
-ppmTo256ColorPcx(pixel **            const pixels, 
-                 int                 const cols, 
-                 int                 const rows, 
-                 struct pcxCmapEntry const pcxcmap[], 
-                 int                 const colors, 
+ppmTo16ColorPcx(pixel **            const pixels,
+                unsigned int        const cols,
+                unsigned int        const rows,
+                struct PcxCmapEntry const pcxcmap[],
+                unsigned int        const colorCt,
+                colorhash_table     const cht,
+                bool                const packbits,
+                unsigned int        const planesRequested,
+                unsigned int        const xPos,
+                unsigned int        const yPos) {
+
+    unsigned int planes;
+    unsigned int bitsPerPixel;
+
+    if (packbits) {
+        planes = 1;
+        if (colorCt > 4)        bitsPerPixel = 4;
+        else if (colorCt > 2)   bitsPerPixel = 2;
+        else                    bitsPerPixel = 1;
+    } else {
+        bitsPerPixel = 1;
+        if (planesRequested)
+            planes = planesRequested;
+        else {
+            if (colorCt > 8)        planes = 4;
+            else if (colorCt > 4)   planes = 3;
+            else if (colorCt > 2)   planes = 2;
+            else                   planes = 1;
+        }
+    }
+
+    writeHeader(stdout, cols, rows, bitsPerPixel, planes, pcxcmap,
+                xPos, yPos);
+
+    writeRaster16Color(stdout, pixels, cols, rows, planes, cht, packbits,
+                       bitsPerPixel);
+}
+
+
+
+static void
+ppmTo256ColorPcx(pixel **            const pixels,
+                 unsigned int        const cols,
+                 unsigned int        const rows,
+                 struct PcxCmapEntry const pcxcmap[],
+                 unsigned int        const colorCt,
                  colorhash_table     const cht,
-                 unsigned int        const xPos, 
+                 unsigned int        const xPos,
                  unsigned int        const yPos) {
 
-    int row;
-    unsigned int i;
-    unsigned char *rawrow;
+    unsigned char * rawrow;
+    unsigned int    row;
+
+    MALLOCARRAY(rawrow, cols);
 
-    rawrow = (unsigned char *)pm_allocrow(cols, sizeof(unsigned char));
+    if (!rawrow)
+        pm_error("Failed to allocate a buffer for %u columns", cols);
 
     /* 8 bits per pixel, 1 plane */
-    write_header(stdout, cols, rows, 8, 1, NULL, xPos, yPos);
+    writeHeader(stdout, cols, rows, 8, 1, NULL, xPos, yPos);
     for (row = 0; row < rows; ++row) {
-        int col;
+        unsigned int col;
         for (col = 0; col < cols; ++col)
             rawrow[col] = indexOfColor(cht, pixels[row][col]);
-        PCXEncode(stdout, rawrow, cols);
+        pcxEncode(stdout, rawrow, cols);
+
     }
-    Putbyte(PCX_256_COLORS, stdout);
-    for (i = 0; i < MAXCOLORS; ++i) {
-        Putbyte(pcxcmap[i].r, stdout);
-        Putbyte(pcxcmap[i].g, stdout);
-        Putbyte(pcxcmap[i].b, stdout);
+    putbyte(PCX_256_COLORS, stdout);
+
+    {
+        unsigned int i;
+
+        for (i = 0; i < MAXCOLORS; ++i) {
+            putbyte(pcxcmap[i].r, stdout);
+            putbyte(pcxcmap[i].g, stdout);
+            putbyte(pcxcmap[i].b, stdout);
+        }
     }
-    pm_freerow((void*)rawrow);
+    free(rawrow);
 }
 
 
 
 static void
-ppmToTruecolorPcx(pixel **     const pixels, 
-                  int          const cols, 
-                  int          const rows, 
+ppmToTruecolorPcx(pixel **     const pixels,
+                  unsigned int const cols,
+                  unsigned int const rows,
                   pixval       const maxval,
-                  unsigned int const xPos, 
+                  unsigned int const xPos,
                   unsigned int const yPos) {
 
-    unsigned char *redrow, *greenrow, *bluerow;
-    int col, row;
+    unsigned char * redrow;
+    unsigned char * grnrow;
+    unsigned char * blurow;
+    unsigned int    row;
+
+    MALLOCARRAY(redrow, cols);
+    MALLOCARRAY(grnrow, cols);
+    MALLOCARRAY(blurow, cols);
 
-    redrow   = (unsigned char *)pm_allocrow(cols, sizeof(unsigned char));
-    greenrow = (unsigned char *)pm_allocrow(cols, sizeof(unsigned char));
-    bluerow  = (unsigned char *)pm_allocrow(cols, sizeof(unsigned char));
+    if (!redrow || !grnrow || !blurow)
+        pm_error("Unable to allocate buffer for a row of %u pixels", cols);
 
     /* 8 bits per pixel, 3 planes */
-    write_header(stdout, cols, rows, 8, 3, NULL, xPos, yPos);
-    for( row = 0; row < rows; row++ ) {
-        register pixel *pP = pixels[row];
-        for( col = 0; col < cols; col++, pP++ ) {
-            if( maxval != PCX_MAXVAL ) {
-                redrow[col]   = (long)PPM_GETR(*pP) * PCX_MAXVAL / maxval;
-                greenrow[col] = (long)PPM_GETG(*pP) * PCX_MAXVAL / maxval;
-                bluerow[col]  = (long)PPM_GETB(*pP) * PCX_MAXVAL / maxval;
-            }
-            else {
-                redrow[col]   = PPM_GETR(*pP);
-                greenrow[col] = PPM_GETG(*pP);
-                bluerow[col]  = PPM_GETB(*pP);
+    writeHeader(stdout, cols, rows, 8, 3, NULL, xPos, yPos);
+
+    for (row = 0; row < rows; ++row) {
+        pixel * const pixrow = pixels[row];
+
+        unsigned int col;
+
+        for (col = 0; col < cols; ++col) {
+            pixel const pix = pixrow[col];
+
+            if (maxval != PCX_MAXVAL) {
+                redrow[col] = (long)PPM_GETR(pix) * PCX_MAXVAL / maxval;
+                grnrow[col] = (long)PPM_GETG(pix) * PCX_MAXVAL / maxval;
+                blurow[col] = (long)PPM_GETB(pix) * PCX_MAXVAL / maxval;
+            } else {
+                redrow[col] = PPM_GETR(pix);
+                grnrow[col] = PPM_GETG(pix);
+                blurow[col] = PPM_GETB(pix);
             }
         }
-        PCXEncode(stdout, redrow, cols);
-        PCXEncode(stdout, greenrow, cols);
-        PCXEncode(stdout, bluerow, cols);
+        pcxEncode(stdout, redrow, cols);
+        pcxEncode(stdout, grnrow, cols);
+        pcxEncode(stdout, blurow, cols);
     }
-    pm_freerow((void*)bluerow);
-    pm_freerow((void*)greenrow);
-    pm_freerow((void*)redrow);
+    free(blurow);
+    free(grnrow);
+    free(redrow);
 }
 
 
 
-static const struct pcxCmapEntry 
+static const struct PcxCmapEntry
 stdPalette[] = {
     {   0,   0,   0 },
     {   0,   0, 170 },
@@ -565,7 +610,7 @@ putPcxColorInHash(colorhash_table const cht,
     int rc;
 
     PPM_DEPTH(ppmColor, newPcxColor, PCX_MAXVAL, maxval);
-        
+
     rc = ppm_lookupcolor(cht, &ppmColor);
 
     if (rc == -1)
@@ -577,8 +622,8 @@ putPcxColorInHash(colorhash_table const cht,
            'maxval' is less than PCX_MAXVAL), and two distinct
            colors in the standard palette are indistinguishable at
            subject image color resolution.
-           
-           So we have to figure out wether color 'newPcxColor' or
+
+           So we have to figure out whether color 'newPcxColor' or
            'existingPcxColor' is a better match for 'ppmColor'.
         */
 
@@ -588,8 +633,8 @@ putPcxColorInHash(colorhash_table const cht,
         pixel existingPcxColor;
 
         PPM_DEPTH(idealPcxColor, ppmColor, maxval, PCX_MAXVAL);
-        
-        PPM_ASSIGN(existingPcxColor, 
+
+        PPM_ASSIGN(existingPcxColor,
                    stdPalette[existingColorIndex].r,
                    stdPalette[existingColorIndex].g,
                    stdPalette[existingColorIndex].b);
@@ -608,19 +653,18 @@ putPcxColorInHash(colorhash_table const cht,
 
 
 static void
-generateStandardPalette(struct pcxCmapEntry ** const pcxcmapP,
+generateStandardPalette(struct PcxCmapEntry ** const pcxcmapP,
                         pixval                 const maxval,
                         colorhash_table *      const chtP,
-                        int *                  const colorsP) {
+                        unsigned int *         const colorsP) {
 
     unsigned int const stdPaletteSize = 16;
-    unsigned int colorIndex;
-    struct pcxCmapEntry * pcxcmap;
-    colorhash_table cht;
+
+    unsigned int          colorIndex;
+    struct PcxCmapEntry * pcxcmap;
+    colorhash_table       cht;
 
     MALLOCARRAY_NOFAIL(pcxcmap, MAXCOLORS);
-    
-    *pcxcmapP = pcxcmap;
 
     cht = ppm_alloccolorhash();
 
@@ -629,8 +673,8 @@ generateStandardPalette(struct pcxCmapEntry ** const pcxcmapP,
             /* The color of this colormap entry, in PCX resolution */
 
         pcxcmap[colorIndex] = stdPalette[colorIndex];
-        
-        PPM_ASSIGN(pcxColor, 
+
+        PPM_ASSIGN(pcxColor,
                    stdPalette[colorIndex].r,
                    stdPalette[colorIndex].g,
                    stdPalette[colorIndex].b);
@@ -648,65 +692,65 @@ generateStandardPalette(struct pcxCmapEntry ** const pcxcmapP,
         pcxcmap[colorIndex].b = 0;
     }
 
+    *pcxcmapP = pcxcmap;
     *chtP = cht;
     *colorsP = stdPaletteSize;
 }
-    
+
 
 
 static void
 readPpmPalette(const char *   const paletteFileName,
-               pixel       (* const ppmPaletteP)[], 
+               pixel       (* const ppmPaletteP)[],
                unsigned int * const paletteSizeP) {
 
     FILE * pfP;
     pixel ** pixels;
     int cols, rows;
     pixval maxval;
-    
+
     pfP = pm_openr(paletteFileName);
 
     pixels = ppm_readppm(pfP, &cols, &rows, &maxval);
 
     pm_close(pfP);
-    
+
     *paletteSizeP = rows * cols;
-    if (*paletteSizeP > MAXCOLORS) 
+    if (*paletteSizeP > MAXCOLORS)
         pm_error("ordered palette image contains %d pixels.  Maximum is %d",
                  *paletteSizeP, MAXCOLORS);
 
     {
-        int j;
-        int row;
-        j = 0;  /* initial value */
-        for (row = 0; row < rows; ++row) {
-            int col;
-            for (col = 0; col < cols; ++col) 
+        unsigned int j;
+        unsigned int row;
+        for (row = 0, j = 0; row < rows; ++row) {
+            unsigned int col;
+            for (col = 0; col < cols; ++col)
                 (*ppmPaletteP)[j++] = pixels[row][col];
         }
     }
     ppm_freearray(pixels, rows);
-}        
+}
 
 
 
 static void
-readPaletteFromFile(struct pcxCmapEntry ** const pcxcmapP,
+readPaletteFromFile(struct PcxCmapEntry ** const pcxcmapP,
                     const char *           const paletteFileName,
                     pixval                 const maxval,
                     colorhash_table *      const chtP,
-                    int *                  const colorsP) {
+                    unsigned int *         const colorsP) {
 
     unsigned int colorIndex;
     pixel ppmPalette[MAXCOLORS];
     unsigned int paletteSize;
-    struct pcxCmapEntry * pcxcmap;
+    struct PcxCmapEntry * pcxcmap;
     colorhash_table cht;
 
     readPpmPalette(paletteFileName, &ppmPalette, &paletteSize);
 
     MALLOCARRAY_NOFAIL(pcxcmap, MAXCOLORS);
-    
+
     *pcxcmapP = pcxcmap;
 
     cht = ppm_alloccolorhash();
@@ -716,8 +760,8 @@ readPaletteFromFile(struct pcxCmapEntry ** const pcxcmapP,
             /* The color of this colormap entry, in PCX resolution */
 
         pcxcmap[colorIndex] = pcxCmapEntryFromPixel(ppmPalette[colorIndex]);
-        
-        PPM_ASSIGN(pcxColor, 
+
+        PPM_ASSIGN(pcxColor,
                    ppmPalette[colorIndex].r,
                    ppmPalette[colorIndex].g,
                    ppmPalette[colorIndex].b);
@@ -728,12 +772,12 @@ readPaletteFromFile(struct pcxCmapEntry ** const pcxcmapP,
     *chtP = cht;
     *colorsP = paletteSize;
 }
-    
+
 
 
 static void
 moveBlackToIndex0(colorhist_vector const chv,
-                  int              const colors) {
+                  unsigned int     const colorCt) {
 /*----------------------------------------------------------------------------
    If black is in the palette, make it at Index 0.
 -----------------------------------------------------------------------------*/
@@ -745,19 +789,20 @@ moveBlackToIndex0(colorhist_vector const chv,
 
     blackPresent = FALSE;  /* initial assumption */
 
-    for (i = 0; i < colors; ++i)
+    for (i = 0; i < colorCt; ++i)
         if (PPM_EQUAL(chv[i].color, blackPixel))
             blackPresent = TRUE;
-            
+
     if (blackPresent) {
         /* We use a trick here.  ppm_addtocolorhist() always adds to the
            beginning of the table and if the color is already elsewhere in
            the table, removes it.
         */
-        int colors2;
-        colors2 = colors;
-        ppm_addtocolorhist(chv, &colors2, MAXCOLORS, &blackPixel, 0, 0);
-        assert(colors2 == colors);
+        int colorCt2;
+
+        colorCt2 = colorCt;
+        ppm_addtocolorhist(chv, &colorCt2, MAXCOLORS, &blackPixel, 0, 0);
+        assert(colorCt2 == colorCt);
     }
 }
 
@@ -765,12 +810,12 @@ moveBlackToIndex0(colorhist_vector const chv,
 
 static void
 makePcxColormapFromImage(pixel **               const pixels,
-                         int                    const cols,
-                         int                    const rows,
+                         unsigned int           const cols,
+                         unsigned int           const rows,
                          pixval                 const maxval,
-                         struct pcxCmapEntry ** const pcxcmapP,
+                         struct PcxCmapEntry ** const pcxcmapP,
                          colorhash_table *      const chtP,
-                         int *                  const colorsP,
+                         unsigned int *         const colorCtP,
                          bool *                 const tooManyColorsP) {
 /*----------------------------------------------------------------------------
    Make a colormap (palette) for the PCX header that can be used
@@ -780,35 +825,35 @@ makePcxColormapFromImage(pixel **               const pixels,
    *pcxcmapP.
 
    Also return a lookup hash to relate a color in the image to the
-   appropriate index in *pcxcmapP.  Return that in newly malloc'ed 
+   appropriate index in *pcxcmapP.  Return that in newly malloc'ed
    storage as *chtP.
 
-   Iff there are too many colors to do that (i.e. more than 256), 
+   Iff there are too many colors to do that (i.e. more than 256),
    return *tooManyColorsP == TRUE.
 -----------------------------------------------------------------------------*/
-    int colors;
+    int colorCt;
     colorhist_vector chv;
 
     pm_message("computing colormap...");
 
-    chv = ppm_computecolorhist(pixels, cols, rows, MAXCOLORS, &colors);
+    chv = ppm_computecolorhist(pixels, cols, rows, MAXCOLORS, &colorCt);
     if (chv == NULL)
         *tooManyColorsP = TRUE;
     else {
-        int i;
-        struct pcxCmapEntry * pcxcmap;
+        unsigned int i;
+        struct PcxCmapEntry * pcxcmap;
 
         *tooManyColorsP = FALSE;
 
-        pm_message("%d colors found", colors);
-        
-        moveBlackToIndex0(chv, colors);
+        pm_message("%d colors found", colorCt);
+
+        moveBlackToIndex0(chv, colorCt);
 
         MALLOCARRAY_NOFAIL(pcxcmap, MAXCOLORS);
 
         *pcxcmapP = pcxcmap;
 
-        for (i = 0; i < colors; ++i) {
+        for (i = 0; i < colorCt; ++i) {
             pixel p;
 
             PPM_DEPTH(p, chv[i].color, maxval, PCX_MAXVAL);
@@ -825,9 +870,9 @@ makePcxColormapFromImage(pixel **               const pixels,
             pcxcmap[i].b = 0;
         }
 
-        *chtP = ppm_colorhisttocolorhash(chv, colors);
+        *chtP = ppm_colorhisttocolorhash(chv, colorCt);
 
-        *colorsP = colors;
+        *colorCtP = colorCt;
 
         ppm_freecolorhist(chv);
     }
@@ -835,45 +880,45 @@ makePcxColormapFromImage(pixel **               const pixels,
 
 
 
-static void 
-ppmToPalettePcx(pixel **            const pixels, 
-                int                 const cols, 
-                int                 const rows,
+static void
+ppmToPalettePcx(pixel **            const pixels,
+                unsigned int        const cols,
+                unsigned int        const rows,
                 pixval              const maxval,
-                unsigned int        const xPos, 
+                unsigned int        const xPos,
                 unsigned int        const yPos,
-                struct pcxCmapEntry const pcxcmap[],
+                struct PcxCmapEntry const pcxcmap[],
                 colorhash_table     const cht,
-                int                 const colors,
+                unsigned int        const colorCt,
                 bool                const packbits,
                 unsigned int        const planes,
-                bool                const use_8_bit) {
-    
+                bool                const use8Bit) {
+
     /* convert image */
-    if( colors <= 16 && !use_8_bit )
-        ppmTo16ColorPcx(pixels, cols, rows, pcxcmap, colors, cht, 
+    if (colorCt <= 16 && !use8Bit )
+        ppmTo16ColorPcx(pixels, cols, rows, pcxcmap, colorCt, cht,
                         packbits, planes, xPos, yPos);
     else
-        ppmTo256ColorPcx(pixels, cols, rows, pcxcmap, colors, cht,
+        ppmTo256ColorPcx(pixels, cols, rows, pcxcmap, colorCt, cht,
                          xPos, yPos);
 }
 
 
 
 int
-main(int argc, char *argv[]) {
+main(int argc, const char *argv[]) {
 
-    struct cmdlineInfo cmdline;
-    FILE* ifP;
+    struct CmdlineInfo cmdline;
+    FILE * ifP;
     int rows, cols;
     pixval maxval;
     pixel **pixels;
-    struct pcxCmapEntry * pcxcmap;
+    struct PcxCmapEntry * pcxcmap;
     colorhash_table cht;
     bool truecolor;
-    int colors;
+    unsigned int colorCt;
 
-    ppm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
@@ -886,17 +931,17 @@ main(int argc, char *argv[]) {
     else {
         if (cmdline.stdpalette) {
             truecolor = FALSE;
-            generateStandardPalette(&pcxcmap, maxval, &cht, &colors);
+            generateStandardPalette(&pcxcmap, maxval, &cht, &colorCt);
         } else if (cmdline.palette) {
             truecolor = FALSE;
-            readPaletteFromFile(&pcxcmap, cmdline.palette, maxval, 
-                                &cht, &colors);
+            readPaletteFromFile(&pcxcmap, cmdline.palette, maxval,
+                                &cht, &colorCt);
         } else {
             bool tooManyColors;
             makePcxColormapFromImage(pixels, cols, rows, maxval,
-                                     &pcxcmap, &cht, &colors,
+                                     &pcxcmap, &cht, &colorCt,
                                      &tooManyColors);
-            
+
             if (tooManyColors) {
                 pm_message("too many colors - writing a 24bit PCX file");
                 pm_message("if you want a non-24bit file, "
@@ -908,16 +953,19 @@ main(int argc, char *argv[]) {
     }
 
     if (truecolor)
-        ppmToTruecolorPcx(pixels, cols, rows, maxval, 
+        ppmToTruecolorPcx(pixels, cols, rows, maxval,
                           cmdline.xpos, cmdline.ypos);
     else {
-        ppmToPalettePcx(pixels, cols, rows, maxval, 
+        ppmToPalettePcx(pixels, cols, rows, maxval,
                         cmdline.xpos, cmdline.ypos,
-                        pcxcmap, cht, colors, cmdline.packed, 
-                        cmdline.planes, cmdline.use_8_bit);
-        
+                        pcxcmap, cht, colorCt, cmdline.packed,
+                        cmdline.planes, cmdline.use8Bit);
+
         ppm_freecolorhash(cht);
         free(pcxcmap);
     }
     return 0;
 }
+
+
+
diff --git a/converter/ppm/ppmtospu.c b/converter/ppm/ppmtospu.c
index b558c1fe..a6acbaa0 100644
--- a/converter/ppm/ppmtospu.c
+++ b/converter/ppm/ppmtospu.c
@@ -292,7 +292,7 @@ computePalette(struct PixelType * const pixelType) {
 
     /* Uses popularity algorithm */
 
-    /* Count the occurences of each color */
+    /* Count the occurrences of each color */
 
     for (i = 0; i < 512; ++i)
         hist[i] = 0;
diff --git a/converter/ppm/sldtoppm.c b/converter/ppm/sldtoppm.c
index 2dc049f8..2fef0233 100644
--- a/converter/ppm/sldtoppm.c
+++ b/converter/ppm/sldtoppm.c
@@ -600,7 +600,7 @@ slider(slvecfn   slvec,
             curcolor = cw & 0xFF;
             break;
 
-        default:              /*  Co-ordinates  */
+        default:              /*  Coordinates  */
             lx = vec.f.x = cw;
             ly = vec.f.y = sli();
             vec.t.x = sli();
diff --git a/converter/ppm/xim.h b/converter/ppm/xim.h
index 70a9a761..116312bb 100644
--- a/converter/ppm/xim.h
+++ b/converter/ppm/xim.h
@@ -6,7 +6,7 @@
 ** Taken from the X.V11R4 version of XimHeader.h:
 **
 ** Author: Philip R. Thompson
-** Address:  phils@athena.mit.edu, 9-526 
+** Address:  phils@athena.mit.edu, 9-526
 ** Note:  size of header should be 1024 (1K) bytes.
 ** $Header: /mit/phils/X/RCS/XimHeader.h,v 1.7 89/11/09 17:26:54 phils Exp Locker: phils $
 ** $Date: 89/11/09 17:26:54 $
@@ -24,7 +24,7 @@ typedef struct ImageHeader {
     char file_version[8];   /* header version */
     char header_size[8];    /* Size of file header in bytes  */
     char image_width[8];    /* Width of the raster image */
-    char image_height[8];   /* Height of the raster imgage */
+    char image_height[8];   /* Height of the raster image */
     char num_colors[8];     /* Actual number of entries in c_map */
     char num_channels[3];   /* 0 or 1 = pixmap, 3 = RG&B buffers */
     char bytes_per_line[5]; /* bytes per scanline */
@@ -63,9 +63,9 @@ typedef struct XimImage {
     short tpics, npics;    /* number of images, total & left in file */
     short ncolors;         /*   "    "  colors in the color table */
     Color* colors;         /* colortable, one byte per r/g/b & pixel */
-    const char* author;    /* author credit, copyright, etc */
-    const char* date;      /* date image was made, grabbed, etc. */
-    const char* program;   /* program used to make this */
+    const char* author;         /* author credit, copyright, etc */
+    const char* date;           /* date image was made, grabbed, etc. */
+    const char* program;        /* program used to make this */
     short ncomments;       /* number of comments strings */
     char** comments;      /* pointers to null terminated strings */
     char* offset;         /* original offset in machine memory */
@@ -81,7 +81,7 @@ typedef struct XimImage {
 typedef struct XimAsciiHeader {
     char file_version[4];   /* header version */
     char header_size[8];    /* Size of file header (fixed part only) */
-    char image_height[8];   /* Height of the raster imgage in pixels */
+    char image_height[8];   /* Height of the raster image in pixels */
     char image_width[8];    /* Width of the raster image in pixels */
     char bytes_line[8];     /* Actual # of bytes separating scanlines */
     char bits_channel[4];   /* Bits per channel (usually 1 or 8) */
@@ -111,7 +111,7 @@ typedef struct XimAsciiHeader {
 
 /* Note:
 * - All data is in char's in order to maintain easily portability
-*   across machines, and some human readibility.
+*   across machines, and some human readability.
 * - Images may be stored as pixmaps (8 bits/pixel) or as separate
 *   red, green, blue channel data (24+ bits/pixel).
 * - An alpha channel is optional and is found after every num_channels
diff --git a/converter/ppm/ximtoppm.c b/converter/ppm/ximtoppm.c
index 92b123f6..d839e770 100644
--- a/converter/ppm/ximtoppm.c
+++ b/converter/ppm/ximtoppm.c
@@ -22,7 +22,9 @@
 #include "shhopt.h"
 #include "nstring.h"
 
-struct cmdlineInfo {
+
+
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -34,8 +36,8 @@ struct cmdlineInfo {
 
 
 static void
-parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo *cmdlineP) {
+parseCommandLine(int argc, const char ** argv,
+                 struct CmdlineInfo *cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that many of the strings that this function returns in the
    *cmdlineP structure are actually in the supplied argv array.  And
@@ -50,14 +52,14 @@ parseCommandLine(int argc, char ** argv,
     unsigned int alphaoutSpec;
 
     option_def_index = 0;   /* incremented by OPTENT3 */
-    OPTENT3(0,   "alphaout",   OPT_STRING, 
+    OPTENT3(0,   "alphaout",   OPT_STRING,
             &cmdlineP->alpha_filename, &alphaoutSpec, 0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char**)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and all of *cmdlineP. */
 
     if (!alphaoutSpec)
@@ -67,21 +69,21 @@ parseCommandLine(int argc, char ** argv,
         cmdlineP->input_filename = "-";  /* he wants stdin */
     else if (argc - 1 == 1)
         cmdlineP->input_filename = strdup(argv[1]);
-    else 
+    else
         pm_error("Too many arguments.  The only argument accepted "
                  "is the input file specification");
 
-    if (cmdlineP->alpha_filename && 
+    if (cmdlineP->alpha_filename &&
         streq(cmdlineP->alpha_filename, "-"))
         cmdlineP->alpha_stdout = TRUE;
-    else 
+    else
         cmdlineP->alpha_stdout = FALSE;
 }
 
 
 
 /* The subroutines are excerpted and slightly modified from the
-   X.V11R4 version of xim_io.c. 
+   X.V11R4 version of xim_io.c.
 */
 
 static int
@@ -100,6 +102,11 @@ ReadXimHeader(FILE *     const in_fp,
         pm_message("ReadXimHeader: unable to read file header" );
         return(0);
     }
+    /* Force broken ASCIIZ strings to at least be valid ASCIIZ */
+    a_head.author [sizeof(a_head.author)  - 1] = '\0';
+    a_head.date   [sizeof(a_head.date)    - 1] = '\0';
+    a_head.program[sizeof(a_head.program) - 1] = '\0';
+
     if (atoi(a_head.header_size) != sizeof(ImageHeader)) {
         pm_message("ReadXimHeader: header size mismatch" );
         return(0);
@@ -113,14 +120,16 @@ ReadXimHeader(FILE *     const in_fp,
     header->ncolors = atoi(a_head.num_colors);
     header->nchannels = atoi(a_head.num_channels);
     header->bytes_per_line = atoi(a_head.bytes_per_line);
-/*    header->npics = atoi(a_head.num_pictures);
-*/
+#if 0
+    header->npics = atoi(a_head.num_pictures);
+#endif
     header->bits_channel = atoi(a_head.bits_per_channel);
     header->alpha_flag = atoi(a_head.alpha_channel);
     header->author = pm_strdup(a_head.author);
     header->date = pm_strdup(a_head.date);
     header->program = pm_strdup(a_head.program);
-    /* Do double checking for bakwards compatibility */
+
+    /* Do double checking for backwards compatibility */
     if (header->npics == 0)
         header->npics = 1;
     if (header->bits_channel == 0)
@@ -130,7 +139,7 @@ ReadXimHeader(FILE *     const in_fp,
         header->bits_channel = 8;
     }
     if ((int)header->bytes_per_line == 0)
-        header->bytes_per_line = 
+        header->bytes_per_line =
             (header->bits_channel == 1 && header->nchannels == 1) ?
                 (header->width + 7) / 8 :
                 header->width;
@@ -186,9 +195,10 @@ ReadImageChannel(FILE *         const infp,
             }
             marker += i;
         }
-        /* return to the beginning of the next image's bufffer */
+        /* return to the beginning of the next image's buffer */
         if (fseek(infp, marker, 0) == -1) {
-            pm_message("ReadImageChannel: can't fseek to location in image buffer" );
+            pm_message("ReadImageChannel: can't fseek to location "
+                       "in image buffer");
             return(0);
         }
         free((char *)line);
@@ -271,7 +281,7 @@ ReadXimImage(FILE *     const in_fp,
 *  Author: Philip Thompson
 *  $Date: 89/11/01 10:14:23 $
 *  $Revision: 1.14 $
-*  Purpose: General xim libray of utililities
+*  Purpose: General xim library of utililities
 *  Copyright (c) 1988  Philip R. Thompson
 *                Computer Resource Laboratory (CRL)
 *                Dept. of Architecture and Planning
@@ -297,28 +307,26 @@ ReadXimImage(FILE *     const in_fp,
 ***********************************************************************/
 
 static int
-ReadXim(in_fp, xim)
-    FILE *in_fp;
-    XimImage *xim;
-{
+ReadXim(FILE *     const in_fp,
+        XimImage * const xim) {
+
     if (!ReadXimHeader(in_fp, xim)) {
         pm_message("can't read xim header" );
-    return(0);
-    }
-    if (!ReadXimImage(in_fp, xim)) {
+        return 0;
+    } else if (!ReadXimImage(in_fp, xim)) {
         pm_message("can't read xim data" );
-    return(0);
-    }
-    return(1);
+        return 0;
+    } else
+        return 1;
 }
 
 
 
 int
-main(int argc,
-     char *argv[]) {
+main(int          argc,
+     const char **argv) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     FILE *ifP, *imageout_file, *alpha_file;
     XimImage xim;
     pixel *pixelrow, colormap[256];
@@ -330,24 +338,24 @@ main(int argc,
     pixval maxval;
     bool success;
 
-    ppm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
-    
+
     ifP = pm_openr(cmdline.input_filename);
-    
+
     if (cmdline.alpha_stdout)
         alpha_file = stdout;
-    else if (cmdline.alpha_filename == NULL) 
+    else if (cmdline.alpha_filename == NULL)
         alpha_file = NULL;
     else
         alpha_file = pm_openw(cmdline.alpha_filename);
-    
-    if (cmdline.alpha_stdout) 
+
+    if (cmdline.alpha_stdout)
         imageout_file = NULL;
     else
         imageout_file = stdout;
-    
+
     success = ReadXim(ifP, &xim);
     if (!success)
         pm_error("can't read Xim file");
@@ -374,7 +382,7 @@ main(int argc,
             "unknown Xim file type, nchannels == %d, bits_channel == %d",
             xim.nchannels, xim.bits_channel);
 
-    if (imageout_file) 
+    if (imageout_file)
         ppm_writeppminit(imageout_file, cols, rows, maxval, 0);
     if (alpha_file)
         pgm_writepgminit(alpha_file, cols, rows, maxval, 0);
@@ -386,8 +394,8 @@ main(int argc,
         if (mapped) {
             byte * const ximrow = xim.data + row * xim.bytes_per_line;
             unsigned int col;
-            
-            for (col = 0; col < cols; ++col) 
+
+            for (col = 0; col < cols; ++col)
                 pixelrow[col] = colormap[ximrow[col]];
             alpharow[col] = 0;
         } else {
@@ -403,11 +411,11 @@ main(int argc,
                            redrow[col], grnrow[col], blurow[col]);
                 if (xim.nchannels > 3)
                     alpharow[col] = othrow[col];
-                else 
+                else
                     alpharow[col] = 0;
             }
         }
-        if (imageout_file) 
+        if (imageout_file)
             ppm_writeppmrow(imageout_file, pixelrow, cols, maxval, 0);
         if (alpha_file)
             pgm_writepgmrow(alpha_file, alpharow, cols, maxval, 0);
@@ -420,3 +428,6 @@ main(int argc,
 
     return 0;
 }
+
+
+
diff --git a/converter/ppm/xpmtoppm.README b/converter/ppm/xpmtoppm.README
index b5e254fa..0a32113c 100644
--- a/converter/ppm/xpmtoppm.README
+++ b/converter/ppm/xpmtoppm.README
@@ -49,7 +49,7 @@ xpmtoppm.c:
   - Now understands multword X11 color names
   
   - Now reads multiple color keys. Takes the color
-    of the hightest available key. Lines no longer need
+    of the highest available key. Lines no longer need
     to begin with key 'c'.
     
   - expanded line buffer to from 500 to 2048 for bigger files
diff --git a/converter/ppm/xpmtoppm.c b/converter/ppm/xpmtoppm.c
index 46101a09..c97b9fdc 100644
--- a/converter/ppm/xpmtoppm.c
+++ b/converter/ppm/xpmtoppm.c
@@ -544,7 +544,7 @@ interpretXpm3ColorTableLine(char               const line[],
                     addToColorMap(hashP, colorName, curbuf, isTransparent);
                     highkey = curkey;
                 }
-                /* intialize state to process this new key */
+                /* initialize state to process this new key */
                 curkey = key;
                 curbuf[0] = '\0';
                 isTransparent = FALSE;
@@ -606,7 +606,7 @@ readXpm3Header(FILE *             const ifP,
                ColorNameHash **   const colorNameHashPP) {
 /*----------------------------------------------------------------------------
   Read the header of the XPM file on stream *ifP.  Assume the
-  getLine() stream is presently positioned to the beginning of the
+  getLine() stream is currently positioned to the beginning of the
   file and it is a Version 3 XPM file.  Leave the stream positioned
   after the header.
 
@@ -721,7 +721,7 @@ readXpm1Header(FILE *           const ifP,
                ColorNameHash ** const colorNameHashPP) {
 /*----------------------------------------------------------------------------
   Read the header of the XPM file on stream *ifP.  Assume the
-  getLine() stream is presently positioned to the beginning of the
+  getLine() stream is currently positioned to the beginning of the
   file and it is a Version 1 XPM file.  Leave the stream positioned
   after the header.
 
@@ -1074,7 +1074,7 @@ main(int argc, char *argv[]) {
 **  - Now understands multiword X11 color names
 **
 **  - Now reads multiple color keys. Takes the color
-**    of the hightest available key. Lines no longer need
+**    of the highest available key. Lines no longer need
 **    to begin with key 'c'.
 **
 **  - expanded line buffer to from 500 to 2048 for bigger files
diff --git a/doc/COPYRIGHT.PATENT b/doc/COPYRIGHT.PATENT
index 24b1583a..5e4db7d7 100644
--- a/doc/COPYRIGHT.PATENT
+++ b/doc/COPYRIGHT.PATENT
@@ -25,6 +25,13 @@ at appropriate places within the package.  A slightly out of date
 summary of all the copyrights is in the file 'doc/copyright_summary'
 in the Netpbm source tree.
 
+Each component is a package of code and documentation; e.g. the 'pamcomp'
+program and the pamcomp user manual go together and are licensed to the public
+as a package.  The Netpbm manual is just a hyperlinked collection of such
+component manuals.  Parts of the manual that are not tied to a particular
+component of code and do not carry a copyright notice are in the public
+domain.
+
 As with most public open source software, no one really knows for sure
 where the code came from.  It is possible that a contributor copied it
 without license to do so.  That might mean any user of the code owes
@@ -35,6 +42,6 @@ maintainer's knowledge."
 
 
 Netpbm may practice valid patents, which would mean that you owe someone
-royalties if you use the code.  This is a miniscule risk, though.
+royalties if you use the code.  This is a minuscule risk, though.
 What is known about patents related to Netpbm is in the file
 'doc/patent_summary' in the Netpbm source tree.
diff --git a/doc/HISTORY b/doc/HISTORY
index 55a5e9db..0c2ce263 100644
--- a/doc/HISTORY
+++ b/doc/HISTORY
@@ -4,20 +4,33 @@ Netpbm.
 CHANGE HISTORY 
 --------------
 
-23.03.25 BJH  Release 10.86.38
+23.03.25 BJH  Release 11.02.00
+
+              jpegtopnm: Add -traceexif
+
+              pbmtextps: Add -asciihex, -ascii85.
+
+              pcdovtoppm: remove dependency on obsolete 'tempfile' program.
 
               jpegtopnm: Many fixes to -dumpexif.  Always broken.
               (-dumpexif was new in Netpbm 9.18 (September 2001))
 
-23.03.14 BJH  Release 10.86.37
-
               pamtopng: fix -chroma option: always rejected.  Always broken.
-              pamtopng was new in Netpbm 10.70 (June 2015).
+              (pamtopng was new in Netpbm 10.70 (June 2015)).
 
               pnmtopng: fix -rgb option: always rejected.  Always broken
-              -rgb was new in Netpbm 10.30 (October 2005).
+              (-rgb was new in Netpbm 10.30 (October 2005)).
+
+              build: change the way you add the separately distributed
+              'hpcdtoppm' code to the build.
+
+22.12.31 BJH  Release 11.01.00
+
+              pamcat: Add -listfile .
 
-22.12.24 BJH  Release 10.86.36
+              pamtojpeg2k: add -size option.  Doesn't precisely work (and
+              -compression has never worked precisely either); should be
+              fixed some day.
 
               ppmtompeg: Fix crash with resize option because of invalid
               memory free.
@@ -25,15 +38,27 @@ CHANGE HISTORY
               fitstopnm: fix invalid memory reference (nonterminated ASCIIZ
               string).
 
-22.09.24 BJH  Release 10.86.35
+              packaging: Fix library minor number to 100 + Netpbm minor number
+              so it is higher than previous ones in library major 100.
+              I.e. libnetpbm.so.100.101 instead of libnetpbm.so.100.1.
+              Introduced in Netpbm 11.00.00.
 
-              pnmindex: fix shell injection vulnerabilities.  Broken since
-              Netpbm 10.28 (June 2005).
+22.09.28 BJH  Release 11.00.00
 
-              pnmmargin: fix shell injection vulneraibility.  Always broken
-              (Program was added in primordial Netpbm in 1990).
+              (No significance to new major number; just ran out of 2-digit
+              minor numbers).
+
+              Add pamcat.
+
+              pamtable: add -tuple.
+
+              pamtable: add -hex.
 
-22.07.17 BJH  Release 10.86.34
+              pbmtextps: improve error messages.
+
+              pnmtofits: fix arbitrary behavior when FITS input lacks
+              required fields in header.  Always broken.  Pnmtofits'
+              predecessor was in primordial Netpbm (1989).
 
               ppmtoicr: Fix bug: all options cause bogus command line parsing
               errors.  Always broken.  Ppmtoicr was new in 1991.
@@ -43,6 +68,25 @@ CHANGE HISTORY
               ppmtoicr: make -rle option issue an error message saying it no
               longer exists (it did, sort of, before 2015).
 
+              ppmforge: Fix arbitrary output with really large -power.
+              
+              pnmindex: fix shell injection vulnerabilities.  Broken since
+              Netpbm 10.28 (June 2005).
+
+              pnmmargin: fix shell injection vulnerability.  Always broken
+              (Program was added in primordial Netpbm in 1990).
+
+              build: Create backward compatibility symbolic link for
+              pnminterp-gen, missing for over 20 years.
+
+22.06.24 BJH  Release 10.99.00
+
+              Add pamrestack.
+
+              Add pamshuffle.
+
+              Add pamtoqoi, qoitopam.
+
               palmtopnm: Fix failure with bogus claim of invalid input on
               architectures that do not use two's complement negative numbers.
               Always broken.  (Ability to convert PackBits input was new in
@@ -55,7 +99,17 @@ CHANGE HISTORY
               pamdice: Fix incorrect output file name with PAM input.  Always
               broken (pamdice was new in Netpbm 9.25 (March 2002).
 
-22.03.20 BJH  Release 10.86.32
+              libnetpbm: Stop bogus runtime error check failure in pmfileio.c
+              shifts.
+
+22.03.27 BJH  Release 10.98.00
+
+              pamtopdbimg: Add -fixedtime.
+
+              ppmfade: Use temporary files securely.
+              
+              pnmtosir: Set some possibly meaningless bits in output to zero
+              so output is repeatable.
 
               pamx: Fix bug: top-justifies image in all cases where it should
               bottom-justify.  Always broken.  (pamx was new in Netpbm 10.34
@@ -67,15 +121,21 @@ CHANGE HISTORY
               output on depth 1 input.  Always broken.  (pamsistoaglyph was
               new in Netpbm 10.47 (June 2009).  Thanks Scott Pakin.
 
-              pambayer: Fix bogus colors at edges.  Always broken (pambayer
+              pambayer: Fix bogus colors at edges.  Always Broken (pambayer
               was new in Release 10.30 (October 2005)).
 
-22.02.13 BJH  Release 10.86.31
-
               libnetpbm, various programs: fix bug: bogus warning that a color
               specified on command line cannot be represented exactly with the
               maxval being used.  Introduced in Netpbm 10.83 (June 2018).
 
+              pnmtopsnr: Fix typo in error message.  Always broken (pnmpsnr
+              was new in Netpbm 9.6 (July 2000).
+
+              ppmtoilbm: Remove -floyd (aka -fs) option, which hasn't worked
+              in a long time if ever and is inappropriate function for this
+              program.  And the broken code is inconsistent with new random
+              number logic elsewhere in the package.
+
               ppmtoapplevol: Fix bug: reads from Standard Input even when you
               specify the input file argument.  Always broken.  (ppmtoapplevol
               was new in Netpbm 10.54 (March 2011).
@@ -84,20 +144,9 @@ CHANGE HISTORY
               than 255.  Always broken.  (ppmtoapplevol was new in Netpbm
               10.54 (March 2011).
 
-22.01.25 BJH  Release 10.86.30
+              pgmmedian: fix crash when median matrix is wider or higher than
+              the input image.
 
-              pgmabel: Fix incorrect output.  Always broken.  (Program was
-              new in Netpbm 10.3 (July 2002).
-
-              libnetpbm: Fix version number
-
-22.01.24 BJH  Release 10.86.29
-
-              picttoppm:  Fix inability to compile introduced in Netpbm
-              10.86.28 (2 days ago).
-
-22.01.22 BJH  Release 10.86.28
- 
               picttoppm: Fix incorrect output for 32 bit per pixel images
               that have only 3 planes.  Broken in Netpbm 10.34 (June 2006).
 
@@ -110,14 +159,37 @@ CHANGE HISTORY
               pgmtexture: Fix incorrect output.  Always broken.  (Program was
               added in primordial Netpbm in 1991).
               
-21.11.28 BJH  Release 10.86.27
+              pgmabel: Fix incorrect output.  Always broken.  (Program was
+              new in Netpbm 10.3 (July 2002).
+
+              Remove Floyd-Steinberg dithering functions (ppm_fs_*) from
+              libnetpbm (libppmfloyd).  No longer used.  Floyd-Steinberg
+              dithering logic can be found in pnmremap.  libppmfloyd
+              was previously used by ppmtoilbm.
+
+21.12.27 BJH  Release 10.97.00
+
+              Add pbmnoise.
+
+              pnmpad: Use -halign with -mwidth and default to centering the
+              image instead of left-justifying when no other padding is being
+              added.  Same with -mheight, -valign, and top-justifying.
+
+              xwdtopnm: Add ability to process bit depth 32.
+
+              pgmtoppm: Add -black, -white.
+
+              ppmpat: Add -mesh.
+
+              pampaintspill: Add -near.  Thanks Scott Pakin.
+
+              pamtogif: Fix bug: doesn't ignore the input alpha mask when user
+              specified -transparent.  Broken in Netpbm 10.37 (December 2006).
 
               palmtopnm: Fix bug: fails with PackBits input on platform with
               default unsigned char, such as ppc64.  Always broken.  (Ability
               to convert PackBits input was new in Netpbm 10.27 (March 2005).
               
-21.11.19 BJH  Release 10.86.26
-
               pamrubber: Fix bug: random behavior with -quad when you specify
               both points for source or target and the second one is lower in
               the image than the first.  Always broken (Pamrubber was new in
@@ -127,31 +199,27 @@ CHANGE HISTORY
               pnmcat, pnmpad: Fix arithmetic overrun with ridiculously large
               image.
 
-21.10.17 BJH  Release 10.86.25
+              pbmclean: Fix overallocation of memory (waste).
 
-              pamtogif: Fix bug: doesn't ignore the input alpha mask when user
-              specified -transparent.  Broken in Netpbm 10.37 (December 2006).
+              libnetbm: Add pnm_writepamrowpart, pnm_formatPamtuples.
 
               libnetpbm: When validating computable size of width and height,
               allow for adding up to 10 instead of 2, to account for rounding
               up to a multiple of 8 in processing bit maps.
 
-21.08.30 BJH  Release 10.86.24
+              Build: Don't attempt to build 'pamexec' on systems without
+              Unix process management.  Bug introduced in Netpbm 10.94
+              (March 2021) and supposedly fixed in 10.95, but not really.
 
-              ximtoppm: Fix bug: invalid memory references with pathological
-              image input.  Broken in Netpbm 86.15 (June 2020).
+21.09.25 BJH  Release 10.96.00
 
-21.06.30 BJH  Release 10.86.23
+              pgmtoppm: Eliminate dependency on color dictionary when user
+              does not specify any colors by name.
 
-              pamtopng: Fix -transparent option - program recognized
-              -transparency instead.  Always broken (pamtopng was new in
-              Netpbm 10.71 (June 2015)).
-
-              Build: make it work on systems that don't have date +%s.  Broken
-              in Netpbm 10.78 (March 2017).  Thanks Claes Nästén
-              (pekdon@gmail.com).
+              pamstereogram: Fix crash with -xbegin=0.  Thanks Scott Pakin.
+              Introduced in Netpbm 10.94.
 
-21.05.15 BJH  Release 10.86.22
+21.06.30 BJH  Release 10.95.00
 
               pamtopng: Fix rejection of all BLACKANDWHITE_ALPHA images with
               message about wrong depth.  Always broken (pamtopng was new in
@@ -166,41 +234,68 @@ CHANGE HISTORY
               BLACKANDWHITE.  Always broken (pamtopng was new in Netpbm 10.71
               (June 2015)).
 
+              pamtopng: Fix -transparent option - program recognized
+              -transparency instead.  Always broken (pamtopng was new in
+              Netpbm 10.71 (June 2015)).
+
               pamtogif: Fix failure with bogus message about wrong depth with
               grayscale and black and white PAM images with transparency.
               Always broken (pamtogif was new in Netpbm 10.37 (December 2006)).
               Thanks Karol Kosek <krkk@krkk.ct8.pl>.
 
-21.04.11 BJH  Release 10.86.21
+              ppmtogif: Same as 'pamtogif' fix above, but with -alpha option.
+              
+              Build: Fix build failure due to missing 'random' function on
+              Mingw platform.  Bug introduced in Netpbm 10.94 (March 2021).
 
-              Build: fix failure of pammixmulti to compile for Mingw for lack
-              of drand48.  Always broken (pammixmulti was new in Netpbm 10.85
-              (December 2018)).
+              Build: Don't attempt to build 'pamexec' on systems without
+              Unix process management.  Bug introduced in Netpbm 10.94
+              (March 2021).
 
-              make package: fix no such file pcdovtoppm.exe failure on
-              Windows.
+              Build: Make it work on systems that don't have date +%s.  Broken
+              in Netpbm 10.78 (March 2017).  Thanks Claes Nästén
+              (pekdon@gmail.com).
+
+              Build: Fix for MacOS build failures with missing sprintf and
+              vasprintf in broken build environment.
+              
+              Mkdeb: fix failure with message about unrecognized format of
+              VERSION file.  Introduced in Netpbm 10.90 (March 2020).
+
+21.03.27 BJH  Release 10.94.00
+
+              Add pamhomography:  Thanks Scott Pakin.
+
+              pamstereogram: Add -yfillshift .
+
+              pamtowinicon: Add BMP/PNG encoding to verbose output.
 
-21.03.21 BJH  Release 10.86.20
+              Use internal random number generator everywhere random numbers
+              are used except ppmtoilbm, so seeded results are the same on
+              all platforms.
 
-              pnmtopng: fix incorrect transparency in output when requesting
+              pamexec: Issue message instead of being killed by a signal when
+              the exec'ed program does not read the whole image"
+
+              ppmforge: Fail if -dimension is greater than 5, which is
+              useless.
+
+              pamscale: Fix bogus "bad magic number" or similar failure most
+              of the time with -nomix.  Broken since Netpbm 10.49 (December
+              2009).
+
+              pnmtopng: Fix incorrect transparency in output when requesting
               transparency.  Introduced after Netpbm 10.35 (August 2006) but
               not after Netpbm 10.47 (June 2009).
 
-              pnmtopng: fix buffer overrun or bogus "too many color/
+              pnmtopng: Fix buffer overrun or bogus "too many color/
               transparency pairs" failure when requesting transparency.
               Introduced after Netpbm 10.26 (January 2005) but not after
               Netpbm 10.35 (August 2006).
 
-              pnmtops: Fix incorrect output (arithmetic overflow) when
-              bounding box is exactly INT_MAX high or wide.  Always broken.
-              Pnmtops was in primordial Netpbm.
-
-21.03.07 BJH  Release 10.86.19
+              pamtojpeg2k: Fix constant failure with message about file
+              close failing.
 
-              pamscale: fix bogus "bad magic number" or similar failure most
-              of the time with -nomix.  Broken since Netpbm 10.49 (December
-              2009).
-              
               libnetpbm: pm_system: Fix bug: standard input feeder process
               repositions unrelated files.  Always broken (pm_system was new
               in Netpbm 10.13 (September 2003).
@@ -209,20 +304,60 @@ CHANGE HISTORY
               (result of pm_system bug above).  Always broken (Pamtowinicon
               was new in Netpbm 10.63 (June 2013).
 
-20.12.08 BJH  Release 10.86.18
+              pnmtopng: Fix trivial memory leaks.
+
+              pnmtops: Fix incorrect output (arithmetic overflow) when
+              bounding box is exactly INT_MAX high or wide.  Always broken.
+              Pnmtops was in primordial Netpbm.
+
+              make package: fix no such file pcdovtoppm.exe failure on
+              Windows.
+
+20.12.28 BJH  Release 10.93.00
+
+              pamarith: Add -equal.
+
+              pamarith: Allow more than two operands for functions for which
+              it makes sense (all but -subtract, -difference, -compare,
+              -divide, -shiftleft, and -shiftright).
 
-              pamarith: Fix bug: fails with more than two operands for
-              -mulitply, -minimum, -maximum, -nand, and -nor.
+              pamarith: fail if operand images have different depth and not
+              depth 1.
+
+              ppmshift: Add -seed .
+
+              pamaddnoise: Fix incorrect output for -type poisson.  Always
+              broken.  (pamaddnoise's precursor pnmaddnoies was new to Netpbm
+              in Netpbm 10.29 (August 2005)).
 
               pamaddnoise: fix bug: garbage output with -type impulse.  Always
-              broken (pamaddnoise's precursors pnmaddnoise was new to Netpbm
-              in Netpbm 10.29 (August 2005).
+              broken (pamaddnoise's precursor pnmaddnoise was new to Netpbm
+              in Netpbm 10.29 (August 2005)).
+
+20.09.26 BJH  Release 10.92.00
+
+              pnmcrop: Make -margin effective with -blank-image=minimize.
 
-20.09.26 BJH  Release 10.86.17
+              pnmnorm: With bounds specified as -bpercent or -bsingle and
+              -wpercent or -wsingle, and the image has only one brightness,
+              don't attempt any normalization - leave image as is.  (Previous
+              version produces all black with -keephues).
+
+              pgmtopbm: Add -randomseed.
 
               pamfunc: Fix always wrong output with -not.  Always broken.
               (-not was new in Netpbm 10.40 (September 2007)).
 
+              pamdepth: fix bug: doesn't work on PAM with black and white
+              tuple type.
+
+              pnmnorm: Fix bug: output too dark when -bpercent and -wpercent
+              indicate overlapping values.  Broken since Netpbm 10.43 (June
+              2008).
+
+              pbmtext: Fix double-free crash with -font .  Introduced in
+              Netpbm 10.91 (June 2020).
+
               jpeg2ktopam: Fix crash whenever the program fails.  Broken in
               Netpbm 10.42 (March 2008).
 
@@ -232,11 +367,12 @@ CHANGE HISTORY
               pamtojpeg2k: Fix wrong result with -tilegrdtly.  Always
               broken (pamtojpeg2k was new in Netpbm 10.12 (November 2002)).
 
-              pamarith: Fix crash with -compare where inputs are PBM.  Broken
-              in Netpbm 10.14 (February 2003).
+              pamarith: Fix crash with -compare where inputs are PBM or
+              BLACKANDWHITE PAM.  Broken in Netpbm 10.14 (February 2003).
 
-              pamfunc: Fix crash with -changemaxval and PBM input.  Always
-              broken.  -changemaxval was new in Netpbm 10.65 (December 2013).
+              pamfunc: Fix crash with -changemaxval and PBM or BLACKANDWHITE
+              PAM input.  Always broken.  -changemaxval was new in Netpbm
+              10.65 (December 2013).
 
               pammixmulti: Fix bug: -randomseed ignored on some systems.
               Always broken.  (pammixmulti was new in Netpbm 10.85 (December
@@ -247,24 +383,31 @@ CHANGE HISTORY
               should have stopped it from working at all, despite reports from
               users that they were using it.
 
-20.08.29 BJH  Release 10.86.16
+              ximtoppm: Fix bug: invalid memory references with pathological
+              image input.  Broken in Netpbm 10.91 (June 2020).
 
-              anytopnm, pnmmargin: Fail properly when unable to create
-              temporary file.  Broken in Netpbm 10.75 (June 2016).
+              Configure: remove obsolete question about URL to put in pointer
+              man pages of yesteryear.
 
-              pamdepth: fix bug: doesn't work on PAM with black and white
-              tuple type.
+              Build: fix bug: PKG_CONFIG make variable not used for merge
+              build.  Always broken (PKG_CONFIG was new in Netpbm 10.76
+              (September 2016).
 
-              pnmnorm: Fix bug: output too dark when -bpercent and -wpercent
-              indicate overlapping values.  Broken since Netpbm 10.43 (June
-              2008).
+20.06.28 BJH  Release 10.91.00
 
-              pcdovtoppm: Fix some garbage from the conversion from csh to sh
-              in Netpbm 9.12 (March 2001) in conversion from csh arrays that
-              should have stopped it from working at all, despite reports from
-              users that they were using it.
+              pamstretch-gen: Add -quiet (supposedly added in 10.86, but never
+              worked).
 
-20.06.27 BJH  Release 10.86.15
+              pamstereogram: Add -tileable.  Thanks Scott Pakin.
+
+              pcdovtoppm: Implement -version, -plain, and -quiet.
+
+              pcdovtoppm: more secure temporary file handling.
+
+              pcdovtoppm: Improve the way it fails when 'hpcdtoppm' fails.
+
+              anytopnm, pnmmargin: Fail properly when unable to create
+              temporary file.  Broken in Netpbm 10.75 (June 2016).
 
               winicontoppm: Fix undefined behavior for various invalid input.
               Always broken.  Winicontoppm was new in Netpbm 9.3 (June 2000).
@@ -273,25 +416,21 @@ CHANGE HISTORY
               image.  Always broken.  Winicontoppm was new in Netpbm 9.3 (June
               2000).
 
-              cameratopam: Fix buffer overrun.  Always present. (cameratopam
-              was new in Netpbm 10.28 (June 2005)).
+              pjtoppm: Handle input stream with no transmission mode command.
+              Always broken.  Pjtoppm was in primordial Netpbm (1991).
 
-              ppmtompeg: Fix buffer overruns with very long names in input
-              parameter files.  Always broken.  Ppmtompeg was new in
-              Netpbm 8.4 (April 2000).
+              cameratopam: Handle I/O error on input file.  Always broken.
+              Cameratopam was new to Netpbm in Netpbm 10.25 (June 2005).
 
-              ximtoppm: Fix possible program crash due to invalid memory
-              reference.  Always broken.  ximtoppm was in primordial Netpbm,
-              ca 1989.
+              xbmtopbm: Recognize "unsigned short" as an extension of
+              XBM X10 format.
 
               pjtoppm: Fix handling of input with width unspecified or not
               positive.  Always broken.  (Pjtoppm was in primordial Netpbm, ca
               1991).
 
-20.06.06 BJH  Release 10.86.14
-
-              pjtoppm: Handle input stream with no transmission mode command.
-              Always broken.  Pjtoppm was in primordial Netpbm (1991).
+              winicontopam: Fix crash with PNG icon.  Always broken.
+              Winicontopam was new in Netpbm 10.63 (June 2013).
 
               picttoppm: Fix bug with an input file that specifies a clip
               region (ClipRgn opcode) that is not contained within the
@@ -302,18 +441,46 @@ CHANGE HISTORY
               scaled.  Broken in Netpbm 10.34 (June 2006) or 10.35 (August
               2006).
 
-20.05.06 BJH  Release 10.86.13
-
               pbmtonokia: Fix incorrect output with -txt option.
 
               pbmtonokia: Fix incorrect output with newer compiler.
 
-20.03.26 BJH  Release 10.86.12
+              pnmtorle: Fix incorrect command and filename in header.
+              Broken in Netpbm 10.88 (September 2019).
 
-              Build: make deb: don't include empty Recommends; newer dpkg-deb
-              won't accept it.
+              cameratopam: Fix buffer overrun.  Always present. (cameratopam
+              was new in Netpbm 10.28 (June 2005)).
 
-20.03.26 BJH  Release 10.86.11
+              cameratopam: Fix undefined behavior using 'swab' to swap bytes
+              in place.  Always present. (cameratopam was new in Netpbm 10.28
+              (June 2005)).
+
+              ppmtompeg: Fix buffer overruns with very long names in input
+              parameter files.  Always broken.  Ppmtompeg was new in
+              Netpbm 8.4 (April 2000).
+
+              ximtoppm: Fix possible program crash due to invalid memory
+              reference.  Always broken.  ximtoppm was in primordial Netpbm,
+              ca 1989.
+
+              pcdovtoppm: Fix bug: accepts anything starting with -s
+              as equivalent to -s.
+
+              pcdovtoppm: properly selects Bash as interpreter.  Broken
+              in Netpbm 9.12 (March 2001) (when it was called pcdindex).
+
+20.03.26 BJH  Release 10.90.00
+
+              pamundice: Add -listfile.
+
+              pamditherbw: Remove restriction to 2^18 pixels width and height
+              for -hilbert .
+
+              pamundice: Add error and warning messages for insane file name
+              pattern.
+
+              pamcut: Improve error messages for legacy command line
+              arguments.
 
               pbmtopgm: Fix incorrect output when convolution area is not
               square.  Always broken.  pbmtopgm was in primordial Netpbm,
@@ -324,20 +491,28 @@ CHANGE HISTORY
               1991.
 
               pnmshear: Fix arithmetic overflow with shear angle near +/- 90
-              degrees.
+              degrees.  Always broken; pnmshear was in primordial Netpbm,
+              ca. 1989.
+
+              pnmshear: Fix shearing direction for angles larger than 90
+              degrees.  Always broken; pnmshear was in primordial Netpbm,
+              ca. 1989.
 
-20.03.15 BJH  Release 10.86.10
+              pamditherbw: Fix bug: issue error message instead of just
+              ignoring one of the options when you specify -hilbert and
+              another halftone option.
+
+              pamdice: Fix junk output when -width or -height not specified.
 
               pamdice: Fix crash when -width or -height is zero.
 
               pamdice: Fix incorrect file names when -outstem contains "%s",
               etc.
 
-              pnmquantall: remove accidentally published debugging trace.
-
-20.02.14 BJH  Release 10.86.09
+              pgmnoise: Correct error messages for invalid height, width
+              arguments.
 
-              pamdice: Fix junk output when -width or -height not specified.
+              pnmquantall: remove accidentally published debugging trace.
 
               libnetpbm: pm_getline, xvminitoppm, pamtris : Fix bug: crash
               when reading empty line.
@@ -345,17 +520,45 @@ CHANGE HISTORY
               libnetpbm: pm_read_unknown_size, rawtopgm, zeisstopnm: crash
               when out of memory
 
-19.12.25 BJH  Release 10.86.08
+              Build: make deb: don't include empty Recommends; newer dpkg-deb
+              won't accept it.
+
+              Install: Use e.g. "10.90.00" for version in pkg-config and
+              config file, instead of e.g. "Netpbm 10.90.00".
 
-              pamrubber: Fix bug: -frame doesn't work.  Always broken.
-              (Pamrubber was new in Netpbm 10.54 (March 2011).
+19.12.29 BJH  Release 10.89.00
 
-19.12.03 BJH  Release 10.86.07
+              pnmpad: Add -reportonly.
 
               anytopnm: Fix unpredictable behavior when file name contains
               spaces.
 
-19.09.28 BJH  Release 10.86.06
+              pamfind: Fix typo in message.
+
+              pnmquant: Fail if user specifies both -spreadbrightness and
+              -spreadluminosity or both -randomseed and -norandom, rather
+              than just pick one.
+
+              pamrubber: Fix bug: -frame doesn't work.  Always broken.
+              (Pamrubber was new in Netpbm 10.54 (March 2011)).
+
+19.09.28 BJH  Release 10.88.00
+
+              pnmquant: Fail if user specifies more than one of -meanpixel,
+              -meancolor, and -center, rather than just pick one.
+
+              pnmremap: Don't output any part of the image if program fails
+              because the maxval of input and map file do not match, in a
+              case where matching maxval is required, i.e. the user specified
+              -firstisdefault or -missingcolor.
+
+              ppmhist: sort secondarily by RGB with -sort=frequency, so
+              output is repeatable.
+
+              pnmcolormap: Add -splitpix, -splitcol, -splitdim.
+              Thanks Vladislav Zavjalov.
+
+              pbmtext: fix erroneous failure message with long input text.
 
               jpeg2ktopam, pamtojpeg2k: fix negative array index.  Always
               broken (pamtojpeg2k was new in Netpbm 10.12 (November 2002)).
@@ -369,21 +572,24 @@ CHANGE HISTORY
               jpeg2ktopam: fix null pointer dereference.  Always broken
               (pamtojpeg2k was new in Netpbm 10.12 (November 2002)).
 
-              Build: fix for Cygwin, "no rule to make pm_config.h".
-
-19.08.09 BJH  Release 10.86.05
+              pnmtorle, rletopnm: fix wild pointer dereference when memory
+              allocation fails.  Always broken (programs were added to
+              Netpbm in Release 9.0 (April 2000).
 
-              pnmtorle, rletopnm: fix wild pointer dereference when a memory
-              allocation fails.
+              pamsumm: Fix bug: with -mean and a conflicting option such as
+              -sum, the program ignores one of the options.  It should fail.
+              Always broken (pamsumm was new in Netpbm 10.21 (March 2004).
 
-19.06.15 BJH  Release 10.86.04
+              Build: fix for Cygwin, "no rule to make pm_config.h".
 
-              pamtris: Fix bug: debug trace left in
+19.06.28 BJH  Release 10.87.00
 
-              pbmtozinc: Fix wrong output on big-endian machines.  Broken in
-              Netpbm 10.71 (June 2015).
+              pamfind: Add -machine .
 
-19.05.04 BJH  Release 10.86.03
+              Multiple: fix bug: when you specify the same option twice, you
+              can get a syntax error, with the message telling you you
+              specified some other option that conflicts with it.  Should just
+              take the last setting.
 
               pnmtopng: Fix bug: Defaults to no filters.  Should be all
               filters.  Effect is larger PNG output.  Broken after Netpbm
@@ -397,16 +603,18 @@ CHANGE HISTORY
               pnmcrop: Don't allow -borderfile with -reportXXX.  It doesn't
               work.
 
-19.04.10 BJH  Release 10.86.02
-
               pnmcrop: fix bug: -bgcolor doesn't work.  Always present
               (-bgcolor was introduced in Netpbm 10.86 (March 2019)).
 
-19.04.06 BJH  Release 10.86.01
+              pbmtext: fix bug: don't ignore -builtin when specified with
+              -font.  Fail with syntax error instead.
+
+              pbmtozinc: fix wrong output on big-endian machines.  Broken in
+              Netpbm 10.71 (June 2015).
+
+              pbmpage: Fix error message for invalid syntax.
 
-              pnmcrop: fix bug: incorrect identification of background with
-              -bgcolor and PBM or PGM image.  Always present (-bgcolor was
-              introduced in Netpbm 10.86 (March 2019)).
+              pamtris: Fix bug: debug trace left in
 
 19.03.30 BJH  Release 10.86.00
 
@@ -1107,7 +1315,7 @@ CHANGE HISTORY
               pnmtopng: Add -srgbintent.
 
               pamstereogram: Add -xbegin.  Change default to render from
-              center outwards intead of from right to left, thus making the
+              center outwards instead of from right to left, thus making the
               center of the image the crispest part.  Thanks Scott Pakin
               (scott+pbm@pakin.org).
 
@@ -1259,7 +1467,7 @@ CHANGE HISTORY
               color map nor a local one.
 
               pgmmorphconv: fix bug: always produces PGM Plain format.  Always
-              present (progam was added to Netpbm in Release 10.0 (June 2002)).
+              present (program was added to Netpbm in Release 10.0 (June 2002)).
 
               pamtilt: fix bug: unconditional crash.  Broken in Netpbm 10.63
               (June 2013).
@@ -1755,7 +1963,7 @@ CHANGE HISTORY
 
               libpam, pamcomp: fix bug: treats tuple type GRAYSCALE_ALPHA like
               GRAYSCALE on 32-bit machine.  Actually, looks only at first 4
-              characters (8 characters on machine with 64 bit addressess) of
+              characters (8 characters on machine with 64 bit addresses) of
               the tuple type.  Broken since Netpbm 10.56 (September 2011).
 
               pngtopam -alphapam with grayscale input: fix bug: generates
@@ -2153,10 +2361,6 @@ CHANGE HISTORY
 
               Add ppmtoascii.  Thanks "Frank Ch. Eigler" <fche@elastic.org>.
 
-              pamarith: Allow more than two operands for functions for which
-              it makes sense (all but -subtract, -difference, -compare,
-              -divide, -shiftleft, and -shiftright).
-
               pnmtops: Add -bitsperpixel option.
 
               pamx: Make exit status 0 instead of 10 when window manager
@@ -2174,7 +2378,7 @@ CHANGE HISTORY
               anytopnm: recognize "PC bitmap" in 'file' response as BMP.
               (in addition to existing "PC bitmap data").
 
-              libnetpbm, various PBM programs: Use SSE insted of MMX.  Thanks
+              libnetpbm, various PBM programs: Use SSE instead of MMX.  Thanks
               Akira F Urushibata <afu@wta.att.ne.jp>.
 
               pbmtext/libpbmfont: Fix wild pointer; probably asymptomatic.
@@ -5705,7 +5909,7 @@ CHANGE HISTORY
 
 00.07.12 BJH  Release 9.6
 
-              Add pnmtofiasco, fiascotopnm, psnpsnr.  Thanks to Ullrich
+              Add pnmtofiasco, fiascotopnm, pnmpnsr.  Thanks to Ullrich
               Hafner.
 
               Make Pnmcrop use a temporary file instead of huge amounts
@@ -5818,7 +6022,7 @@ CHANGE HISTORY
               ppmdither: fix bug with input maxval != 255.  Make output
               maxval the LCM of the requested numbers of primary levels.
 
-              xwdtopnm: works with files where there aren't an integeral
+              xwdtopnm: works with files where there aren't an integral
               number of pixels per storage unit (e.g. 24 bits per pixel)
               
               Add some missing pXm_init()
diff --git a/doc/INSTALL b/doc/INSTALL
index aad0a5e5..c20d372e 100644
--- a/doc/INSTALL
+++ b/doc/INSTALL
@@ -34,7 +34,7 @@ buildtools/debian/README in the source tree.
 The 'configure' program is not GNU Autoconf -- it is a simple program
 specific to Netpbm that prompts you for information about your system.
 If your system is not typical enough, you'll have to do a little more
-work, as described below under "custom installation."
+work, as described below under "custom building."
 
 You need to use GNU Make even if nothing else on your system is GNU,
 because the Netpbm make files exploit many advanced features of GNU
@@ -171,8 +171,8 @@ You do, however, have to tell Configure accurately whether you have the
 library installed and if so, where.
 
 
-INSTALLATION - WINDOWS
-----------------------
+WINDOWS
+-------
 
 For notes on building Netpbm on Windows using Cygwin, see the file
 README.CYGWIN.  With Cygwin, you can build Netpbm programs that use
@@ -210,7 +210,7 @@ to
 in _mingw.h.  This is the trick other C libraries use.
 
 (A user proposed that this change be distributed in _mingw.h, in April 2017 on
-the mingw-users mailing list, but the maintainer was opposed to accomodating
+the mingw-users mailing list, but the maintainer was opposed to accommodating
 programs written for the older standards).
 
 If you cannot change _mingw.h, you can alternatively change Netpbm.  Find all
@@ -223,8 +223,8 @@ and change them to
   #define _XOPEN_SOURCE 0
 
 
-INSTALLATION - MAKING ONLY THE PARTS YOU NEED
----------------------------------------------
+MAKING ONLY THE PARTS YOU NEED
+------------------------------
 
 If you don't need the whole package, but just want one tool in it that you
 heard about, you can make just that one.  For example, to make Pnmtojpeg,
@@ -293,15 +293,20 @@ preprocessor options) are similar.
   $ make CFLAGS=-O0
 
 
-CUSTOM INSTALLATION
--------------------
+AUTOMATED AND CUSTOM INSTALLATION
+---------------------------------
+
+If you want to have a program install Netpbm, don't use 'installnetpbm'.  Just
+write your own program to install from the package that 'make package'
+generates.  That package is just a directory full of files, and you should be
+able to tell by inspection what to do with those files (copy to /bin, etc).
+If not, there is a README file in the package that explains everything.  Your
+install program will probably just be shell script that issues about five
+commands.
 
-If the Installnetpbm program doesn't install the way you want, it is
-easy to install it manually using the package that 'make package'
-generates.  That package is just a directory full of files, and you
-should be able to tell by inspection what to do with those files (copy
-to /bin, etc).  If not, there will be a README file in the package to
-explain everything.
+Likewise, even if you're installing interactively, if the Installnetpbm
+program doesn't install the way you want, just install manually from the
+package, using a few commands such as 'cp'.
 
 
 INSTALLATION - SHARED LIBRARIES
diff --git a/doc/TESTS b/doc/TESTS
index 9434f580..44f86758 100644
--- a/doc/TESTS
+++ b/doc/TESTS
@@ -1,5 +1,3 @@
-Please cut and paste from below:
----------------------------------------------------------------------------
 Contents
 ========
 
@@ -7,6 +5,8 @@ Contents
   1.1 Standard test procedure
   1.2 Summary report
   1.3 Prerequisites
+    1.3.1 Required programs
+    1.3.2 Required locales
   1.4 Repeatability
   1.5 Execution time
   1.6 Testing package in designated directory
@@ -69,6 +69,9 @@ appear at the end:
 1.3 Prerequisites
 =================
 
+1.3.1 Required programs
+-----------------------
+
 The tests require the Bash command shell.  The script Execute-Tests has
 some expressions unique to Bash.  Quite old versions work, at least back
 to Bash v. 2.05b.
@@ -81,28 +84,54 @@ The tests use the following utilities:
  - sh
  - awk
 
+ - basename
  - cat
  - cksum
  - cmp
+ - comm
  - cp
  - cut
  - date
  - dirname
  - egrep
  - fgrep
- - grep
  - file
+ - grep
+ - gs
  - head
  - iconv
  - mkdir
  - mktemp
+ - perl
  - rm
  - sed
  - seq
+ - sh
+ - sort
  - tee
  - tr
  - uniq
+ - wc
+
+
+1.3.2 Required locales
+----------------------
+
+For full covereage the following locales must be available:
+
+  en_US.iso88591, en_US.utf8
+
+To check whether they are available, execute the following and see if they
+are reported:
+
+  locale -a | grep en_US
+
+The output should contain these lines:
+
+  en_US.iso88591
+  en_US.utf8
 
+If these locales are absent some pbmtext tests will be skipped.
 
 
 1.4 Repeatability
diff --git a/doc/copyright_summary b/doc/copyright_summary
index 9ab3a784..84fa9397 100644
--- a/doc/copyright_summary
+++ b/doc/copyright_summary
@@ -1,4 +1,4 @@
-Here is an analysys of Netpbm copyrights done by Steve McIntyre
+Here is an analysis of Netpbm copyrights done by Steve McIntyre
 <stevem@chiark.greenend.org.uk> finishing on October 7, 2001.
 
 It is based on Netpbm 9.20, so it doesn't cover material added since
diff --git a/doc/patent_summary b/doc/patent_summary
index b9623d09..5fe0923c 100644
--- a/doc/patent_summary
+++ b/doc/patent_summary
@@ -22,6 +22,13 @@ applied to things you implement in computer programs.  This is one of
 the Free Software Foundation's causes.  See 
 <http://www.gnu.org/philosophy.html#laws>.
 
+All the patents mentioned in this file have probably expired.  The maintainer
+is unaware of any recent patented inventions used in Netpbm.
+
+
+JBIG patents
+------------
+
 The Jbigtopnm and Pnmtojbig programs use arithmetic coding patents and
 other patents covering various aspects of the "front end."
 
@@ -37,7 +44,7 @@ Forgent owns a patent it believes covers JPEG compression.  This
 patent was virtually unknown before July 2002, when Forgent began to
 enforce it.  It has successfully enforced it against two companies
 (Sony and an unnamed Japanese digital camera maker), but without court
-ruling.  This patent, U.S. Patent No. 4,698,672, expires in 2006.
+ruling.  This patent, U.S. Patent No. 4,698,672, expired in 2006.
 
 Philips and Lucent Technologies also own patents they claim cover
 JPEG.
diff --git a/editor/Makefile b/editor/Makefile
index 5b12e4ca..0027832c 100644
--- a/editor/Makefile
+++ b/editor/Makefile
@@ -16,23 +16,24 @@ SUBDIRS = pamflip specialty
 # This package is so big, it's useful even when some parts won't 
 # build.
 
-PORTBINARIES = pamaddnoise pamaltsat pambackground pambrighten pamcomp pamcut \
-	       pamdice pamditherbw pamedge \
-	       pamenlarge \
-	       pamfunc pamhue pamlevels pammasksharpen pammixmulti \
-	       pamperspective pamrecolor pamrubber \
-	       pamscale pamsistoaglyph pamstretch pamthreshold pamundice \
-	       pamwipeout \
+PORTBINARIES = pamaddnoise pamaltsat pambackground pambrighten \
+	       pamcat pamcomp pamcut \
+	       pamdice pamditherbw pamedge pamenlarge \
+	       pamfunc pamhomography pamhue pamlevels \
+	       pammasksharpen pammixmulti \
+	       pamperspective pamrecolor pamrestack pamrubber \
+	       pamscale pamshuffle pamsistoaglyph pamstretch pamthreshold \
+	       pamundice pamwipeout \
 	       pbmclean pbmmask pbmpscale pbmreduce \
 	       pgmdeshadow pgmenhance \
 	       pgmmedian \
-	       pnmalias pnmcat pnmconvol pnmcrop \
+	       pnmalias pnmconvol pnmcrop \
 	       pnmgamma \
 	       pnmhisteq pnminvert pnmmontage \
 	       pnmnlfilt pnmnorm pnmpad pnmpaste \
 	       pnmremap pnmrotate \
 	       pnmscalefixed pnmshear pnmsmooth pnmstitch pnmtile \
-	       ppmbrighten ppmchange ppmcolormask \
+	       ppmchange ppmcolormask \
 	       ppmdim ppmdist ppmdither ppmdraw \
 	       ppmflash ppmlabel ppmmix \
 
@@ -44,7 +45,7 @@ NOMERGEBINARIES =
 MERGEBINARIES = $(PORTBINARIES)
 
 BINARIES = $(MERGEBINARIES) $(NOMERGEBINARIES)
-SCRIPTS = pnmflip ppmfade ppmquant ppmshadow \
+SCRIPTS = ppmbrighten pnmflip ppmfade ppmquant ppmshadow \
 	  pamstretch-gen pnmmargin pnmquant pnmquantall 
 
 OBJECTS = $(BINARIES:%=%.o)
@@ -63,10 +64,15 @@ install.bin install.merge: install.bin.local
 .PHONY: install.bin.local
 install.bin.local: $(PKGDIR)/bin
 # Remember that $(SYMLINK) might just be a copy command.
-# backward compatibility: program used to be pnminterp
+
+# In December 2001, pamstretch replaced pnminterp and pamstretch-getn
+# replaced pnminterp-gen
 	cd $(PKGDIR)/bin ; \
 	rm -f pnminterp$(EXE); \
 	$(SYMLINK) pamstretch$(EXE) pnminterp$(EXE)
+	cd $(PKGDIR)/bin ; \
+	rm -f pnminterp-gen$(EXE); \
+	$(SYMLINK) pamstretch-gen$(EXE) pnminterp-gen$(EXE)
 # In March 2002, pnmnorm replaced ppmnorm and pgmnorm
 	cd $(PKGDIR)/bin ; \
 	rm -f ppmnorm$(EXE) ; \
@@ -100,6 +106,10 @@ install.bin.local: $(PKGDIR)/bin
 	cd $(PKGDIR)/bin ; \
 	rm -f pnmcomp$(EXE) ; \
 	$(SYMLINK) pamcomp$(EXE) pnmcomp$(EXE)
+# In August 2022, pamcat replaced pnmcat
+	cd $(PKGDIR)/bin ; \
+	rm -f pnmcat$(EXE) ; \
+	$(SYMLINK) pamcat$(EXE) pnmcat$(EXE)
 
 mergecomptrylist:
 	cat /dev/null >$@
@@ -111,4 +121,5 @@ mergecomptrylist:
 	echo "TRY(\"pnmcut\",     main_pamcut);"     >>$@
 	echo "TRY(\"pnmscale\",   main_pamscale);"   >>$@
 	echo "TRY(\"pnmcomp\",    main_pamcomp);"    >>$@
+	echo "TRY(\"pnmcat\",     main_pamcomp);"    >>$@
 
diff --git a/editor/pamaddnoise.c b/editor/pamaddnoise.c
index ccfde0b6..9ca80394 100644
--- a/editor/pamaddnoise.c
+++ b/editor/pamaddnoise.c
@@ -1,8 +1,8 @@
 /*
-** 
-** Add gaussian, multiplicative gaussian, impulse, laplacian or 
-** poisson noise to a portable anymap.
-** 
+**
+** Add gaussian, multiplicative gaussian, impulse, laplacian or
+** poisson noise to a Netpbm image
+**
 ** Version 1.0  November 1995
 **
 ** Copyright (C) 1995 by Mike Burns (burns@cac.psu.edu)
@@ -28,33 +28,198 @@
 
 #define _XOPEN_SOURCE 500  /* get M_PI in math.h */
 
+#include <assert.h>
 #include <math.h>
 
 #include "pm_c_util.h"
+#include "mallocvar.h"
+#include "rand.h"
+#include "shhopt.h"
+#include "pm_gamma.h"
 #include "pam.h"
 
-#define RANDOM_MASK 0x7FFF  /* only compare lower 15 bits.  Stupid PCs. */
-
 static double const EPSILON = 1.0e-5;
-static double const arand = 32767.0;      /* 2^15-1 in case stoopid computer */
-
-enum noiseType {
-    GAUSSIAN,
-    IMPULSE,  /* aka salt and pepper noise */
-    LAPLACIAN,
-    MULTIPLICATIVE_GAUSSIAN,
-    POISSON,
-    MAX_NOISE_TYPES
+static double const SALT_RATIO = 0.5;
+
+
+
+static double
+rand1(struct pm_randSt * const randStP) {
+
+    return (double)pm_rand(randStP)/RAND_MAX;
+}
+
+
+
+enum NoiseType {
+    NOISETYPE_GAUSSIAN,
+    NOISETYPE_IMPULSE,  /* aka salt and pepper noise */
+    NOISETYPE_LAPLACIAN,
+    NOISETYPE_MULTIPLICATIVE_GAUSSIAN,
+    NOISETYPE_POISSON
+};
+
+
+
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char * inputFileName;
+
+    enum NoiseType noiseType;
+
+    unsigned int seedSpec;
+    unsigned int seed;
+
+    float lambda;
+    float lsigma;
+    float mgsigma;
+    float sigma1;
+    float sigma2;
+    float tolerance;
 };
 
 
 
+static enum NoiseType
+typeFmName(const char * const name) {
+
+    enum NoiseType retval;
+
+    if (false)
+        assert(false);
+    else if (pm_keymatch(name, "gaussian", 1))
+        retval = NOISETYPE_GAUSSIAN;
+    else if (pm_keymatch(name, "impulse", 1))
+        retval = NOISETYPE_IMPULSE;
+    else if (pm_keymatch(name, "laplacian", 1))
+        retval = NOISETYPE_LAPLACIAN;
+    else if (pm_keymatch(name, "multiplicative_gaussian", 1))
+        retval = NOISETYPE_MULTIPLICATIVE_GAUSSIAN;
+    else if (pm_keymatch(name, "poisson", 1))
+        retval = NOISETYPE_POISSON;
+    else
+        pm_error("Unrecognized -type value '%s'.  "
+                 "We recognize 'gaussian', 'impulse', 'laplacian', "
+                 "'multiplicative_gaussian', and 'poisson'", name);
+
+    return retval;
+}
+
+
+
 static void
-gaussian_noise(sample   const maxval,
-               sample   const origSample,
-               sample * const newSampleP,
-               float    const sigma1,
-               float    const sigma2) {
+parseCommandLine(int argc, const char ** const argv,
+                 struct CmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   Note that the file spec array we return is stored in the storage that
+   was passed to us as the argv array.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;
+        /* Instructions to OptParseOptions3 on how to parse our options. */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+
+    unsigned int typeSpec, lambdaSpec, lsigmaSpec, mgsigmaSpec,
+        sigma1Spec, sigma2Spec, toleranceSpec;
+
+    const char * type;
+
+    MALLOCARRAY(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0,   "type",            OPT_STRING,   &type,
+            &typeSpec,           0);
+    OPTENT3(0,   "seed",            OPT_UINT,     &cmdlineP->seed,
+            &cmdlineP->seedSpec, 0);
+    OPTENT3(0,   "lambda",          OPT_FLOAT,    &cmdlineP->lambda,
+            &lambdaSpec,         0);
+    OPTENT3(0,   "lsigma",          OPT_FLOAT,    &cmdlineP->lsigma,
+            &lsigmaSpec,         0);
+    OPTENT3(0,   "mgsigma",         OPT_FLOAT,    &cmdlineP->mgsigma,
+            &mgsigmaSpec,        0);
+    OPTENT3(0,   "sigma1",          OPT_FLOAT,    &cmdlineP->sigma1,
+            &sigma1Spec,         0);
+    OPTENT3(0,   "sigma2",          OPT_FLOAT,    &cmdlineP->sigma2,
+            &sigma2Spec,         0);
+    OPTENT3(0,   "tolerance",       OPT_FLOAT,    &cmdlineP->tolerance,
+            &toleranceSpec,      0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (!typeSpec)
+        cmdlineP->noiseType = NOISETYPE_GAUSSIAN;
+    else
+        cmdlineP->noiseType = typeFmName(type);
+
+    if (sigma1Spec && cmdlineP->noiseType != NOISETYPE_GAUSSIAN)
+        pm_error("-sigma1 is valid only with -type=gaussian");
+
+    if (sigma2Spec && cmdlineP->noiseType != NOISETYPE_GAUSSIAN)
+        pm_error("-sigma2 is valid only with -type=gaussian");
+
+    if (mgsigmaSpec &&
+        cmdlineP->noiseType != NOISETYPE_MULTIPLICATIVE_GAUSSIAN)
+        pm_error("-mgsigma is valid only with -type=multiplicative_guassian");
+
+    if (toleranceSpec && cmdlineP->noiseType != NOISETYPE_IMPULSE)
+        pm_error("-tolerance is valid only with -type=impulse");
+
+    if (lsigmaSpec && cmdlineP->noiseType != NOISETYPE_LAPLACIAN)
+        pm_error("-lsigma is valid only with -type=laplacian");
+
+    if (lambdaSpec && cmdlineP->noiseType != NOISETYPE_POISSON)
+        pm_error("-lambda is valid only with -type=poisson");
+
+    if (!lambdaSpec)
+        cmdlineP->lambda = 12.0;
+
+    if (!lsigmaSpec)
+        cmdlineP->lsigma = 10.0;
+
+    if (!mgsigmaSpec)
+        cmdlineP->mgsigma = 0.5;
+
+    if (!sigma1Spec)
+        cmdlineP->sigma1 = 4.0;
+
+    if (!sigma2Spec)
+        cmdlineP->sigma2 = 20.0;
+
+    if (!toleranceSpec)
+        cmdlineP->tolerance = 0.10;
+
+    if (!cmdlineP->seedSpec)
+        cmdlineP->seed = pm_randseed();
+
+    if (argc-1 > 1)
+        pm_error("Too many arguments (%u).  File spec is the only argument.",
+                 argc-1);
+
+    if (argc-1 < 1)
+        cmdlineP->inputFileName = "-";
+    else
+        cmdlineP->inputFileName = argv[1];
+
+    free(option_def);
+}
+
+
+
+static void
+addGaussianNoise(sample             const maxval,
+                 sample             const origSample,
+                 sample *           const newSampleP,
+                 float              const sigma1,
+                 float              const sigma2,
+                 struct pm_randSt * const randStP) {
 /*----------------------------------------------------------------------------
    Add Gaussian noise.
 
@@ -64,14 +229,14 @@ gaussian_noise(sample   const maxval,
     double x1, x2, xn, yn;
     double rawNewSample;
 
-    x1 = (rand() & RANDOM_MASK) / arand; 
+    x1 = rand1(randStP);
 
     if (x1 == 0.0)
         x1 = 1.0;
-    x2 = (rand() & RANDOM_MASK) / arand;
+    x2 = rand1(randStP);
     xn = sqrt(-2.0 * log(x1)) * cos(2.0 * M_PI * x2);
     yn = sqrt(-2.0 * log(x1)) * sin(2.0 * M_PI * x2);
-    
+
     rawNewSample =
         origSample + (sqrt((double) origSample) * sigma1 * xn) + (sigma2 * yn);
 
@@ -81,41 +246,43 @@ gaussian_noise(sample   const maxval,
 
 
 static void
-impulse_noise(sample   const maxval,
-              sample   const origSample,
-              sample * const newSampleP,
-              float    const tolerance) {
+addImpulseNoise(sample             const maxval,
+                sample             const origSample,
+                sample *           const newSampleP,
+                float              const tolerance,
+                double             const saltRatio,
+                struct pm_randSt * const randStP) {
 /*----------------------------------------------------------------------------
    Add impulse (salt and pepper) noise
 -----------------------------------------------------------------------------*/
 
-    double const low_tol  = tolerance / 2.0;
-    double const high_tol = 1.0 - (tolerance / 2.0);
-    double const sap = (rand() & RANDOM_MASK) / arand; 
+    double const pepperRatio = 1.0 - saltRatio;
+    double const loTolerance = tolerance * pepperRatio;
+    double const hiTolerance = 1.0 - tolerance * saltRatio;
+    double const sap         = rand1(randStP);
 
-    if (sap < low_tol) 
-        *newSampleP = 0;
-    else if ( sap >= high_tol )
-        *newSampleP = maxval;
-    else
-        *newSampleP = origSample;
+    *newSampleP =
+        sap < loTolerance ? 0 :
+        sap >= hiTolerance? maxval :
+        origSample;
 }
 
 
 
 static void
-laplacian_noise(sample   const maxval,
-                double   const infinity,
-                sample   const origSample,
-                sample * const newSampleP,
-                float    const lsigma) {
+addLaplacianNoise(sample             const maxval,
+                  double             const infinity,
+                  sample             const origSample,
+                  sample *           const newSampleP,
+                  float              const lsigma,
+                  struct pm_randSt * const randStP) {
 /*----------------------------------------------------------------------------
    Add Laplacian noise
 
    From Pitas' book.
 -----------------------------------------------------------------------------*/
-    double const u = (rand() & RANDOM_MASK) / arand; 
-                
+    double const u = rand1(randStP);
+
     double rawNewSample;
 
     if (u <= 0.5) {
@@ -136,11 +303,12 @@ laplacian_noise(sample   const maxval,
 
 
 static void
-multiplicative_gaussian_noise(sample   const maxval,
-                              double   const infinity,
-                              sample   const origSample,
-                              sample * const newSampleP,
-                              float    const mgsigma) {
+addMultiplicativeGaussianNoise(sample             const maxval,
+                               double             const infinity,
+                               sample             const origSample,
+                               sample *           const newSampleP,
+                               float              const mgsigma,
+                               struct pm_randSt * const randStP) {
 /*----------------------------------------------------------------------------
    Add multiplicative Gaussian noise
 
@@ -150,14 +318,14 @@ multiplicative_gaussian_noise(sample   const maxval,
     double rawNewSample;
 
     {
-        double const uniform = (rand() & RANDOM_MASK) / arand; 
+        double const uniform = rand1(randStP);
         if (uniform <= EPSILON)
             rayleigh = infinity;
         else
             rayleigh = sqrt(-2.0 * log( uniform));
     }
     {
-        double const uniform = (rand() & RANDOM_MASK) / arand; 
+        double const uniform = rand1(randStP);
         gauss = rayleigh * cos(2.0 * M_PI * uniform);
     }
     rawNewSample = origSample + (origSample * mgsigma * gauss);
@@ -166,262 +334,106 @@ multiplicative_gaussian_noise(sample   const maxval,
 }
 
 
+static double
+poissonPmf(double       const lambda,
+           unsigned int const k) {
+/*----------------------------------------------------------------------------
+   This is the probability mass function (PMF) of a discrete random variable
+   with lambda 'lambda'.
+
+   I.e. it gives the probability that a value sampled from a Poisson
+   distribution with lambda 'lambda' has the value 'k'.
+
+   That means it's the probability that in a Poisson stream of events in which
+   the mean number of events in an interval of a certains size is 'lambda' that
+   'k' events happen.
+-----------------------------------------------------------------------------*/
+    double x;
+    unsigned int i;
+
+    /* We're computing the formula
+
+         (pow(lamda, k) * exp(-lambda)) / fact(k).
+
+       Note that k is ordinarily quite small.
+    */
+
+    x = exp(-lambda);
+
+    for (i = 1; i <= k; ++i) {
+        x *= lambda;
+        x /= i;
+    }
+    return x;
+}
+
+
 
 static void
-poisson_noise(sample   const maxval,
-              sample   const origSample,
-              sample * const newSampleP,
-              float    const lambda) {
+addPoissonNoise(struct pam *       const pamP,
+                sample             const origSample,
+                sample *           const newSampleP,
+                float              const lambdaOfMaxval,
+                struct pm_randSt * const randStP) {
 /*----------------------------------------------------------------------------
    Add Poisson noise
 -----------------------------------------------------------------------------*/
-    double const x  = lambda * origSample;
-    double const x1 = exp(-x);
+    samplen const origSamplen = pnm_normalized_sample(pamP, origSample);
+
+    float const origSampleIntensity = pm_ungamma709(origSamplen);
+
+    double const lambda  = origSampleIntensity * lambdaOfMaxval;
+
+    double const u = rand1(randStP);
+
+    /* We now apply the inverse CDF (cumulative distribution function) of the
+       Poisson distribution to uniform random variable 'u' to get a Poisson
+       random variable.  Unfortunately, we have no algebraic equation for the
+       inverse of the CDF, but the random variable is discrete, so we can just
+       iterate.
+    */
 
-    double rawNewSample;
-    float rr;
     unsigned int k;
+    double cumProb;
+
+    for (k = 0, cumProb = 0.0; k < lambdaOfMaxval; ++k) {
+
+        cumProb += poissonPmf(lambda, k);
 
-    rr = 1.0;  /* initial value */
-    k = 0;     /* initial value */
-    rr = rr * ((rand() & RANDOM_MASK) / arand);
-    while (rr > x1) {
-        ++k;
-        rr = rr * ((rand() & RANDOM_MASK) / arand);
+        if (cumProb >= u)
+            break;
     }
-    rawNewSample = k / lambda;
 
-    *newSampleP = MIN(MAX((int)rawNewSample, 0), maxval);
+    {
+        samplen const newSamplen = pm_gamma709(k/lambdaOfMaxval);
+
+        *newSampleP = pnm_unnormalized_sample(pamP, newSamplen);
+    }
 }
 
 
 
-int 
-main(int argc, char * argv[]) {
+int
+main(int argc, const char ** argv) {
 
     FILE * ifP;
+    struct CmdlineInfo cmdline;
     struct pam inpam;
     struct pam outpam;
     tuple * tuplerow;
     const tuple * newtuplerow;
     unsigned int row;
     double infinity;
+    struct pm_randSt randSt;
 
-    int argn;
-    const char * inputFilename;
-    int noise_type;
-    unsigned int seed;
-    int i;
-    const char * const usage = "[-type noise_type] [-lsigma x] [-mgsigma x] "
-        "[-sigma1 x] [-sigma2 x] [-lambda x] [-seed n] "
-        "[-tolerance ratio] [pgmfile]";
-
-    const char * const noise_name[] = { 
-        "gaussian",
-        "impulse",
-        "laplacian",
-        "multiplicative_gaussian",
-        "poisson"
-    };
-    int const noise_id[] = { 
-        GAUSSIAN,
-        IMPULSE,
-        LAPLACIAN,
-        MULTIPLICATIVE_GAUSSIAN,
-        POISSON
-    };
-    /* minimum number of characters to match noise name for pm_keymatch() */
-    int const noise_compare[] = {
-        1,
-        1,
-        1,
-        1,
-        1
-    };
-
-    /* define default values for configurable options */
-    float lambda = 0.05;        
-    float lsigma = 10.0;
-    float mgsigma = 0.5;
-    float sigma1 = 4.0;
-    float sigma2 = 20.0;
-    float tolerance = 0.10;
-
-    pnm_init(&argc, argv);
-
-    seed = pm_randseed();
-    noise_type = GAUSSIAN;
-
-    argn = 1;
-    while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
-    {
-        if ( pm_keymatch( argv[argn], "-lambda", 3 ) )
-        {
-            ++argn;
-            if ( argn >= argc )
-            {
-                pm_message( 
-                    "incorrect number of arguments for -lambda option" );
-                pm_usage( usage );
-            }
-            else if ( argv[argn][0] == '-' )
-            {
-                pm_message( "invalid argument to -lambda option: %s", 
-                            argv[argn] );
-                pm_usage( usage );
-            }
-            lambda = atof( argv[argn] );
-        }
-        else if ( pm_keymatch( argv[argn], "-lsigma", 3 ) )
-        {
-            ++argn;
-            if ( argn >= argc )
-            {
-                pm_message( 
-                    "incorrect number of arguments for -lsigma option" );
-                pm_usage( usage );
-            }
-            else if ( argv[argn][0] == '-' )
-            {
-                pm_message( "invalid argument to -lsigma option: %s", 
-                            argv[argn] );
-                pm_usage( usage );
-            }
-            lsigma = atof( argv[argn] );
-        }
-        else if ( pm_keymatch( argv[argn], "-mgsigma", 2 ) )
-        {
-            ++argn;
-            if ( argn >= argc )
-            {
-                pm_message( 
-                    "incorrect number of arguments for -mgsigma option" );
-                pm_usage( usage );
-            }
-            else if ( argv[argn][0] == '-' )
-            {
-                pm_message( "invalid argument to -mgsigma option: %s", 
-                            argv[argn] );
-                pm_usage( usage );
-            }
-            mgsigma = atof( argv[argn] );
-        }
-        else if ( pm_keymatch( argv[argn], "-seed", 3 ) )
-        {
-            ++argn;
-            if ( argn >= argc )
-            {
-                pm_message( "incorrect number of arguments for -seed option" );
-                pm_usage( usage );
-            }
-            else if ( argv[argn][0] == '-' )
-            {
-                pm_message( "invalid argument to -seed option: %s", 
-                            argv[argn] );
-                pm_usage( usage );
-            }
-            seed = atoi(argv[argn]);
-        }
-        else if ( pm_keymatch( argv[argn], "-sigma1", 7 ) ||
-                  pm_keymatch( argv[argn], "-s1", 3 ) )
-        {
-            ++argn;
-            if ( argn >= argc )
-            {
-                pm_message( 
-                    "incorrect number of arguments for -sigma1 option" );
-                pm_usage( usage );
-            }
-            else if ( argv[argn][0] == '-' )
-            {
-                pm_message( "invalid argument to -sigma1 option: %s", 
-                            argv[argn] );
-                pm_usage( usage );
-            }
-            sigma1 = atof( argv[argn] );
-        }
-        else if ( pm_keymatch( argv[argn], "-sigma2", 7 ) ||
-                  pm_keymatch( argv[argn], "-s2", 3 ) )
-        {
-            ++argn;
-            if ( argn >= argc )
-            {
-                pm_message( 
-                    "incorrect number of arguments for -sigma2 option" );
-                pm_usage( usage );
-            }
-            else if ( argv[argn][0] == '-' )
-            {
-                pm_message( "invalid argument to -sigma2 option: %s", 
-                            argv[argn] );
-                pm_usage( usage );
-            }
-            sigma2 = atof( argv[argn] );
-        }
-        else if ( pm_keymatch( argv[argn], "-tolerance", 3 ) )
-        {
-            ++argn;
-            if ( argn >= argc )
-            {
-                pm_message( 
-                    "incorrect number of arguments for -tolerance option" );
-                pm_usage( usage );
-            }
-            else if ( argv[argn][0] == '-' )
-            {
-                pm_message( "invalid argument to -tolerance option: %s", 
-                            argv[argn] );
-                pm_usage( usage );
-            }
-            tolerance = atof( argv[argn] );
-        }
-        else if ( pm_keymatch( argv[argn], "-type", 3 ) )
-        {
-            ++argn;
-            if ( argn >= argc )
-            {
-                pm_message( "incorrect number of arguments for -type option" );
-                pm_usage( usage );
-            }
-            else if ( argv[argn][0] == '-' )
-            {
-                pm_message( "invalid argument to -type option: %s", 
-                            argv[argn] );
-                pm_usage( usage );
-            }
-            /* search through list of valid noise types and compare */
-            i = 0;
-            while ( ( i < MAX_NOISE_TYPES ) && 
-                    !pm_keymatch( argv[argn], 
-                                  noise_name[i], noise_compare[i] ) )
-                ++i;
-            if ( i >= MAX_NOISE_TYPES )
-            {
-                pm_message( "invalid argument to -type option: %s", 
-                            argv[argn] );
-                pm_usage( usage );
-            }
-            noise_type = noise_id[i];
-        }
-        else
-            pm_usage( usage );
-        ++argn;
-    }
-
-    if ( argn < argc )
-    {
-        inputFilename = argv[argn];
-        argn++;
-    }
-    else
-        inputFilename = "-";
+    pm_proginit(&argc, argv);
 
-    if ( argn != argc )
-        pm_usage( usage );
+    parseCommandLine(argc, argv, &cmdline);
 
-    srand(seed);
+    pm_randinit(&randSt);
+    pm_srand2(&randSt, cmdline.seedSpec, cmdline.seed);
 
-    ifP = pm_openr(inputFilename);
+    ifP = pm_openr(cmdline.inputFileName);
 
     pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
 
@@ -430,50 +442,56 @@ main(int argc, char * argv[]) {
 
     pnm_writepaminit(&outpam);
 
-    tuplerow = pnm_allocpamrow(&inpam);
+    tuplerow    = pnm_allocpamrow(&inpam);
     newtuplerow = pnm_allocpamrow(&inpam);
+
     infinity = (double) inpam.maxval;
-    
+
     for (row = 0; row < inpam.height; ++row) {
         unsigned int col;
         pnm_readpamrow(&inpam, tuplerow);
         for (col = 0; col < inpam.width; ++col) {
             unsigned int plane;
             for (plane = 0; plane < inpam.depth; ++plane) {
-                switch (noise_type) {
-                case GAUSSIAN:
-                    gaussian_noise(inpam.maxval,
-                                   tuplerow[col][plane],
-                                   &newtuplerow[col][plane],
-                                   sigma1, sigma2);
+                switch (cmdline.noiseType) {
+                case NOISETYPE_GAUSSIAN:
+                    addGaussianNoise(inpam.maxval,
+                                     tuplerow[col][plane],
+                                     &newtuplerow[col][plane],
+                                     cmdline.sigma1, cmdline.sigma2,
+                                     &randSt);
                     break;
-                    
-                case IMPULSE:
-                    impulse_noise(inpam.maxval,
-                                  tuplerow[col][plane],
-                                  &newtuplerow[col][plane],
-                                  tolerance);
-                   break;
-                    
-                case LAPLACIAN:
-                    laplacian_noise(inpam.maxval, infinity,
+
+                case NOISETYPE_IMPULSE:
+                    addImpulseNoise(inpam.maxval,
                                     tuplerow[col][plane],
                                     &newtuplerow[col][plane],
-                                    lsigma);
+                                    cmdline.tolerance, SALT_RATIO,
+                                    &randSt);
+                   break;
+
+                case NOISETYPE_LAPLACIAN:
+                    addLaplacianNoise(inpam.maxval, infinity,
+                                      tuplerow[col][plane],
+                                      &newtuplerow[col][plane],
+                                      cmdline.lsigma,
+                                      &randSt);
                     break;
-                    
-                case MULTIPLICATIVE_GAUSSIAN:
-                    multiplicative_gaussian_noise(inpam.maxval, infinity,
-                                                  tuplerow[col][plane],
-                                                  &newtuplerow[col][plane],
-                                                  mgsigma);
+
+                case NOISETYPE_MULTIPLICATIVE_GAUSSIAN:
+                    addMultiplicativeGaussianNoise(inpam.maxval, infinity,
+                                                   tuplerow[col][plane],
+                                                   &newtuplerow[col][plane],
+                                                   cmdline.mgsigma,
+                                                   &randSt);
                     break;
-                    
-                case POISSON:
-                    poisson_noise(inpam.maxval,
-                                  tuplerow[col][plane],
-                                  &newtuplerow[col][plane],
-                                  lambda);
+
+                case NOISETYPE_POISSON:
+                    addPoissonNoise(&inpam,
+                                    tuplerow[col][plane],
+                                    &newtuplerow[col][plane],
+                                    cmdline.lambda,
+                                    &randSt);
                     break;
 
                 }
@@ -481,8 +499,12 @@ main(int argc, char * argv[]) {
         }
         pnm_writepamrow(&outpam, newtuplerow);
     }
+    pm_randterm(&randSt);
     pnm_freepamrow(newtuplerow);
     pnm_freepamrow(tuplerow);
 
     return 0;
 }
+
+
+
diff --git a/editor/pamaltsat.c b/editor/pamaltsat.c
index 6d9b91e0..3bff55bd 100644
--- a/editor/pamaltsat.c
+++ b/editor/pamaltsat.c
@@ -160,7 +160,7 @@ typedef double (binsearchFunc)(double       const x,
 
 /* The binary-search function. Returns such <x> from [<min>, <max>] that
    monotonically increasing function func(x, data) equals <value> within
-   precision <prec>. <dataP> is an arbitary parameter to <func>. */
+   precision <prec>. <dataP> is an arbitrary parameter to <func>. */
 static double
 binsearch(binsearchFunc       func,
           const void  * const dataP,
@@ -299,7 +299,7 @@ typedef struct {
     TupleD *        tupsatP;
         /* saturated color                            */
     double *        intRatioP;
-        /* ratio of orignal and saturated intensities */
+        /* ratio of original and saturated intensities */
 } MaxLogSatInfo;
 
 
@@ -346,7 +346,7 @@ getMaxLogSat(LinSampleInfo * const siP,
 /*  Discarding return value (maximum saturation) because upon completion of
     binsearch() info.tupsatP will contain the saturated color. The target value
     of maximum channel intensity is decreased by PREC in order to avoid
-    overlow. */
+    overflow. */
     binsearch(binsearchMaxLogSat, &info, PREC, 1.0, upperLimit, 1.0 - PREC);
 }
 
@@ -399,11 +399,11 @@ saturateSpectrum(LinSampleInfo * const siP,
     else {
         double const km1 =
             (1.0 - siP->intensity)/(siP->maxval - siP->intensity);
-            /* Maximum saturation factor that keeps maximum layer intesity
+            /* Maximum saturation factor that keeps maximum layer intensity
                within range
             */
         double const km2 = siP->intensity/(siP->intensity - sample[siP->minl]);
-            /* Maximum saturation factor  that keeps minimum layer intesity
+            /* Maximum saturation factor  that keeps minimum layer intensity
                within range
             */
 
diff --git a/editor/pambackground.c b/editor/pambackground.c
index b4941042..218f5b7e 100644
--- a/editor/pambackground.c
+++ b/editor/pambackground.c
@@ -4,19 +4,19 @@
 #include "shhopt.h"
 #include "pam.h"
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    const char * inputFileName;  
+    const char * inputFileName;
     unsigned int verbose;
 };
 
 
 
 static void
-parseCommandLine(int argc, char ** const argv,
-                 struct cmdlineInfo * const cmdlineP) {
+parseCommandLine(int argc, const char ** const argv,
+                 struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that the file spec array we return is stored in the storage that
    was passed to us as the argv array.
@@ -37,7 +37,7 @@ parseCommandLine(int argc, char ** const argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (argc-1 < 1)
@@ -48,7 +48,7 @@ parseCommandLine(int argc, char ** const argv,
             pm_error("There is at most one argument:  input file name.  "
                      "You specified %d", argc-1);
     }
-}        
+}
 
 
 
@@ -83,7 +83,7 @@ allocateOutputPointerRow(unsigned int const width,
 
 
 static void
-createWhiteTuple(const struct pam * const pamP, 
+createWhiteTuple(const struct pam * const pamP,
                  tuple *            const whiteTupleP) {
 /*----------------------------------------------------------------------------
    Create a "white" tuple.  By that we mean a tuple all of whose elements
@@ -134,7 +134,7 @@ selectBackground(struct pam * const pamP,
             bg = ul;
         }
     }
-    
+
     *bgColorP = pnm_allocpamtuple(pamP);
     pnm_assigntuple(pamP, *bgColorP, bg);
 }
@@ -301,8 +301,8 @@ expandBackgroundHoriz(unsigned char ** const pi,
                       unsigned int     const height,
                       bool *           const expandedP) {
 /*----------------------------------------------------------------------------
-   In every row, expand the background rightward from any known background
-   pixel through all consecutive unknown pixels.
+   In every row except top and bottom, expand the background rightward from
+   any known background pixel through all consecutive unknown pixels.
 
    Then do the same thing leftward.
 
@@ -343,8 +343,9 @@ expandBackgroundVert(unsigned char ** const pi,
                      unsigned int     const height,
                      bool *           const expandedP) {
 /*----------------------------------------------------------------------------
-   In every column, expand the background downward from any known background
-   pixel through all consecutive unknown pixels.
+   In every column except leftmost and rightmost, expand the background
+   downward from any known background pixel through all consecutive unknown
+   pixels.
 
    Then do the same thing upward.
 
@@ -400,7 +401,7 @@ findBackgroundPixels(struct pam *                   const inpamP,
 -----------------------------------------------------------------------------*/
     unsigned char ** pi;
     bool backgroundComplete;
-    unsigned int passes;
+    unsigned int passCt;
 
     pi = newPi(inpamP->width, inpamP->height);
 
@@ -409,29 +410,29 @@ findBackgroundPixels(struct pam *                   const inpamP,
     setEdges(pi, inpamP->width, inpamP->height);
 
     backgroundComplete = FALSE;
-    passes = 0;
-    
+    passCt = 0;
+
     while (!backgroundComplete) {
         bool expandedHoriz, expandedVert;
 
         expandBackgroundHoriz(pi, inpamP->width, inpamP->height,
                               &expandedHoriz);
-    
+
         expandBackgroundVert(pi, inpamP->width, inpamP->height,
                              &expandedVert);
 
         backgroundComplete = !expandedHoriz && !expandedVert;
 
-        ++passes;
+        ++passCt;
     }
 
     if (verbose)
-        pm_message("Background found in %u passes", passes);
+        pm_message("Background found in %u passes", passCt);
 
     *piP = (const unsigned char * const *)pi;
 }
 
-                     
+
 
 static void
 writeOutput(const struct pam *            const inpamP,
@@ -468,16 +469,16 @@ writeOutput(const struct pam *            const inpamP,
 
 
 int
-main(int argc, char *argv[]) {
+main(int argc, const char *argv[]) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     struct pam inpam;
     FILE * ifP;
     pm_filepos rasterpos;
     tuple backgroundColor;
     const unsigned char * const * pi;
-    
-    pnm_init(&argc, argv);
+
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
@@ -500,6 +501,9 @@ main(int argc, char *argv[]) {
     pm_close(ifP);
 
     pnm_freepamtuple(backgroundColor);
-    
+
     return 0;
 }
+
+
+
diff --git a/editor/pamcat.c b/editor/pamcat.c
new file mode 100644
index 00000000..7823bdfc
--- /dev/null
+++ b/editor/pamcat.c
@@ -0,0 +1,1461 @@
+/*=============================================================================
+                                   pamcat
+===============================================================================
+
+  Concatenate images.
+
+  By Bryan Henderson and Akira Urushibata.  Contributed to the public domain
+  by its authors.
+
+=============================================================================*/
+
+#include <stdio.h>
+#include <limits.h>
+#include <assert.h>
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "shhopt.h"
+#include "bitarith.h"
+#include "nstring.h"
+#include "pam.h"
+#include "pbm.h"
+
+#define LEFTBITS pm_byteLeftBits
+#define RIGHTBITS pm_byteRightBits
+
+enum PadColorMethod {PAD_BLACK, PAD_WHITE, PAD_AUTO};
+  /* The method of determining the color of padding when images are not the
+     same height or width.  Always white (maxval samples) always black (zero
+     samples) or determined from what looks like background for the image in
+     question.
+  */
+
+
+enum Orientation {TOPBOTTOM, LEFTRIGHT};
+  /* Direction of concatenation */
+
+enum Justification {JUST_CENTER, JUST_MIN, JUST_MAX};
+  /* Justification of images in concatenation */
+
+/* FOPEN_MAX is usually defined in stdio.h, PATH_MAX in limits.h
+   Given below are typical values.  Adjust as necessary.
+ */
+
+#ifndef FOPEN_MAX
+  #define FOPEN_MAX 16
+#endif
+
+#ifndef PATH_MAX
+  #define PATH_MAX 255
+#endif
+
+
+static const char **
+copyOfStringList(const char ** const list,
+                 unsigned int  const size) {
+
+    const char ** retval;
+    unsigned int i;
+
+    MALLOCARRAY_NOFAIL(retval, size);
+
+    for (i = 0; i < size; ++i)
+        retval[i] = pm_strdup(list[i]);
+
+    return retval;
+}
+
+
+
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char **       inputFileName;
+    unsigned int        inputFileCt;
+    const char *        listfile;  /* NULL if not specified */
+    enum PadColorMethod padColorMethod;
+    enum Orientation    orientation;
+    enum Justification  justification;
+    unsigned int        verbose;
+};
+
+
+static void
+parseCommandLine(int argc, const char ** const argv,
+                 struct CmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   Note that the file spec array we return is stored in the storage that
+   was passed to us as the argv array.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;
+        /* Instructions to OptParseOptions3() on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+
+    unsigned int leftright, topbottom;
+    unsigned int black, white;
+    unsigned int jtop, jbottom, jleft, jright, jcenter;
+    unsigned int listfileSpec;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "leftright",   OPT_FLAG,   NULL, &leftright,         0);
+    OPTENT3(0, "lr",          OPT_FLAG,   NULL, &leftright,         0);
+    OPTENT3(0, "topbottom",   OPT_FLAG,   NULL, &topbottom,         0);
+    OPTENT3(0, "tb",          OPT_FLAG,   NULL, &topbottom,         0);
+    OPTENT3(0, "black",       OPT_FLAG,   NULL, &black,             0);
+    OPTENT3(0, "white",       OPT_FLAG,   NULL, &white,             0);
+    OPTENT3(0, "jtop",        OPT_FLAG,   NULL, &jtop,              0);
+    OPTENT3(0, "jbottom",     OPT_FLAG,   NULL, &jbottom,           0);
+    OPTENT3(0, "jleft",       OPT_FLAG,   NULL, &jleft,             0);
+    OPTENT3(0, "jright",      OPT_FLAG,   NULL, &jright,            0);
+    OPTENT3(0, "jcenter",     OPT_FLAG,   NULL, &jcenter,           0);
+    OPTENT3(0, "listfile",    OPT_STRING, &cmdlineP->listfile,
+            &listfileSpec,      0);
+    OPTENT3(0, "verbose",     OPT_FLAG,   NULL, &cmdlineP->verbose, 0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    free(option_def);
+
+    if (leftright + topbottom > 1)
+        pm_error("You may specify only one of -topbottom (-tb) and "
+                 "-leftright (-lr)");
+    else if (leftright)
+        cmdlineP->orientation = LEFTRIGHT;
+    else if (topbottom)
+        cmdlineP->orientation = TOPBOTTOM;
+    else
+        pm_error("You must specify either -leftright or -topbottom");
+
+    if (black + white > 1)
+        pm_error("You may specify only one of -black and -white");
+    else if (black)
+        cmdlineP->padColorMethod = PAD_BLACK;
+    else if (white)
+        cmdlineP->padColorMethod = PAD_WHITE;
+    else
+        cmdlineP->padColorMethod = PAD_AUTO;
+
+    if (jtop + jbottom + jleft + jright + jcenter > 1)
+        pm_error("You may specify only one of -jtop, -jbottom, "
+                 "-jleft, and -jright");
+    else {
+        switch (cmdlineP->orientation) {
+        case LEFTRIGHT:
+            if (jleft)
+                pm_error("-jleft is invalid with -leftright");
+            if (jright)
+                pm_error("-jright is invalid with -leftright");
+            if (jtop)
+                cmdlineP->justification = JUST_MIN;
+            else if (jbottom)
+                cmdlineP->justification = JUST_MAX;
+            else if (jcenter)
+                cmdlineP->justification = JUST_CENTER;
+            else
+                cmdlineP->justification = JUST_CENTER;
+            break;
+        case TOPBOTTOM:
+            if (jtop)
+                pm_error("-jtop is invalid with -topbottom");
+            if (jbottom)
+                pm_error("-jbottom is invalid with -topbottom");
+            if (jleft)
+                cmdlineP->justification = JUST_MIN;
+            else if (jright)
+                cmdlineP->justification = JUST_MAX;
+            else if (jcenter)
+                cmdlineP->justification = JUST_CENTER;
+            else
+                cmdlineP->justification = JUST_CENTER;
+            break;
+        }
+    }
+
+    if (listfileSpec) {
+        if (argc-1 > 0)
+          pm_error ("You can not specify files on the command line and "
+                    "also -listfile.");
+    } else {
+        cmdlineP->listfile = NULL;
+
+        if (argc-1 < 1) {
+            MALLOCARRAY_NOFAIL(cmdlineP->inputFileName, 1);
+            cmdlineP->inputFileName[0] = "-";
+            cmdlineP->inputFileCt = 1;
+        } else {
+            unsigned int i;
+            unsigned int stdinCt;
+            /* Number of input files user specified as Standard Input */
+
+            MALLOCARRAY_NOFAIL(cmdlineP->inputFileName, argc-1);
+
+            for (i = 0, stdinCt = 0; i < argc-1; ++i) {
+                cmdlineP->inputFileName[i] = argv[1+i];
+                if (streq(argv[1+i], "-"))
+                    ++stdinCt;
+            }
+            cmdlineP->inputFileCt = argc-1;
+            if (stdinCt > 1)
+                pm_error("At most one input image can come from "
+                         "Standard Input.  You specified %u", stdinCt);
+        }
+    }
+}
+
+
+
+static void
+freeCmdLine(struct CmdlineInfo const cmdline) {
+
+    if (!cmdline.listfile)
+        free(cmdline.inputFileName);
+}
+
+
+
+static void
+createInFileListFmFile(const char  *        const listFileNm,
+                       bool                 const verbose,
+                       const char ***       const inputFileNmP,
+                       unsigned int *       const inputFileCtP) {
+
+    FILE * const lfP = pm_openr(listFileNm);
+
+    const char ** inputFileNm;
+    unsigned int inputFileCt;
+    unsigned int emptyLineCt;
+    unsigned int stdinCt;
+    int eof;
+
+    MALLOCARRAY_NOFAIL(inputFileNm, FOPEN_MAX);
+
+    for (inputFileCt = emptyLineCt = stdinCt = eof = 0; !eof; ) {
+
+        size_t lineLen;
+        char * buf;
+        size_t bufferSz;
+
+        buf = NULL;  /* initial value */
+        bufferSz = 0;  /* initial value */
+
+        pm_getline(lfP, &buf, &bufferSz, &eof, &lineLen);
+
+        if (!eof) {
+            if (lineLen == 0)
+                ++emptyLineCt;
+            else if (lineLen > PATH_MAX)
+                pm_error("Path/file name in list file is too long "
+                         "(%u bytes).  Maximum is %u bytes",
+                         (unsigned)lineLen, PATH_MAX);
+            else /* 0 < lineLen < PATH_MAX */ {
+                if (inputFileCt >= FOPEN_MAX)
+                    pm_error("Too many files in list file.  Maximum is %u",
+                             FOPEN_MAX);
+                else {
+                    inputFileNm[inputFileCt] = buf;
+                    ++inputFileCt;
+                    if (streq(buf, "-"))
+                        ++stdinCt;
+                }
+            }
+        }
+    }
+
+    pm_close(lfP);
+
+    if (stdinCt > 1)
+        pm_error("At most one input image can come from Standard Input.  "
+                 "You specified %u", stdinCt);
+
+    if (inputFileCt == 0)
+        pm_error("No files specified in list file.");
+
+    if (verbose) {
+        pm_message("%u files specified and %u blank lines in list file",
+                   inputFileCt, emptyLineCt);
+    }
+
+    *inputFileCtP = inputFileCt;
+    *inputFileNmP = inputFileNm;
+}
+
+
+
+static void
+createInFileList(struct CmdlineInfo const cmdline,
+                 bool               const verbose,
+                 const char ***     const inputFileNmP,
+                 unsigned int *     const inputFileCtP) {
+
+    if (cmdline.listfile)
+        createInFileListFmFile(cmdline.listfile, verbose,
+                               inputFileNmP, inputFileCtP);
+    else {
+        *inputFileCtP = cmdline.inputFileCt;
+        *inputFileNmP = copyOfStringList(cmdline.inputFileName,
+                                         cmdline.inputFileCt);
+    }
+}
+
+
+
+static void
+freeInFileList(const char ** const inputFileNm,
+               unsigned int  const inputFileCt) {
+
+    unsigned int i;
+
+    for (i = 0; i < inputFileCt; ++i)
+        pm_strfree(inputFileNm[i]);
+
+    free(inputFileNm);
+}
+
+
+
+static const char *
+tupletypeX(bool         const allVisual,
+           unsigned int const colorDepth,
+           sample       const maxMaxval,
+           bool         const haveOpacity) {
+
+    const char * retval;
+
+    if (allVisual) {
+        switch (colorDepth) {
+        case 1:
+            if (maxMaxval == 1)
+                retval = haveOpacity ? "BLACKANDWHITE_ALPHA" : "BLACKANDWHITE";
+            else
+                retval = haveOpacity ? "GRAYSCALE_ALPHA"     : "GRAYSCALE";
+            break;
+        case 3:
+            retval = haveOpacity ? "RGB_ALPHA"           : "RGB";
+            break;
+        default:
+            assert(false);
+        }
+    } else
+        retval = "";
+
+    return retval;
+}
+
+
+
+typedef struct {
+    /* This describes a transformation from one tuple type to another,
+       e.g. from BLACKANDWHITE to GRAY_ALPHA.
+
+       For transformations bewteen the defined ones for visual images,
+       only the "up" transformations are covered.
+    */
+    bool mustPromoteColor;
+        /* Plane 0, which is the black/white or grayscale plane and also
+           the red plane must be copied as the red, green, and blue planes
+           (0, 1, and 2).
+        */
+    bool mustPromoteOpacity;
+        /* Plane 1, which is the opacity plane for black and white or
+           grayscale tuples, must be copied as the RGB opacity plane (3).
+        */
+    bool mustCreateOpacity;
+        /* The opacity plane value must be set to opaque */
+
+    bool mustPadZero;
+        /* Where the target tuple type is deeper than the source tuple
+           type, all higher numbered planes must be cleared to zero.
+
+           This is mutually exclusive with the rest of the musts.
+        */
+
+} TtTransform;
+
+
+
+static TtTransform
+ttXformForImg(const struct pam * const inpamP,
+              const struct pam * const outpamP) {
+/*----------------------------------------------------------------------------
+  The transform required to transform tuples of the kind described by *inpamP
+  to tuples of the kind described by *outpamP (e.g. from grayscale to RGB,
+  which involves replicating one plane into three).
+
+  We assume *outpamP tuples are of a type that is at least as expressive as
+  *inpamP tuples.  So e.g. outpamP->tuple_type cannot be "GRAYSCALE" if
+  inpamP->tuple_type is "RGB".
+-----------------------------------------------------------------------------*/
+    TtTransform retval;
+
+    if (inpamP->visual && outpamP->visual) {
+        retval.mustPromoteColor   =
+            (outpamP->color_depth > inpamP->color_depth);
+        retval.mustPromoteOpacity =
+            (outpamP->color_depth > inpamP->color_depth &&
+             (outpamP->have_opacity && inpamP->have_opacity));
+        retval.mustCreateOpacity  =
+            (outpamP->have_opacity && !inpamP->have_opacity);
+        retval.mustPadZero = false;
+    } else {
+        retval.mustPromoteColor   = false;
+        retval.mustPromoteOpacity = false;
+        retval.mustCreateOpacity  = false;
+        retval.mustPadZero        = true;
+    }
+    return retval;
+}
+
+
+
+static void
+reportPlans(unsigned int       const fileCt,
+            const struct pam * const outpamP) {
+
+    pm_message("Concatenating %u input images", fileCt);
+
+    pm_message("Output width, height, depth: %u x %u x %u",
+               outpamP->width, outpamP->height, outpamP->depth);
+
+    if (outpamP->format == RPBM_FORMAT)
+        pm_message("Using PBM fast path and producing raw PBM output");
+    else if (outpamP->format == PBM_FORMAT)
+        pm_message("Output format: Plain PBM");
+    else {
+        pm_message("Output maxval (max of all inputs): %lu", outpamP->maxval);
+
+        switch (outpamP->format) {
+        case PGM_FORMAT:
+            pm_message("Output format: Plain PGM");
+            break;
+        case RPGM_FORMAT:
+            pm_message("Output format: Raw PGM");
+            break;
+        case PPM_FORMAT:
+            pm_message("Output format: Plain PPM");
+            break;
+        case RPPM_FORMAT:
+            pm_message("Output format: Raw PPM");
+            break;
+        case PAM_FORMAT:
+            pm_message("Output format: PAM");
+
+            if (strlen(outpamP->tuple_type) > 0)
+                pm_message("Output tuple type: '%s'", outpamP->tuple_type);
+            else
+                pm_message("Output tuple type is null string because "
+                           "input images have various non-visual tuple types");
+            break;
+        }
+    }
+}
+
+
+
+static void
+computeOutputParms(unsigned int       const fileCt,
+                   enum Orientation   const orientation,
+                   const struct pam * const inpam,  /* array */
+                   bool               const verbose,
+                   struct pam *       const outpamP) {
+
+    double newCols, newRows;
+    unsigned int maxDepth;
+    sample maxMaxval;
+    int newFormat;
+    const char * firstTupletype;
+    bool allSameTt;
+    bool allVisual;
+    unsigned int maxColorDepth;
+    bool haveOpacity;
+    unsigned int fileSeq;
+
+    for (fileSeq = 0, newCols = 0, newRows = 0, maxDepth = 0, maxMaxval = 0,
+             newFormat = 0,
+             allVisual = true, maxColorDepth = 0, haveOpacity = false,
+             firstTupletype = NULL, allSameTt = true;
+         fileSeq < fileCt;
+         ++fileSeq) {
+
+        const struct pam * const inpamP = &inpam[fileSeq];
+
+        switch (orientation) {
+        case LEFTRIGHT:
+            newCols += inpamP->width;
+            newRows = MAX(newRows, inpamP->height);
+            break;
+        case TOPBOTTOM:
+            newRows += inpamP->height;
+            newCols = MAX(newCols, inpamP->width);
+            break;
+        }
+
+        if (!firstTupletype)
+            firstTupletype = inpamP->tuple_type;
+        if (inpamP->tuple_type != firstTupletype)
+            allSameTt = false;
+
+        if (inpamP->visual) {
+            maxColorDepth = MAX(maxColorDepth, inpamP->color_depth);
+
+            if (inpamP->have_opacity)
+                haveOpacity = true;
+        } else
+            allVisual = false;
+
+        maxDepth      = MAX(maxDepth,      inpamP->depth);
+        maxMaxval     = MAX(maxMaxval,     inpamP->maxval);
+
+        if (PAM_FORMAT_TYPE(inpamP->format) > PAM_FORMAT_TYPE(newFormat))
+            newFormat = inpamP->format;
+    }
+    assert(newCols       > 0);
+    assert(newRows       > 0);
+    assert(maxMaxval     > 0);
+    assert(newFormat     > 0);
+
+    if (newCols > INT_MAX)
+       pm_error("Output width too large: %.0f.", newCols);
+    if (newRows > INT_MAX)
+       pm_error("Output height too large: %.0f.", newRows);
+
+    outpamP->size = sizeof(*outpamP);
+    outpamP->len  = PAM_STRUCT_SIZE(tuple_type);
+
+    /* Note that while 'double' is not in general a precise numerical type,
+       in the case of a sum of integers which is less than INT_MAX, it
+       is exact, because double's precision is greater than int's.
+    */
+    outpamP->height           = (unsigned int)newRows;
+    outpamP->width            = (unsigned int)newCols;
+    if (allVisual)
+        outpamP->depth        = MAX(maxDepth,
+                                    maxColorDepth + (haveOpacity ? 1 : 0));
+    else
+        outpamP->depth        = maxDepth;
+    outpamP->allocation_depth = 0;  /* This means same as depth */
+    outpamP->maxval           = maxMaxval;
+    outpamP->format           = newFormat;
+    if (allSameTt)
+        STRSCPY(outpamP->tuple_type, firstTupletype);
+    else
+        STRSCPY(outpamP->tuple_type,
+                tupletypeX(allVisual, maxColorDepth, maxMaxval, haveOpacity));
+    outpamP->comment_p        = NULL;
+    outpamP->plainformat      = false;
+
+    if (verbose)
+        reportPlans(fileCt, outpamP);
+}
+
+
+
+static void
+copyBitrow(const unsigned char * const source,
+           unsigned char *       const destBitrow,
+           unsigned int          const cols,
+           unsigned int          const offset) {
+/*----------------------------------------------------------------------------
+  Copy from source to destBitrow, without shifting.  Preserve
+  surrounding image data.
+-----------------------------------------------------------------------------*/
+    unsigned char * const dest = & destBitrow[ offset/8 ];
+        /* Copy destination, with leading full bytes ignored. */
+    unsigned int const rs = offset % 8;
+        /* The "little offset", as measured from start of dest.  Source
+           is already shifted by this value.
+        */
+    unsigned int const trs = (cols + rs) % 8;
+        /* The number of partial bits in the final char. */
+    unsigned int const colByteCnt = pbm_packed_bytes(cols + rs);
+        /* # bytes to process, including partial ones on both ends. */
+    unsigned int const last = colByteCnt - 1;
+
+    unsigned char const origHead = dest[0];
+    unsigned char const origEnd  = dest[last];
+
+    unsigned int i;
+
+    assert(colByteCnt >= 1);
+
+    for (i = 0; i < colByteCnt; ++i)
+        dest[i] = source[i];
+
+    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);
+}
+
+
+
+static void
+padFillBitrow(unsigned char * const destBitrow,
+              unsigned char   const padColor,
+              unsigned int    const cols,
+              unsigned int    const offset) {
+/*----------------------------------------------------------------------------
+   Fill destBitrow, starting at offset, with padColor.  padColor is a
+   byte -- 0x00 or 0xff -- not a single bit.
+-----------------------------------------------------------------------------*/
+    unsigned char * const dest = &destBitrow[offset/8];
+    unsigned int const rs = offset % 8;
+    unsigned int const trs = (cols + rs) % 8;
+    unsigned int const colByteCnt = pbm_packed_bytes(cols + rs);
+    unsigned int const last = colByteCnt - 1;
+
+    unsigned char const origHead = dest[0];
+    unsigned char const origEnd  = dest[last];
+
+    unsigned int i;
+
+    assert(colByteCnt > 0);
+
+    for (i = 0; i < colByteCnt; ++i)
+        dest[i] = padColor;
+
+    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);
+}
+
+
+
+/* concatenateLeftRightPbm() and concatenateLeftRightGen()
+   employ almost identical algorithms.
+   The difference is in the data types and functions.
+
+   Same for concatenateTopBottomPbm() and concatenateTopBottomGen().
+*/
+
+
+typedef struct {
+    /* Information about one image */
+    unsigned char * proberow;
+        /* Top row of image, when background color is
+           auto-determined.
+        */
+    unsigned int offset;
+        /* start position of image, in bits, counting from left
+           edge
+        */
+    unsigned char background;
+        /* Background color.  0x00 means white; 0xff means black */
+    unsigned int padtop;
+        /* Top padding amount */
+} LrImgCtlPbm;
+
+
+
+static void
+createLrImgCtlPbm(const struct pam *  const inpam,  /* array */
+                  unsigned int        const fileCt,
+                  unsigned int        const outHeight,
+                  enum Justification  const justification,
+                  enum PadColorMethod const padColorMethod,
+                  LrImgCtlPbm **      const imgCtlP) {
+/*----------------------------------------------------------------------------
+   Read the first row of each image in inpam[] and return that and additional
+   information about images as *imgCtlP.
+-----------------------------------------------------------------------------*/
+    LrImgCtlPbm * imgCtl;  /* array, size 'fileCt' */
+    unsigned int fileSeq;
+
+    MALLOCARRAY_NOFAIL(imgCtl, fileCt);
+
+    for (fileSeq = 0; fileSeq < fileCt; ++fileSeq) {
+        LrImgCtlPbm *      const imgCtlP = &imgCtl[fileSeq];
+        const struct pam * const inpamP  = &inpam[fileSeq];
+
+        switch (justification) {
+        case JUST_MIN:
+            imgCtlP->padtop = 0;
+            break;
+        case JUST_MAX:
+            imgCtlP->padtop = outHeight - inpam[fileSeq].height;
+            break;
+        case JUST_CENTER:
+            imgCtlP->padtop = (outHeight - inpamP->height) / 2;
+            break;
+        }
+
+        imgCtlP->offset =
+            (fileSeq == 0) ?
+                0 : imgCtl[fileSeq-1].offset + inpam[fileSeq-1].width;
+
+        if (inpamP->height == outHeight)  /* no padding */
+            imgCtlP->proberow = NULL;
+        else {                   /* determine pad color for image i */
+            switch (padColorMethod) {
+            case PAD_AUTO: {
+                bit bgBit;
+                imgCtlP->proberow =
+                    pbm_allocrow_packed((unsigned int)inpamP->width + 7);
+                pbm_readpbmrow_bitoffset(
+                    inpamP->file, imgCtlP->proberow,
+                    inpamP->width, inpamP->format, imgCtlP->offset % 8);
+
+                bgBit = pbm_backgroundbitrow(
+                    imgCtlP->proberow, inpamP->width,
+                    imgCtlP->offset % 8);
+
+                imgCtlP->background = bgBit == PBM_BLACK ? 0xff : 0x00;
+            } break;
+            case PAD_BLACK:
+                imgCtlP->proberow   = NULL;
+                imgCtlP->background = 0xff;
+                break;
+            case PAD_WHITE:
+                imgCtlP->proberow   = NULL;
+                imgCtlP->background = 0x00;
+                break;
+            }
+        }
+    }
+    *imgCtlP = imgCtl;
+}
+
+
+
+static void
+destroyPbmImgCtl(LrImgCtlPbm * const imgCtl,  /* array */
+                 unsigned int  const fileCt) {
+
+    unsigned int i;
+
+    for (i = 0; i < fileCt; ++i) {
+        if (imgCtl[i].proberow)
+            free(imgCtl[i].proberow);
+    }
+    free(imgCtl);
+}
+
+
+
+static void
+concatenateLeftRightPbm(struct pam *        const outpamP,
+                        const struct pam *  const inpam,  /* array */
+                        unsigned int        const fileCt,
+                        enum Justification  const justification,
+                        enum PadColorMethod const padColorMethod) {
+
+    unsigned char * const outrow = pbm_allocrow_packed(outpamP->width);
+        /* We use just one outrow.  All padding and image data (with the
+           exception of following imgCtl.proberow) goes directly into this
+           packed PBM row.
+        */
+
+    LrImgCtlPbm * imgCtl;
+        /* malloc'ed array, one element per image.  Shadows inpam[] */
+    unsigned int row;
+
+    createLrImgCtlPbm(inpam, fileCt, outpamP->height,
+                      justification, padColorMethod,
+                      &imgCtl);
+
+    outrow[pbm_packed_bytes(outpamP->width)-1] = 0x00;
+
+    for (row = 0; row < outpamP->height; ++row) {
+        unsigned int fileSeq;
+
+        for (fileSeq = 0; fileSeq < fileCt; ++fileSeq) {
+            const LrImgCtlPbm * const imgCtlP = &imgCtl[fileSeq];
+            const struct pam *  const inpamP  = &inpam[fileSeq];
+
+            if ((row == 0 && imgCtlP->padtop > 0) ||
+                row == imgCtlP->padtop + inpamP->height) {
+
+                /* This row begins a run of padding, either above or below
+                   file 'i', so set 'outrow' to padding.
+                */
+                padFillBitrow(outrow, imgCtlP->background, inpamP->width,
+                              imgCtlP->offset);
+            }
+
+            if (row == imgCtlP->padtop && imgCtlP->proberow != NULL) {
+                /* Top row has been read to proberow[] to determine
+                   background.  Copy it to outrow[].
+                */
+                copyBitrow(imgCtlP->proberow, outrow,
+                           inpamP->width, imgCtlP->offset);
+            } else if (row >= imgCtlP->padtop &&
+                       row < imgCtlP->padtop + inpamP->height) {
+                pbm_readpbmrow_bitoffset(
+                    inpamP->file, outrow, inpamP->width, inpamP->format,
+                    imgCtlP->offset);
+            } else {
+                /* It's a row of padding, so outrow[] is already set
+                   appropriately.
+                */
+            }
+        }
+        pbm_writepbmrow_packed(outpamP->file, outrow, outpamP->width, 0);
+    }
+
+    destroyPbmImgCtl(imgCtl, fileCt);
+
+    pbm_freerow_packed(outrow);
+}
+
+
+
+static void
+concatenateTopBottomPbm(const struct pam *  const outpamP,
+                        const struct pam *  const inpam,  /* array */
+                        unsigned int        const fileCt,
+                        enum Justification  const justification,
+                        enum PadColorMethod const padColorMethod) {
+
+    unsigned char * const outrow = pbm_allocrow_packed(outpamP->width);
+        /* Like the left-right PBM case, all padding and image data
+           goes directly into outrow.  There is no proberow.
+        */
+    unsigned char background, backgroundPrev;
+        /* 0x00 means white; 0xff means black */
+    unsigned int  padleft;
+    bool          backChange;
+        /* Background color is different from that of the previous
+           input image.
+        */
+
+    unsigned int fileSeq;
+    unsigned int row, startRow;
+
+    outrow[pbm_packed_bytes(outpamP->width)-1] = 0x00;
+
+    switch (padColorMethod){
+    case PAD_AUTO:   /* do nothing */    break;
+    case PAD_BLACK:  background = 0xff;  break;
+    case PAD_WHITE:  background = 0x00;  break;
+    }
+
+    for (fileSeq = 0; fileSeq < fileCt; ++fileSeq) {
+        const struct pam * const inpamP = &inpam[fileSeq];
+
+        if (inpamP->width == outpamP->width) {
+            /* No padding */
+            startRow   = 0;
+            backChange = FALSE;
+            padleft    = 0;
+            outrow[pbm_packed_bytes(outpamP->width)-1] = 0x00;
+        } else {
+            /* Determine amount of padding and color */
+            switch (justification) {
+            case JUST_MIN:
+                padleft = 0;
+                break;
+            case JUST_MAX:
+                padleft = outpamP->width - inpamP->width;
+                break;
+            case JUST_CENTER:
+                padleft = (outpamP->width - inpamP->width) / 2;
+                break;
+            }
+
+            switch (padColorMethod) {
+            case PAD_AUTO: {
+                bit bgBit;
+
+                startRow = 1;
+
+                pbm_readpbmrow_bitoffset(
+                    inpamP->file, outrow, inpamP->width, inpamP->format,
+                    padleft);
+
+                bgBit = pbm_backgroundbitrow(outrow, inpamP->width, padleft);
+                background = bgBit == PBM_BLACK ? 0xff : 0x00;
+
+                backChange = (fileSeq == 0 || background != backgroundPrev);
+            } break;
+            case PAD_WHITE:
+            case PAD_BLACK:
+                startRow = 0;
+                backChange = (fileSeq == 0);
+                break;
+            }
+
+            if (backChange ||
+                (fileSeq > 0 && inpam[fileSeq-1].width > inpamP->width)) {
+                unsigned int const padright =
+                    outpamP->width - padleft - inpamP->width;
+
+                if (padleft > 0)
+                    padFillBitrow(outrow, background, padleft, 0);
+
+                if (padright > 0)
+                    padFillBitrow(outrow, background, padright,
+                                  padleft + inpamP->width);
+
+            }
+        }
+
+        if (startRow == 1)
+            /* Top row already read for auto background color
+               determination.  Write it out.
+            */
+            pbm_writepbmrow_packed(outpamP->file, outrow, outpamP->width, 0);
+
+        for (row = startRow; row < inpamP->height; ++row) {
+            pbm_readpbmrow_bitoffset(inpamP->file, outrow, inpamP->width,
+                                     inpamP->format, padleft);
+            pbm_writepbmrow_packed(outpamP->file, outrow, outpamP->width, 0);
+        }
+
+        backgroundPrev = background;
+    }
+    pbm_freerow_packed(outrow);
+}
+
+
+
+static void
+padPlanesRow(const struct pam *  const inpamP,
+             tuple *             const outrow,
+             const struct pam *  const outpamP) {
+/*----------------------------------------------------------------------------
+  Rearrange the planes of *outrow as needed to transform them into tuples
+  as described by *outpamP from tuples as described by *inpamP.
+-----------------------------------------------------------------------------*/
+    TtTransform const ttTransform = ttXformForImg(inpamP, outpamP);
+
+    assert(inpamP->allocation_depth >= outpamP->depth);
+
+    if (ttTransform.mustPromoteOpacity) {
+        unsigned int col;
+
+        assert(outpamP->depth >= PAM_TRN_PLANE);
+
+        for (col = 0; col < inpamP->width; ++col) {
+            outrow[col][outpamP->opacity_plane] =
+                outrow[col][inpamP->opacity_plane];
+        }
+    }
+    if (ttTransform.mustPromoteColor) {
+        unsigned int col;
+
+        assert(outpamP->depth >= PAM_GRN_PLANE);
+        assert(outpamP->depth >= PAM_BLU_PLANE);
+
+        for (col = 0; col < inpamP->width; ++col) {
+            assert(PAM_RED_PLANE == 0);
+            outrow[col][PAM_GRN_PLANE] = outrow[col][0];
+            outrow[col][PAM_BLU_PLANE] = outrow[col][0];
+        }
+    }
+
+    if (ttTransform.mustCreateOpacity) {
+        unsigned int col;
+
+        for (col = 0; col < inpamP->width; ++col)
+            outrow[col][outpamP->opacity_plane] = outpamP->maxval;
+    }
+
+    if (ttTransform.mustPadZero) {
+        unsigned int plane;
+
+        for (plane = inpamP->depth; plane < outpamP->depth; ++plane) {
+            unsigned int col;
+
+            for (col = 0; col < inpamP->width; ++col)
+                outrow[col][plane] = 0;
+        }
+    }
+}
+
+
+
+typedef struct {
+/*----------------------------------------------------------------------------
+   Parameters and state for placing a row of a particular input image in
+   the output in a left-right concatenation.
+-----------------------------------------------------------------------------*/
+    tuple *      cachedRow;
+        /* Contents of the current row of the image, with depth and maxval
+           adjusted for output, in malloc'ed space belonging to this object.
+           Input file is positioned past this row.  Null if data not present
+           and input file is positioned to the current row.
+        */
+    tuple *      out;
+        /* Point in output row buffer where the row from this image goes */
+    tuple        background;
+    unsigned int padtop;
+        /* Number of rows of padding that go above this image in the output */
+} LrImgCtl;
+
+
+
+static void
+createLrImgCtlArray(const struct pam *  const inpam,  /* array */
+                    unsigned int        const fileCt,
+                    tuple *             const newTuplerow,
+                    const struct pam *  const outpamP,
+                    enum Justification  const justification,
+                    enum PadColorMethod const padColorMethod,
+                    LrImgCtl **         const imgCtlP) {
+
+    LrImgCtl * imgCtl;  /* array */
+    unsigned int fileSeq;
+
+    MALLOCARRAY_NOFAIL(imgCtl, fileCt);
+
+    for (fileSeq = 0; fileSeq < fileCt; ++fileSeq) {
+        LrImgCtl *         const thisEntryP = &imgCtl[fileSeq];
+        const struct pam * const inpamP     = &inpam[fileSeq];
+
+        switch (justification) {  /* Determine top padding */
+            case JUST_MIN:
+                thisEntryP->padtop = 0;
+                break;
+            case JUST_MAX:
+                thisEntryP->padtop = outpamP->height - inpamP->height;
+                break;
+            case JUST_CENTER:
+                thisEntryP->padtop = (outpamP->height - inpamP->height) / 2;
+                break;
+        }
+
+        thisEntryP->out =
+            (fileSeq == 0 ?
+             &newTuplerow[0] : imgCtl[fileSeq-1].out + inpam[fileSeq-1].width);
+
+        if (inpamP->height == outpamP->height) { /* no vertical padding */
+            thisEntryP->cachedRow  = NULL;
+            pnm_createBlackTuple(outpamP, &thisEntryP->background);
+                /* Meaningless because no padding */
+        } else {
+            /* Determine pad color */
+            switch (padColorMethod){
+            case PAD_AUTO:
+                thisEntryP->cachedRow = pnm_allocpamrow(inpamP);
+                pnm_readpamrow(inpamP, thisEntryP->cachedRow);
+                pnm_scaletuplerow(inpamP, thisEntryP->cachedRow,
+                                  thisEntryP->cachedRow, outpamP->maxval);
+                padPlanesRow(inpamP, thisEntryP->cachedRow, outpamP);
+                {
+                    struct pam cachedRowPam;
+                    cachedRowPam = *outpamP;
+                    cachedRowPam.width = inpamP->width;
+                    thisEntryP->background = pnm_backgroundtuplerow(
+                        &cachedRowPam, thisEntryP->cachedRow);
+                }
+                break;
+            case PAD_BLACK:
+                thisEntryP->cachedRow = NULL;
+                pnm_createBlackTuple(outpamP, &thisEntryP->background);
+                break;
+            case PAD_WHITE:
+                thisEntryP->cachedRow = NULL;
+                pnm_createWhiteTuple(outpamP, &thisEntryP->background);
+                break;
+            }
+        }
+        if (outpamP->visual) {
+            /* Any opacity sample in background color tuple is meaningless at
+               this point; make it opaque.
+            */
+            if (outpamP->have_opacity) {
+                thisEntryP->background[outpamP->opacity_plane] =
+                    outpamP->maxval;
+            }
+        }
+
+    }
+    *imgCtlP = imgCtl;
+}
+
+
+
+static void
+destroyLrImgCtlArray(LrImgCtl *   const imgCtl,  /* array */
+                     unsigned int const fileCt) {
+
+    unsigned int fileSeq;
+
+    for (fileSeq = 0; fileSeq < fileCt; ++fileSeq) {
+        LrImgCtl * const thisEntryP = &imgCtl[fileSeq];
+
+        pnm_freepamtuple(thisEntryP->background);
+        pnm_freepamrow(thisEntryP->cachedRow);
+    }
+
+    free(imgCtl);
+}
+
+
+
+static void
+concatenateLeftRightGen(const struct pam *  const outpamP,
+                        const struct pam *  const inpam,  /* array */
+                        unsigned int        const fileCt,
+                        enum Justification  const justification,
+                        enum PadColorMethod const padColorMethod) {
+
+    tuple * const outrow = pnm_allocpamrow(outpamP);
+
+    LrImgCtl *   imgCtl;
+    unsigned int row;
+
+    createLrImgCtlArray(inpam, fileCt, outrow, outpamP,
+                        justification, padColorMethod,
+                        &imgCtl);
+
+    for (row = 0; row < outpamP->height; ++row) {
+        unsigned int fileSeq;
+
+        for (fileSeq = 0; fileSeq < fileCt; ++fileSeq) {
+            LrImgCtl *   const thisEntryP   = &imgCtl[fileSeq];
+            const struct pam * const inpamP = &inpam[fileSeq];
+
+            if ((row == 0 && thisEntryP->padtop > 0) ||
+                row == thisEntryP->padtop + inpamP->height) {
+                /* This row begins a run of padding, either above or below
+                   image 'fileSeq', so set its part of outrow[] to padding.
+                */
+                unsigned int col;
+                for (col = 0; col < inpamP->width; ++col) {
+                    pnm_assigntuple(outpamP, thisEntryP->out[col],
+                                    thisEntryP->background);
+                }
+            }
+            if (row == thisEntryP->padtop && thisEntryP->cachedRow) {
+                /* We're at the top row of image 'fileSeq', and that row
+                   has already been read to cachedRow[] to determine
+                   background.  Copy it to image fileseq's part of outrow[].
+                */
+                unsigned int col;
+                for (col = 0; col < inpamP->width; ++col) {
+                    pnm_assigntuple(outpamP, thisEntryP->out[col],
+                                    thisEntryP->cachedRow[col]);
+                }
+                free(thisEntryP->cachedRow);
+                thisEntryP->cachedRow = NULL;
+            } else if (row >= thisEntryP->padtop &&
+                       row < thisEntryP->padtop + inpamP->height) {
+                pnm_readpamrow(inpamP, thisEntryP->out);
+                pnm_scaletuplerow(inpamP, thisEntryP->out,
+                                  thisEntryP->out, outpamP->maxval);
+                padPlanesRow(inpamP, thisEntryP->out, outpamP);
+            } else {
+                /* It's a row of padding, so image filesSeq's part of outrow[]
+                   is already set appropriately.
+                */
+            }
+        }
+        /* Note that imgCtl[N].out[] is an alias to part of outrow[], so
+           outrow[] has been set.
+        */
+        pnm_writepamrow(outpamP, outrow);
+    }
+    destroyLrImgCtlArray(imgCtl, fileCt);
+
+    pnm_freepamrow(outrow);
+}
+
+
+
+static tuple
+initialBackgroundColor(const struct pam *  const outpamP,
+                       enum PadColorMethod const padColorMethod) {
+
+    tuple retval;
+
+    switch (padColorMethod) {
+    case PAD_AUTO:
+        /* Background is different for each input image */
+        retval = pnm_allocpamtuple(outpamP);
+            /* Dummy value; just need something to free */
+        break;
+    case PAD_BLACK:
+        pnm_createBlackTuple(outpamP, &retval);
+        break;
+    case PAD_WHITE:
+        pnm_createWhiteTuple(outpamP, &retval);
+        break;
+    }
+
+    if (outpamP->visual) {
+        /* Any opacity sample in background color tuple is meaningless at this
+           point; make it opaque.
+        */
+        if (outpamP->have_opacity)
+            retval[outpamP->opacity_plane] = outpamP->maxval;
+    }
+
+    return retval;
+}
+
+
+
+static unsigned int
+leftPadAmount(const struct pam * const outpamP,
+              const struct pam * const inpamP,
+              enum Justification const justification) {
+
+    switch (justification) {
+    case JUST_MIN:    return 0;
+    case JUST_MAX:    return outpamP->width - inpamP->width;
+    case JUST_CENTER: return (outpamP->width - inpamP->width) / 2;
+    }
+    assert(false);
+}
+
+
+
+static void
+setHorizPadding(tuple *            const newTuplerow,
+                const struct pam * const outpamP,
+                bool               const backChanged,
+                const struct pam * const inpam,  /* array */
+                unsigned int       const imageSeq,
+                unsigned int       const padLeft,
+                tuple              const background) {
+/*----------------------------------------------------------------------------
+   Set the left and right padding for an output row in a top-bottom
+   concatenation.
+
+   'newTuplerow' is where we set the padding (and also assumed to hold the
+   contents of the previous output row).  *outpamP describes it.
+
+   'backChanged' means the background color is different for the current row
+   from that of the previous row.
+
+   inpam[] is the array of descriptors for all the input images.  'imageSeq'
+   is the index into this array for the current image.
+
+   'background' is the background color to set.
+-----------------------------------------------------------------------------*/
+    if (backChanged ||
+        (imageSeq > 0 && inpam[imageSeq-1].width > inpam[imageSeq].width)) {
+        unsigned int col;
+
+        for (col = 0; col < padLeft; ++col)
+            pnm_assigntuple(outpamP, newTuplerow[col], background);
+        for (col = padLeft + inpam[imageSeq].width;
+             col < outpamP->width;
+             ++col) {
+            pnm_assigntuple(outpamP, newTuplerow[col], background);
+        }
+    } else {
+        /* No need to pad because newTuplerow[] already contains the
+           correct padding from the previous row.
+        */
+    }
+}
+
+
+
+static void
+readFirstTBRowAndDetermineBackground(const struct pam *  const inpamP,
+                                     const struct pam *  const outpamP,
+                                     tuple *             const out,
+                                     tuple *             const backgroundP) {
+/*----------------------------------------------------------------------------
+   Read the first row of an input image into 'out', adjusting it to conform
+   to the output depth and maxval described by *outpamP.
+
+   The image is positioned to the first row at entry.
+
+   From this row, determine the background color for the input image and
+   return it as *backgroundP (a newly malloced tuple).
+-----------------------------------------------------------------------------*/
+    pnm_readpamrow(inpamP, out);
+
+    pnm_scaletuplerow(inpamP, out, out, outpamP->maxval);
+
+    padPlanesRow(inpamP, out, outpamP);
+
+    {
+        struct pam partialOutpam;
+            /* Descriptor for the input image with depth and maxval adjusted to
+               that of the output image.
+            */
+        tuple background;
+
+        partialOutpam = *outpamP;
+        partialOutpam.width = inpamP->width;
+
+        background = pnm_backgroundtuplerow(&partialOutpam, out);
+
+        if (outpamP->visual) {
+            /* Make the background opaque. */
+            if (outpamP->have_opacity)
+                background[outpamP->opacity_plane] = outpamP->maxval;
+        }
+
+        *backgroundP = background;
+    }
+}
+
+
+
+static void
+concatenateTopBottomGen(const struct pam *  const outpamP,
+                        const struct pam *  const inpam,  /* array */
+                        unsigned int        const fileCt,
+                        enum Justification  const justification,
+                        enum PadColorMethod const padColorMethod) {
+
+    tuple * const newTuplerow = pnm_allocpamrow(outpamP);
+    tuple * out;
+        /* The location in newTuplerow[] that the row from the current
+           input image goes.
+        */
+    unsigned int fileSeq;
+    tuple background;
+    tuple backgroundPrev;
+
+    background = initialBackgroundColor(outpamP, padColorMethod);
+
+    for (fileSeq = 0; fileSeq < fileCt; ++fileSeq) {
+        const struct pam * const inpamP = &inpam[fileSeq];
+
+        unsigned int row;
+        unsigned int startRow;
+        bool backChanged;
+            /* The background color is different from that of the previous
+               input image.
+            */
+
+        if (inpamP->width == outpamP->width) {
+            /* no padding */
+            startRow = 0;
+            backChanged = false;
+            out = &newTuplerow[0];
+        } else {
+            unsigned int const padLeft =
+                leftPadAmount(outpamP, inpamP, justification);
+
+            if (padColorMethod == PAD_AUTO) {
+                out = &newTuplerow[padLeft];
+                backgroundPrev = background;
+                readFirstTBRowAndDetermineBackground(
+                    inpamP, outpamP, out, &background);
+
+                backChanged =
+                    fileSeq == 0 ||
+                        pnm_tupleequal(outpamP, background, backgroundPrev);
+                pnm_freepamtuple(backgroundPrev);
+
+                startRow = 1;
+            } else {
+                /* Background color is constant: black or white */
+                startRow = 0;
+                out = &newTuplerow[padLeft];
+                backChanged = (fileSeq == 0);
+            }
+
+            setHorizPadding(newTuplerow, outpamP, backChanged, inpam, fileSeq,
+                            padLeft, background);
+        }
+
+        if (startRow == 1)
+            /* Top row was already read for auto background color
+               determination.  Write it out.
+            */
+            pnm_writepamrow(outpamP, newTuplerow);
+
+        for (row = startRow; row < inpamP->height; ++row) {
+            pnm_readpamrow(inpamP, out);
+
+            pnm_scaletuplerow(inpamP, out, out, outpamP->maxval);
+
+            padPlanesRow(inpamP, out, outpamP);
+
+            pnm_writepamrow(outpamP, newTuplerow);
+        }
+    }
+    pnm_freepamtuple(background);
+    pnm_freepamrow(newTuplerow);
+}
+
+
+
+int
+main(int           argc,
+     const char ** argv) {
+
+    struct CmdlineInfo cmdline;
+    const char ** inputFileNm;
+    unsigned int inputFileCt;
+    struct pam * inpam;  /* malloc'ed array */
+    struct pam outpam;
+    unsigned int i;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    createInFileList(cmdline, !!cmdline.verbose, &inputFileNm, &inputFileCt);
+
+    MALLOCARRAY_NOFAIL(inpam, inputFileCt);
+
+    for (i = 0; i < inputFileCt; ++i) {
+        FILE *  ifP;
+        ifP = pm_openr(inputFileNm[i]);
+        inpam[i].comment_p = NULL;  /* Don't want to see the comments */
+        pnm_readpaminit(ifP, &inpam[i], PAM_STRUCT_SIZE(opacity_plane));
+    }
+
+    computeOutputParms(inputFileCt, cmdline.orientation, inpam,
+                       cmdline.verbose, &outpam);
+
+    outpam.file = stdout;
+
+    for (i = 0; i < inputFileCt; ++i)
+        pnm_setminallocationdepth(&inpam[i], outpam.depth);
+
+    pnm_writepaminit(&outpam);
+
+    if (outpam.format == RPBM_FORMAT) {
+        switch (cmdline.orientation) {
+        case LEFTRIGHT:
+            concatenateLeftRightPbm(&outpam, inpam, inputFileCt,
+                                    cmdline.justification,
+                                    cmdline.padColorMethod);
+            break;
+        case TOPBOTTOM:
+            concatenateTopBottomPbm(&outpam, inpam, inputFileCt,
+                                    cmdline.justification,
+                                    cmdline.padColorMethod);
+            break;
+        }
+    } else {
+        switch (cmdline.orientation) {
+        case LEFTRIGHT:
+            concatenateLeftRightGen(&outpam, inpam, inputFileCt,
+                                    cmdline.justification,
+                                    cmdline.padColorMethod);
+            break;
+        case TOPBOTTOM:
+            concatenateTopBottomGen(&outpam, inpam, inputFileCt,
+                                    cmdline.justification,
+                                    cmdline.padColorMethod);
+            break;
+        }
+    }
+    for (i = 0; i < inputFileCt; ++i)
+        pm_close(inpam[i].file);
+    free(inpam);
+    freeInFileList(inputFileNm, inputFileCt);
+    freeCmdLine(cmdline);
+    pm_close(stdout);
+
+    return 0;
+}
+
+
+
diff --git a/editor/pamcomp.c b/editor/pamcomp.c
index 6e1e7f7d..9ccd41c7 100644
--- a/editor/pamcomp.c
+++ b/editor/pamcomp.c
@@ -208,117 +208,49 @@ parseCommandLine(int                        argc,
 
 
 
-static int
-commonFormat(int const formatA,
-             int const formatB) {
-/*----------------------------------------------------------------------------
-   Return a viable format for the result of composing the two formats
-   'formatA' and 'formatB'.
------------------------------------------------------------------------------*/
-    int retval;
-
-    int const typeA = PAM_FORMAT_TYPE(formatA);
-    int const typeB = PAM_FORMAT_TYPE(formatB);
-
-    if (typeA == PAM_TYPE || typeB == PAM_TYPE)
-        retval = PAM_FORMAT;
-    else if (typeA == PPM_TYPE || typeB == PPM_TYPE)
-        retval = PPM_FORMAT;
-    else if (typeA == PGM_TYPE || typeB == PGM_TYPE)
-        retval = PGM_FORMAT;
-    else if (typeA == PBM_TYPE || typeB == PBM_TYPE)
-        retval = PBM_FORMAT;
-    else {
-        /* Results are undefined for this case, so we do a hail Mary. */
-        retval = formatA;
-    }
-    return retval;
-}
-
-
-
-typedef enum { TT_BLACKANDWHITE, TT_GRAYSCALE, TT_RGB } BaseTupletype;
-
-
-
-static BaseTupletype
-commonTupletype(const char * const tupletypeA,
-                const char * const tupletypeB) {
-
-    if (strneq(tupletypeA, "RGB", 3) ||
-        strneq(tupletypeB, "RGB", 3))
-        return TT_RGB;
-    else if (strneq(tupletypeA, "GRAYSCALE", 9) ||
-             strneq(tupletypeB, "GRAYSCALE", 9))
-        return TT_GRAYSCALE;
-    else if (strneq(tupletypeA, "BLACKANDWHITE", 13) ||
-             strneq(tupletypeB, "BLACKANDWHITE", 13))
-        return TT_BLACKANDWHITE;
-    else
-        /* Results are undefined for this case, so we do a hail Mary. */
-        return TT_RGB;
-}
-
-
-
 static void
-determineOutputTupleType(BaseTupletype const baseTupletype,
-                         bool          const underlayHaveOpacity,
-                         char *        const tupleType,
-                         size_t        const size) {
+initAlphaFile(struct CmdlineInfo const cmdline,
+              struct pam *       const overlayPamP,
+              FILE **            const filePP,
+              struct pam *       const pamP) {
 
-    char buffer[80];
+    FILE * fileP;
 
-    switch (baseTupletype) {
-    case TT_BLACKANDWHITE:
-        STRSCPY(buffer, "RGB");
-        break;
-    case TT_GRAYSCALE:
-        STRSCPY(buffer, "GRAYSCALE");
-        break;
-    case TT_RGB:
-        STRSCPY(buffer, "RGB");
-        break;
-    }
+    if (cmdline.alphaFilespec) {
+        fileP = pm_openr(cmdline.alphaFilespec);
+        pamP->comment_p = NULL;
+        pnm_readpaminit(fileP, pamP, PAM_STRUCT_SIZE(opacity_plane));
 
-    if (underlayHaveOpacity)
-        STRSCAT(buffer, "_ALPHA");
+        if (overlayPamP->width != pamP->width ||
+            overlayPamP->height != pamP->height)
+            pm_error("Opacity map and overlay image are not the same size");
+    } else
+        fileP = NULL;
 
-    strncpy(tupleType, buffer, size);
+    *filePP = fileP;
 }
 
 
 
-static void
-determineOutputType(const struct pam * const underlayPamP,
-                    const struct pam * const overlayPamP,
-                    struct pam *       const composedPamP) {
-
-    BaseTupletype const baseTupletype =
-        commonTupletype(underlayPamP->tuple_type, overlayPamP->tuple_type);
-
-    composedPamP->height = underlayPamP->height;
-    composedPamP->width  = underlayPamP->width;
+typedef enum { TT_BLACKANDWHITE, TT_GRAYSCALE, TT_RGB } BaseTupletype;
 
-    composedPamP->format = commonFormat(underlayPamP->format,
-                                        overlayPamP->format);
-    composedPamP->plainformat = FALSE;
 
-    composedPamP->maxval = pm_lcm(underlayPamP->maxval, overlayPamP->maxval,
-                                  1, PNM_OVERALLMAXVAL);
 
-    composedPamP->visual = true;
-    composedPamP->color_depth = (baseTupletype == TT_RGB ? 3 : 1);
-    composedPamP->have_opacity = underlayPamP->have_opacity;
-    composedPamP->opacity_plane = (baseTupletype == TT_RGB ? 3 : 1);
-
-    composedPamP->depth =
-        (baseTupletype == TT_RGB ? 3 : 1) +
-        (underlayPamP->have_opacity ? 1 : 0);
+static void
+validateComputableHeight(int const originTop,
+                         int const overRows) {
 
-    determineOutputTupleType(baseTupletype, underlayPamP->have_opacity,
-                             composedPamP->tuple_type,
-                             sizeof(composedPamP->tuple_type));
+    if (originTop < 0) {
+        if (originTop < -INT_MAX)
+            pm_error("Overlay starts too far above the underlay image to be "
+                     "computable.  Overlay can be at most %d rows above "
+                     "the underlay.", INT_MAX);
+    } else {
+        if (INT_MAX - originTop <= overRows)
+            pm_error("Too many total rows involved to be computable.  "
+                     "You must have a shorter overlay image or compose it "
+                     "higher on the underlay image.");
+    }
 }
 
 
@@ -362,25 +294,6 @@ warnOutOfFrame(int const originLeft,
 
 
 static void
-validateComputableHeight(int const originTop,
-                         int const overRows) {
-
-    if (originTop < 0) {
-        if (originTop < -INT_MAX)
-            pm_error("Overlay starts too far above the underlay image to be "
-                     "computable.  Overlay can be at most %d rows above "
-                     "the underlay.", INT_MAX);
-    } else {
-        if (INT_MAX - originTop <= overRows)
-            pm_error("Too many total rows involved to be computable.  "
-                     "You must have a shorter overlay image or compose it "
-                     "higher on the underlay image.");
-    }
-}
-
-
-
-static void
 computeOverlayPosition(int                const underCols,
                        int                const underRows,
                        int                const overCols,
@@ -483,6 +396,194 @@ computeOverlayPosition(int                const underCols,
 
 
 
+static BaseTupletype
+commonTupletype(const char * const tupletypeA,
+                const char * const tupletypeB) {
+
+    if (strneq(tupletypeA, "RGB", 3) ||
+        strneq(tupletypeB, "RGB", 3))
+        return TT_RGB;
+    else if (strneq(tupletypeA, "GRAYSCALE", 9) ||
+             strneq(tupletypeB, "GRAYSCALE", 9))
+        return TT_GRAYSCALE;
+    else if (strneq(tupletypeA, "BLACKANDWHITE", 13) ||
+             strneq(tupletypeB, "BLACKANDWHITE", 13))
+        return TT_BLACKANDWHITE;
+    else
+        /* Results are undefined for this case, so we do a hail Mary. */
+        return TT_RGB;
+}
+
+
+
+static int
+commonFormat(int const formatA,
+             int const formatB) {
+/*----------------------------------------------------------------------------
+   Return a viable format for the result of composing the two formats
+   'formatA' and 'formatB'.
+-----------------------------------------------------------------------------*/
+    int retval;
+
+    int const typeA = PAM_FORMAT_TYPE(formatA);
+    int const typeB = PAM_FORMAT_TYPE(formatB);
+
+    if (typeA == PAM_TYPE || typeB == PAM_TYPE)
+        retval = PAM_FORMAT;
+    else if (typeA == PPM_TYPE || typeB == PPM_TYPE)
+        retval = PPM_FORMAT;
+    else if (typeA == PGM_TYPE || typeB == PGM_TYPE)
+        retval = PGM_FORMAT;
+    else if (typeA == PBM_TYPE || typeB == PBM_TYPE)
+        retval = PBM_FORMAT;
+    else {
+        /* Results are undefined for this case, so we do a hail Mary. */
+        retval = formatA;
+    }
+    return retval;
+}
+
+
+
+static void
+determineOutputTupleType(BaseTupletype const baseTupletype,
+                         bool          const underlayHaveOpacity,
+                         char *        const tupleType,
+                         size_t        const size) {
+
+    char buffer[80];
+
+    switch (baseTupletype) {
+    case TT_BLACKANDWHITE:
+        STRSCPY(buffer, "RGB");
+        break;
+    case TT_GRAYSCALE:
+        STRSCPY(buffer, "GRAYSCALE");
+        break;
+    case TT_RGB:
+        STRSCPY(buffer, "RGB");
+        break;
+    }
+
+    if (underlayHaveOpacity)
+        STRSCAT(buffer, "_ALPHA");
+
+    strncpy(tupleType, buffer, size);
+}
+
+
+
+static void
+determineOutputType(const struct pam * const underlayPamP,
+                    const struct pam * const overlayPamP,
+                    struct pam *       const composedPamP) {
+
+    BaseTupletype const baseTupletype =
+        commonTupletype(underlayPamP->tuple_type, overlayPamP->tuple_type);
+
+    composedPamP->height = underlayPamP->height;
+    composedPamP->width  = underlayPamP->width;
+
+    composedPamP->format = commonFormat(underlayPamP->format,
+                                        overlayPamP->format);
+    composedPamP->plainformat = FALSE;
+
+    composedPamP->maxval = pm_lcm(underlayPamP->maxval, overlayPamP->maxval,
+                                  1, PNM_OVERALLMAXVAL);
+
+    composedPamP->visual = true;
+    composedPamP->color_depth = (baseTupletype == TT_RGB ? 3 : 1);
+    composedPamP->have_opacity = underlayPamP->have_opacity;
+    composedPamP->opacity_plane = (baseTupletype == TT_RGB ? 3 : 1);
+
+    composedPamP->depth =
+        (baseTupletype == TT_RGB ? 3 : 1) +
+        (underlayPamP->have_opacity ? 1 : 0);
+
+    determineOutputTupleType(baseTupletype, underlayPamP->have_opacity,
+                             composedPamP->tuple_type,
+                             sizeof(composedPamP->tuple_type));
+}
+
+
+
+static void
+determineInputAdaptations(const struct pam * const underlayPamP,
+                          const struct pam * const overlayPamP,
+                          const struct pam * const composedPamP,
+                          struct pam *       const adaptUnderlayPamP,
+                          struct pam *       const adaptOverlayPamP) {
+/*----------------------------------------------------------------------------
+   For easy of computation, this program reads a tuple row from one of the
+   input files, then transforms it something similar to the format of the
+   eventual output tuple row.  E.g. if the input is grayscale and the
+   output color, it converts the depth 1 row read from the file to a depth
+   3 row for use in computations.
+
+   This function determines what the result of that transformation should be.
+   It's not as simple as it sounds because of opacity.  The overlay may have
+   an opacity plane that has to be kept for the computations, while the output
+   has no opacity plane.
+
+   Our output PAMs are meaningless except in the fields that pertain to a
+   row of tuples.  E.g. the file descriptor and image height members are
+   meaningless.
+-----------------------------------------------------------------------------*/
+    /* We make the underlay row identical to the composed (output) row,
+       except for its width.
+    */
+
+    *adaptUnderlayPamP = *composedPamP;
+    adaptUnderlayPamP->width = underlayPamP->width;
+
+    /* Same for the overlay row, except that it retains is original
+       opacity.
+    */
+
+    adaptOverlayPamP->width = overlayPamP->width;
+    adaptOverlayPamP->tuple_type[0] = '\0';  /* a hack; this doesn't matter */
+    adaptOverlayPamP->visual = true;
+    adaptOverlayPamP->color_depth = composedPamP->color_depth;
+    adaptOverlayPamP->have_opacity = overlayPamP->have_opacity;
+    adaptOverlayPamP->opacity_plane = composedPamP->color_depth;
+    adaptOverlayPamP->depth =
+        composedPamP->color_depth +
+        (overlayPamP->have_opacity ? 1 : 0);
+    adaptOverlayPamP->maxval = composedPamP->maxval;
+    adaptOverlayPamP->bytes_per_sample = composedPamP->bytes_per_sample;
+    adaptOverlayPamP->allocation_depth = overlayPamP->allocation_depth;
+}
+
+
+
+static void
+adaptRowFormat(struct pam * const inpamP,
+               struct pam * const outpamP,
+               tuple *      const tuplerow) {
+/*----------------------------------------------------------------------------
+   Convert the row in 'tuplerow', which is in a format described by
+   *inpamP, to the format described by *outpamP.
+
+   'tuplerow' must have enough allocated depth to do this.
+-----------------------------------------------------------------------------*/
+    assert(outpamP->visual);
+    assert(inpamP->visual);
+
+    pnm_scaletuplerow(inpamP, tuplerow, tuplerow, outpamP->maxval);
+
+    if (outpamP->color_depth == 3) {
+        if (outpamP->have_opacity)
+            pnm_makerowrgba(inpamP, tuplerow);
+        else
+            pnm_makerowrgb(inpamP, tuplerow);
+    } else {
+        if (outpamP->have_opacity)
+            pnm_addopacityrow(inpamP, tuplerow);
+    }
+}
+
+
+
 static sample
 composeComponents(sample           const compA,
                   sample           const compB,
@@ -680,34 +781,6 @@ overlayPixel(tuple            const overlayTuple,
 
 
 static void
-adaptRowFormat(struct pam * const inpamP,
-               struct pam * const outpamP,
-               tuple *      const tuplerow) {
-/*----------------------------------------------------------------------------
-   Convert the row in 'tuplerow', which is in a format described by
-   *inpamP, to the format described by *outpamP.
-
-   'tuplerow' must have enough allocated depth to do this.
------------------------------------------------------------------------------*/
-    assert(outpamP->visual);
-    assert(inpamP->visual);
-
-    pnm_scaletuplerow(inpamP, tuplerow, tuplerow, outpamP->maxval);
-
-    if (outpamP->color_depth == 3) {
-        if (outpamP->have_opacity)
-            pnm_makerowrgba(inpamP, tuplerow);
-        else
-            pnm_makerowrgb(inpamP, tuplerow);
-    } else {
-        if (outpamP->have_opacity)
-            pnm_addopacityrow(inpamP, tuplerow);
-    }
-}
-
-
-
-static void
 composeRow(int              const originleft,
            struct pam *     const underlayPamP,
            struct pam *     const overlayPamP,
@@ -751,55 +824,6 @@ composeRow(int              const originleft,
 
 
 static void
-determineInputAdaptations(const struct pam * const underlayPamP,
-                          const struct pam * const overlayPamP,
-                          const struct pam * const composedPamP,
-                          struct pam *       const adaptUnderlayPamP,
-                          struct pam *       const adaptOverlayPamP) {
-/*----------------------------------------------------------------------------
-   For easy of computation, this program reads a tuple row from one of the
-   input files, then transforms it something similar to the format of the
-   eventual output tuple row.  E.g. if the input is grayscale and the
-   output color, it converts the depth 1 row read from the file to a depth
-   3 row for use in computations.
-
-   This function determines what the result of that transformation should be.
-   It's not as simple as it sounds because of opacity.  The overlay may have
-   an opacity plane that has to be kept for the computations, while the output
-   has no opacity plane.
-
-   Our output PAMs are meaningless except in the fields that pertain to a
-   row of tuples.  E.g. the file descriptor and image height members are
-   meaningless.
------------------------------------------------------------------------------*/
-    /* We make the underlay row identical to the composed (output) row,
-       except for its width.
-    */
-
-    *adaptUnderlayPamP = *composedPamP;
-    adaptUnderlayPamP->width = underlayPamP->width;
-
-    /* Same for the overlay row, except that it retains is original
-       opacity.
-    */
-
-    adaptOverlayPamP->width = overlayPamP->width;
-    adaptOverlayPamP->tuple_type[0] = '\0';  /* a hack; this doesn't matter */
-    adaptOverlayPamP->visual = true;
-    adaptOverlayPamP->color_depth = composedPamP->color_depth;
-    adaptOverlayPamP->have_opacity = overlayPamP->have_opacity;
-    adaptOverlayPamP->opacity_plane = composedPamP->color_depth;
-    adaptOverlayPamP->depth =
-        composedPamP->color_depth +
-        (overlayPamP->have_opacity ? 1 : 0);
-    adaptOverlayPamP->maxval = composedPamP->maxval;
-    adaptOverlayPamP->bytes_per_sample = composedPamP->bytes_per_sample;
-    adaptOverlayPamP->allocation_depth = overlayPamP->allocation_depth;
-}
-
-
-
-static void
 composite(int          const originleft,
           int          const origintop,
           struct pam * const underlayPamP,
@@ -899,30 +923,6 @@ composite(int          const originleft,
 
 
 
-static void
-initAlphaFile(struct CmdlineInfo const cmdline,
-              struct pam *       const overlayPamP,
-              FILE **            const filePP,
-              struct pam *       const pamP) {
-
-    FILE * fileP;
-
-    if (cmdline.alphaFilespec) {
-        fileP = pm_openr(cmdline.alphaFilespec);
-        pamP->comment_p = NULL;
-        pnm_readpaminit(fileP, pamP, PAM_STRUCT_SIZE(opacity_plane));
-
-        if (overlayPamP->width != pamP->width ||
-            overlayPamP->height != pamP->height)
-            pm_error("Opacity map and overlay image are not the same size");
-    } else
-        fileP = NULL;
-
-    *filePP = fileP;
-}
-
-
-
 int
 main(int argc, const char *argv[]) {
 
diff --git a/editor/pamcut.c b/editor/pamcut.c
index 1c7cb4a7..7870fd70 100644
--- a/editor/pamcut.c
+++ b/editor/pamcut.c
@@ -17,6 +17,7 @@
 #include "pam.h"
 #include "shhopt.h"
 #include "mallocvar.h"
+#include "nstring.h"
 
 #define UNSPEC INT_MAX
     /* UNSPEC is the value we use for an argument that is not specified
@@ -35,10 +36,10 @@ typedef struct {
 
            If LOCTYPE_NONE: Meaningless
 
-           If LOCTYPE_FROMFAR: Number of colums from the far edge of the image
+           If LOCTYPE_FROMFAR: Number of columns from the far edge of the image
            (right or bottom).  Last column/row is 1.
 
-           If LOCTYPE_FROMNEAR: Number of colums from the near edge of the
+           If LOCTYPE_FROMNEAR: Number of columns from the near edge of the
            image (left or top).  First column/row is 0.
         */
 } Location;
@@ -79,6 +80,73 @@ struct CmdlineInfo {
 
 
 static void
+parseLegacyLocationArgs(const char **        const argv,
+                        struct CmdlineInfo * const cmdlineP) {
+
+    int leftArg, topArg, widthArg, heightArg;
+
+    {
+        const char * error;
+        pm_string_to_int(argv[1], &leftArg,   &error);
+        if (error)
+            pm_error("Invalid number for left column argument.  %s", error);
+    }
+    {
+        const char * error;
+        pm_string_to_int(argv[2], &topArg,    &error);
+        if (error)
+            pm_error("Invalid number for top row argument.  %s",     error);
+    }
+    {
+        const char * error;
+        pm_string_to_int(argv[3], &widthArg,  &error);
+        if (error)
+            pm_error("Invalid number for width argument.  %s",       error);
+    }
+    {
+        const char * error;
+        pm_string_to_int(argv[4], &heightArg, &error);
+        if (error)
+            pm_error("Invalid number for height argument.  %s",      error);
+    }
+
+    if (leftArg < 0) {
+        cmdlineP->leftLoc.locType = LOCTYPE_FROMFAR;
+        cmdlineP->leftLoc.n       = -leftArg;
+    } else {
+        cmdlineP->leftLoc.locType = LOCTYPE_FROMNEAR;
+        cmdlineP->leftLoc.n       = leftArg;
+    }
+    if (topArg < 0) {
+        cmdlineP->topLoc.locType = LOCTYPE_FROMFAR;
+        cmdlineP->topLoc.n       = -topArg;
+    } else {
+        cmdlineP->topLoc.locType = LOCTYPE_FROMNEAR;
+        cmdlineP->topLoc.n       = topArg;
+    }
+    if (widthArg > 0) {
+        cmdlineP->width = widthArg;
+        cmdlineP->widthSpec = 1;
+        cmdlineP->rghtLoc.locType = LOCTYPE_NONE;
+    } else {
+        cmdlineP->widthSpec = 0;
+        cmdlineP->rghtLoc.locType = LOCTYPE_FROMFAR;
+        cmdlineP->rghtLoc.n = -(widthArg - 1);
+    }
+    if (heightArg > 0) {
+        cmdlineP->height = heightArg;
+        cmdlineP->heightSpec = 1;
+        cmdlineP->botLoc.locType = LOCTYPE_NONE;
+    } else {
+        cmdlineP->heightSpec = 0;
+        cmdlineP->botLoc.locType = LOCTYPE_FROMFAR;
+        cmdlineP->botLoc.n = -(heightArg - 1);
+    }
+}
+
+
+
+static void
 parseCommandLine(int argc, const char ** const argv,
                  struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
@@ -156,51 +224,9 @@ parseCommandLine(int argc, const char ** const argv,
         break;
     }
 
-    if (haveLegacyLocationArgs) {
-        int leftArg, topArg, widthArg, heightArg;
-
-        if (sscanf(argv[1], "%d", &leftArg) != 1)
-            pm_error("Invalid number for left column argument");
-        if (sscanf(argv[2], "%d", &topArg) != 1)
-            pm_error("Invalid number for right column argument");
-        if (sscanf(argv[3], "%d", &widthArg) != 1)
-            pm_error("Invalid number for width argument");
-        if (sscanf(argv[4], "%d", &heightArg) != 1)
-            pm_error("Invalid number for height argument");
-
-        if (leftArg < 0) {
-            cmdlineP->leftLoc.locType = LOCTYPE_FROMFAR;
-            cmdlineP->leftLoc.n       = -leftArg;
-        } else {
-            cmdlineP->leftLoc.locType = LOCTYPE_FROMNEAR;
-            cmdlineP->leftLoc.n       = leftArg;
-        }
-        if (topArg < 0) {
-            cmdlineP->topLoc.locType = LOCTYPE_FROMFAR;
-            cmdlineP->topLoc.n       = -topArg;
-        } else {
-            cmdlineP->topLoc.locType = LOCTYPE_FROMNEAR;
-            cmdlineP->topLoc.n       = topArg;
-        }
-        if (widthArg > 0) {
-            cmdlineP->width = widthArg;
-            cmdlineP->widthSpec = 1;
-            cmdlineP->rghtLoc.locType = LOCTYPE_NONE;
-        } else {
-            cmdlineP->widthSpec = 0;
-            cmdlineP->rghtLoc.locType = LOCTYPE_FROMFAR;
-            cmdlineP->rghtLoc.n = -(widthArg - 1);
-        }
-        if (heightArg > 0) {
-            cmdlineP->height = heightArg;
-            cmdlineP->heightSpec = 1;
-            cmdlineP->botLoc.locType = LOCTYPE_NONE;
-        } else {
-            cmdlineP->heightSpec = 0;
-            cmdlineP->botLoc.locType = LOCTYPE_FROMFAR;
-            cmdlineP->botLoc.n = -(heightArg - 1);
-        }
-    } else {
+    if (haveLegacyLocationArgs)
+        parseLegacyLocationArgs(argv, cmdlineP);
+    else {
         if (leftSpec && cropleftSpec)
             pm_error("You cannot specify both -left and -cropleft");
         if (leftSpec) {
diff --git a/editor/pamdice.c b/editor/pamdice.c
index b478a25a..58e24e5b 100644
--- a/editor/pamdice.c
+++ b/editor/pamdice.c
@@ -17,34 +17,30 @@
 #include "nstring.h"
 #include "mallocvar.h"
 
-#define MAXFILENAMELEN 80
-    /* Maximum number of characters we accept in filenames */
-
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
     const char * inputFileName;  /* '-' if stdin */
-    const char * outstem; 
-        /* null-terminated string, max MAXFILENAMELEN-10 characters */
+    const char * outstem;
     unsigned int sliceVertically;    /* boolean */
     unsigned int sliceHorizontally;  /* boolean */
     unsigned int width;    /* Meaningless if !sliceVertically */
     unsigned int height;   /* Meaningless if !sliceHorizontally */
-    unsigned int hoverlap; 
+    unsigned int hoverlap;
         /* Meaningless if !sliceVertically.  Guaranteed < width */
-    unsigned int voverlap; 
+    unsigned int voverlap;
         /* Meaningless if !sliceHorizontally.  Guaranteed < height */
     unsigned int verbose;
 };
 
 
 static void
-parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo * const cmdlineP ) {
+parseCommandLine(int argc, const char ** argv,
+                 struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    parse program command line described in Unix standard form by argc
-   and argv.  Return the information in the options as *cmdlineP.  
+   and argv.  Return the information in the options as *cmdlineP.
 
    If command line is internally inconsistent (invalid options, etc.),
    issue error message to stderr and abort program.
@@ -52,18 +48,18 @@ 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;
+    optEntry * option_def;
         /* Instructions to pm_optParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
-    
+
     unsigned int outstemSpec, hoverlapSpec, voverlapSpec;
     unsigned int option_def_index;
 
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENT3 */
-    OPTENT3(0, "width",       OPT_UINT,    &cmdlineP->width,       
+    OPTENT3(0, "width",       OPT_UINT,    &cmdlineP->width,
             &cmdlineP->sliceVertically,       0);
     OPTENT3(0, "height",      OPT_UINT,    &cmdlineP->height,
             &cmdlineP->sliceHorizontally,     0);
@@ -80,7 +76,7 @@ parseCommandLine(int argc, char ** argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdline_p and others. */
 
     if (cmdlineP->sliceVertically) {
@@ -114,9 +110,11 @@ parseCommandLine(int argc, char ** argv,
         cmdlineP->inputFileName = "-";
     else if (argc-1 == 1)
         cmdlineP->inputFileName = argv[1];
-    else 
-        pm_error("Progam takes at most 1 parameter: the file specification.  "
+    else
+        pm_error("Program takes at most 1 parameter: the file specification.  "
                  "You specified %u", argc-1);
+
+    free(option_def);
 }
 
 
@@ -133,7 +131,7 @@ divup(unsigned int const dividend,
 
 
 static void
-computeSliceGeometry(struct cmdlineInfo const cmdline,
+computeSliceGeometry(struct CmdlineInfo const cmdline,
                      struct pam         const inpam,
                      bool               const verbose,
                      unsigned int *     const nHorizSliceP,
@@ -146,20 +144,30 @@ computeSliceGeometry(struct cmdlineInfo const cmdline,
 /*----------------------------------------------------------------------------
    Compute the geometry of the slices, both common slices and possibly
    smaller remainder slices at the top and right.
+
+   We return the following.
+
+   *nHorizSliceP is the number of horizontal slices.  *sliceHeightP is the
+   height of every slice except possibly the bottom one.  *bottomSliceHeightP
+   is the height of the bottom slice.
+
+   *nVertSliceP is the number of vertical slices.  *sliceWidthP is the width
+   of every slice except possibly the rightmost one.  *rightSliceWidthP is the
+   width of the rightmost slice.
 -----------------------------------------------------------------------------*/
     if (cmdline.sliceHorizontally) {
         if (cmdline.height >= inpam.height)
             *nHorizSliceP = 1;
         else
-            *nHorizSliceP = 1 + divup(inpam.height - cmdline.height, 
+            *nHorizSliceP = 1 + divup(inpam.height - cmdline.height,
                                       cmdline.height - cmdline.voverlap);
         *sliceHeightP = cmdline.height;
 
-        *bottomSliceHeightP = 
-            inpam.height - (*nHorizSliceP-1) * (cmdline.height - cmdline.voverlap);
+        *bottomSliceHeightP = inpam.height -
+            (*nHorizSliceP-1) * (cmdline.height - cmdline.voverlap);
     } else {
-        *nHorizSliceP = 1;
-        *sliceHeightP = inpam.height;
+        *nHorizSliceP       = 1;
+        *sliceHeightP       = inpam.height;
         *bottomSliceHeightP = inpam.height;
     }
 
@@ -167,14 +175,14 @@ computeSliceGeometry(struct cmdlineInfo const cmdline,
         if (cmdline.width >= inpam.width)
             *nVertSliceP = 1;
         else
-            *nVertSliceP = 1 + divup(inpam.width - cmdline.width, 
+            *nVertSliceP = 1 + divup(inpam.width - cmdline.width,
                                      cmdline.width - cmdline.hoverlap);
         *sliceWidthP = cmdline.width;
-        *rightSliceWidthP = 
-            inpam.width - (*nVertSliceP-1) * (cmdline.width - cmdline.hoverlap);
+        *rightSliceWidthP = inpam.width -
+            (*nVertSliceP-1) * (cmdline.width - cmdline.hoverlap);
     } else {
-        *nVertSliceP = 1;
-        *sliceWidthP = inpam.width;
+        *nVertSliceP      = 1;
+        *sliceWidthP      = inpam.width;
         *rightSliceWidthP = inpam.width;
     }
 
@@ -185,7 +193,7 @@ computeSliceGeometry(struct cmdlineInfo const cmdline,
                    *nVertSliceP, *nHorizSliceP,
                    *sliceWidthP, *sliceHeightP);
         if (*rightSliceWidthP != *sliceWidthP)
-            pm_message("Right vertical slice is only %u wide", 
+            pm_message("Right vertical slice is only %u wide",
                        *rightSliceWidthP);
         if (*bottomSliceHeightP != *sliceHeightP)
             pm_message("Bottom horizontal slice is only %u high",
@@ -212,7 +220,7 @@ ndigits(unsigned int const arg) {
 
 
 static void
-computeOutputFilenameFormat(int           const format, 
+computeOutputFilenameFormat(int           const format,
                             unsigned int  const nHorizSlice,
                             unsigned int  const nVertSlice,
                             const char ** const filenameFormatP) {
@@ -228,7 +236,7 @@ computeOutputFilenameFormat(int           const format,
         pm_error("INTERNAL ERROR: impossible value for libnetpbm image "
                  "fomat code: %d", format);
     }
-    
+
     pm_asprintf(filenameFormatP, "%%s_%%0%uu_%%0%uu.%s",
                 ndigits(nHorizSlice), ndigits(nVertSlice), filenameSuffix);
 
@@ -239,16 +247,16 @@ computeOutputFilenameFormat(int           const format,
 
 
 static void
-openOutStreams(struct pam   const inpam, 
-               struct pam         outpam[],
-               unsigned int const horizSlice, 
+openOutStreams(struct pam   const inpam,
+               struct pam * const outpam,
+               unsigned int const horizSlice,
                unsigned int const nHorizSlice,
                unsigned int const nVertSlice,
-               unsigned int const sliceHeight, 
+               unsigned int const sliceHeight,
                unsigned int const sliceWidth,
                unsigned int const rightSliceWidth,
                unsigned int const hOverlap,
-               char         const outstem[]) {
+               const char * const outstem) {
 /*----------------------------------------------------------------------------
    Open the output files for a single horizontal slice (there's one file
    for each vertical slice) and write the Netpbm headers to them.  Also
@@ -270,34 +278,37 @@ openOutStreams(struct pam   const inpam,
         else {
             outpam[vertSlice] = inpam;
             outpam[vertSlice].file = pm_openw(filename);
-            
-            outpam[vertSlice].width = 
+
+            outpam[vertSlice].width =
                 vertSlice < nVertSlice-1 ? sliceWidth : rightSliceWidth;
-            
+
             outpam[vertSlice].height = sliceHeight;
-            
+
             pnm_writepaminit(&outpam[vertSlice]);
 
             pm_strfree(filename);
         }
-    }        
+    }
     pm_strfree(filenameFormat);
 }
 
 
 
 static void
-closeOutFiles(struct pam pam[], unsigned int const nVertSlice) {
+closeOutFiles(struct pam * const pam,
+              unsigned int const nVertSlice) {
 
     unsigned int vertSlice;
-    
+
     for (vertSlice = 0; vertSlice < nVertSlice; ++vertSlice)
         pm_close(pam[vertSlice].file);
 }
 
+
+
 static void
-sliceRow(tuple              inputRow[], 
-         struct pam         outpam[], 
+sliceRow(tuple *      const inputRow,
+         struct pam * const outpam,
          unsigned int const nVertSlice,
          unsigned int const hOverlap) {
 /*----------------------------------------------------------------------------
@@ -308,14 +319,15 @@ sliceRow(tuple              inputRow[],
    'hOverlap', which is meaningful only when nVertSlice is greater than 1,
    is the amount by which slices overlap each other.
 -----------------------------------------------------------------------------*/
-    tuple * outputRow;
-    unsigned int vertSlice;
     unsigned int const sliceWidth = outpam[0].width;
-    unsigned int const stride = 
+    unsigned int const stride =
         nVertSlice > 1 ? sliceWidth - hOverlap : sliceWidth;
 
-    for (vertSlice = 0, outputRow = inputRow; 
-         vertSlice < nVertSlice; 
+    tuple *      outputRow;
+    unsigned int vertSlice;
+
+    for (vertSlice = 0, outputRow = inputRow;
+         vertSlice < nVertSlice;
          outputRow += stride, ++vertSlice) {
         pnm_writepamrow(&outpam[vertSlice], outputRow);
     }
@@ -333,15 +345,15 @@ sliceRow(tuple              inputRow[],
 struct inputWindow {
     unsigned int windowSize;
     unsigned int firstRowInWindow;
-    struct pam pam;
-    tuple ** rows;
+    struct pam   pam;
+    tuple **     rows;
 };
 
 static void
 initInput(struct inputWindow * const inputWindowP,
           struct pam *         const pamP,
           unsigned int         const windowSize) {
-    
+
     struct pam allocPam;  /* Just for allocating the window array */
     unsigned int i;
 
@@ -350,7 +362,7 @@ initInput(struct inputWindow * const inputWindowP,
 
     allocPam = *pamP;
     allocPam.height = windowSize;
-    
+
     inputWindowP->rows = pnm_allocpamarray(&allocPam);
 
     inputWindowP->firstRowInWindow = 0;
@@ -371,6 +383,8 @@ termInputWindow(struct inputWindow * const inputWindowP) {
     pnm_freepamarray(inputWindowP->rows, &freePam);
 }
 
+
+
 static tuple *
 getInputRow(struct inputWindow * const inputWindowP,
             unsigned int         const row) {
@@ -393,7 +407,7 @@ getInputRow(struct inputWindow * const inputWindowP,
         /* Read in the new last row in the window */
         inputWindowP->rows[i] = oldRow0;  /* Reuse the memory */
         pnm_readpamrow(&inputWindowP->pam, inputWindowP->rows[i]);
-    }        
+    }
 
     return inputWindowP->rows[row - inputWindowP->firstRowInWindow];
 }
@@ -420,10 +434,10 @@ allocOutpam(unsigned int  const nVertSlice,
 
 
 int
-main(int argc, char ** argv) {
+main(int argc, const char ** argv) {
 
-    struct cmdlineInfo cmdline;
-    FILE    *ifP;
+    struct CmdlineInfo cmdline;
+    FILE    * ifP;
     struct pam inpam;
     unsigned int horizSlice;
         /* Number of the current horizontal slice.  Slices are numbered
@@ -433,7 +447,7 @@ main(int argc, char ** argv) {
         /* Width in pam columns of each vertical slice, except
            the rightmost slice, which may be narrower.  If we aren't slicing
            vertically, that means one slice, i.e. the slice width
-           is the image width.  
+           is the image width.
         */
     unsigned int rightSliceWidth;
         /* Width in pam columns of the rightmost vertical slice. */
@@ -441,23 +455,23 @@ main(int argc, char ** argv) {
         /* Height in pam rows of each horizontal slice, except
            the bottom slice, which may be shorter.  If we aren't slicing
            horizontally, that means one slice, i.e. the slice height
-           is the image height.  
+           is the image height.
         */
     unsigned int bottomSliceHeight;
         /* Height in pam rows of the bottom horizontal slice. */
     unsigned int nHorizSlice;
     unsigned int nVertSlice;
     struct inputWindow inputWindow;
-    
+
     struct pam * outpam;
-        /* malloc'ed.  outpam[x] is the pam structure that controls
+        /* malloc'ed array.  outpam[x] is the pam structure that controls
            the current horizontal slice of vertical slice x.
         */
 
-    pnm_init(&argc, argv);
-    
+    pm_proginit(&argc, argv);
+
     parseCommandLine(argc, argv, &cmdline);
-        
+
     ifP = pm_openr(cmdline.inputFileName);
 
     pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
@@ -467,28 +481,29 @@ main(int argc, char ** argv) {
                          &nVertSlice, &sliceWidth, &rightSliceWidth);
 
     allocOutpam(nVertSlice, &outpam);
-    
-    initInput(&inputWindow, &inpam, 
+
+    initInput(&inputWindow, &inpam,
               nHorizSlice > 1 ? cmdline.voverlap + 1 : 1);
 
     for (horizSlice = 0; horizSlice < nHorizSlice; ++horizSlice) {
-        unsigned int const thisSliceFirstRow = 
+        unsigned int const thisSliceFirstRow =
             horizSlice > 0 ? horizSlice * (sliceHeight - cmdline.voverlap) : 0;
             /* Note that 'cmdline.voverlap' is not defined when there is only
                one horizontal slice
             */
-        unsigned int const thisSliceHeight = 
+        unsigned int const thisSliceHeight =
             horizSlice < nHorizSlice-1 ? sliceHeight : bottomSliceHeight;
 
         unsigned int row;
 
-        openOutStreams(inpam, outpam, horizSlice, nHorizSlice, nVertSlice, 
+        openOutStreams(inpam, outpam, horizSlice, nHorizSlice, nVertSlice,
                        thisSliceHeight, sliceWidth, rightSliceWidth,
                        cmdline.hoverlap, cmdline.outstem);
 
         for (row = 0; row < thisSliceHeight; ++row) {
             tuple * const inputRow =
                 getInputRow(&inputWindow, thisSliceFirstRow + row);
+
             sliceRow(inputRow, outpam, nVertSlice, cmdline.hoverlap);
         }
         closeOutFiles(outpam, nVertSlice);
@@ -502,3 +517,6 @@ main(int argc, char ** argv) {
 
     return 0;
 }
+
+
+
diff --git a/editor/pamditherbw.c b/editor/pamditherbw.c
index 4b192e6e..694b2c21 100644
--- a/editor/pamditherbw.c
+++ b/editor/pamditherbw.c
@@ -14,12 +14,14 @@
 #include <string.h>
 
 #include "pm_c_util.h"
-#include "pam.h"
-#include "dithers.h"
+#include "rand.h"
 #include "mallocvar.h"
 #include "shhopt.h"
+#include "pam.h"
+#include "dithers.h"
 #include "pm_gamma.h"
 
+
 enum halftone {QT_FS,
                QT_ATKINSON,
                QT_THRESH,
@@ -42,7 +44,7 @@ struct cmdlineInfo {
     enum halftone halftone;
     unsigned int  clumpSize;
         /* Defined only for halftone == QT_HILBERT */
-    unsigned int  clusterRadius;  
+    unsigned int  clusterRadius;
         /* Defined only for halftone == QT_CLUSTER */
     float         threshval;
     unsigned int  randomseed;
@@ -85,9 +87,9 @@ parseCommandLine(int argc, char ** argv,
     OPTENT3(0, "c4",        OPT_FLAG,  NULL, &cluster4Opt,  0);
     OPTENT3(0, "cluster8",  OPT_FLAG,  NULL, &cluster8Opt,  0);
     OPTENT3(0, "c8",        OPT_FLAG,  NULL, &cluster8Opt,  0);
-    OPTENT3(0, "value",     OPT_FLOAT, &cmdlineP->threshval, 
+    OPTENT3(0, "value",     OPT_FLOAT, &cmdlineP->threshval,
             &valueSpec, 0);
-    OPTENT3(0, "clump",     OPT_UINT,  &cmdlineP->clumpSize, 
+    OPTENT3(0, "clump",     OPT_UINT,  &cmdlineP->clumpSize,
             &clumpSpec, 0);
     OPTENT3(0,   "randomseed",   OPT_UINT,    &cmdlineP->randomseed,
             &cmdlineP->randomseedSpec,      0);
@@ -101,10 +103,10 @@ parseCommandLine(int argc, char ** argv,
 
     free(option_def);
 
-    if (floydOpt + atkinsonOpt + thresholdOpt + hilbertOpt + dither8Opt + 
+    if (floydOpt + atkinsonOpt + thresholdOpt + hilbertOpt + dither8Opt +
         cluster3Opt + cluster4Opt + cluster8Opt == 0)
         cmdlineP->halftone = QT_FS;
-    else if (floydOpt + atkinsonOpt + thresholdOpt + dither8Opt + 
+    else if (floydOpt + atkinsonOpt + thresholdOpt + hilbertOpt + dither8Opt +
         cluster3Opt + cluster4Opt + cluster8Opt > 1)
         pm_error("Cannot specify more than one halftoning type");
     else {
@@ -135,7 +137,7 @@ parseCommandLine(int argc, char ** argv,
         } else if (cluster8Opt) {
             cmdlineP->halftone = QT_CLUSTER;
             cmdlineP->clusterRadius = 8;
-        } else 
+        } else
             pm_error("INTERNAL ERROR.  No halftone option");
     }
 
@@ -190,152 +192,211 @@ makeOutputPam(unsigned int const width,
 
 /* Hilbert curve tracer */
 
-#define MAXORD 18
+typedef struct {
+    unsigned int x;
+    unsigned int y;
+} Point;
+
+
 
-struct Hil {
-    int order;
-    int ord;
+typedef struct {
+    bool firstPointDone;
+    unsigned int order;
+    unsigned int ord;
+        /* Meaningful only when 'firstPointDone' is true */
     int turn;
     int dx;
     int dy;
     int x;
     int y;
-    int stage[MAXORD];
-    int width;
-    int height;
-};
+    int stage[sizeof(unsigned int)*8];
+        /* One entry for every bit in the height or width, each of which
+           is an unsigned int
+        */
+    unsigned int width;
+    unsigned int height;
+} Hilbert;
 
-static void 
-initHilbert(int          const w, 
-            int          const h,
-            struct Hil * const hilP) {
+static void
+hilbert_init(Hilbert *    const hilP,
+             unsigned int const width,
+             unsigned int const height) {
 /*----------------------------------------------------------------------------
-  Initialize the Hilbert curve tracer 
+  Initialize the Hilbert curve tracer
 -----------------------------------------------------------------------------*/
-    int big, ber;
-    hilP->width = w;
-    hilP->height = h;
-    big = w > h ? w : h;
-    for (ber = 2, hilP->order = 1; ber < big; ber <<= 1, hilP->order++);
-    if (hilP->order > MAXORD)
-        pm_error("Sorry, hilbert order is too large");
-    hilP->ord = hilP->order;
-    hilP->order--;
+    unsigned int const maxDim = MAX(width, height);
+
+    unsigned int order;
+
+    hilP->width  = width;
+    hilP->height = height;
+    {
+        unsigned int ber;
+        for (ber = 2, order = 0; ber < maxDim; ber <<= 1, ++order);
+    }
+    assert(order + 1 <= ARRAY_SIZE(hilP->stage));
+    hilP->order = order;
+    hilP->firstPointDone = false;
 }
 
 
 
-static bool
-hilbert(int *        const px,
-        int *        const py,
-        struct Hil * const hilP) {
-/*----------------------------------------------------------------------------
-  Return non-zero if got another point
------------------------------------------------------------------------------*/
-    int temp;
-    if (hilP->ord > hilP->order) {
-        /* have to do first point */
-
-        hilP->ord--;
-        hilP->stage[hilP->ord] = 0;
-        hilP->turn = -1;
-        hilP->dy = 1;
-        hilP->dx = hilP->x = hilP->y = 0;
-        *px = *py = 0;
-        return true;
-    }
+static void
+hilbert_doFirstPoint(Hilbert * const hilbertP,
+                     bool *    const gotPointP,
+                     Point *   const pointP) {
+
+    hilbertP->ord = hilbertP->order;
+    hilbertP->stage[hilbertP->ord] = 0;
+    hilbertP->turn = -1;
+    hilbertP->dy = 1;
+    hilbertP->dx = hilbertP->x = hilbertP->y = 0;
+    hilbertP->firstPointDone = true;
+
+    pointP->x = 0; pointP->y = 0;
+    *gotPointP = true;
+}
+
+
+
+static void
+hilbert_advanceStateMachine(Hilbert * const hilbertP,
+                            bool *    const gotPointP,
+                            Point *   const pointP) {
 
-    /* Operate the state machine */
     for(;;)  {
-        switch (hilP->stage[hilP->ord]) {
-        case 0:
-            hilP->turn = -hilP->turn;
-            temp = hilP->dy;
-            hilP->dy = -hilP->turn * hilP->dx;
-            hilP->dx = hilP->turn * temp;
-            if (hilP->ord > 0) {
-                hilP->stage[hilP->ord] = 1;
-                hilP->ord--;
-                hilP->stage[hilP->ord]=0;
+        switch (hilbertP->stage[hilbertP->ord]) {
+        case 0: {
+            int const origDy = hilbertP->dy;
+
+            hilbertP->turn = -hilbertP->turn;
+            hilbertP->dy = -hilbertP->turn * hilbertP->dx;
+            hilbertP->dx = hilbertP->turn * origDy;
+            if (hilbertP->ord > 0) {
+                hilbertP->stage[hilbertP->ord] = 1;
+                --hilbertP->ord;
+                hilbertP->stage[hilbertP->ord]=0;
                 continue;
             }
-        case 1:
-            hilP->x += hilP->dx;
-            hilP->y += hilP->dy;
-            if (hilP->x < hilP->width && hilP->y < hilP->height) {
-                hilP->stage[hilP->ord] = 2;
-                *px = hilP->x;
-                *py = hilP->y;
-                return true;
+        }
+        case 1: {
+            hilbertP->x += hilbertP->dx;
+            hilbertP->y += hilbertP->dy;
+            if (hilbertP->x < hilbertP->width &&
+                hilbertP->y < hilbertP->height) {
+
+                hilbertP->stage[hilbertP->ord] = 2;
+
+                pointP->x = hilbertP->x;
+                pointP->y = hilbertP->y;
+                *gotPointP = true;
+                return;
             }
-        case 2:
-            hilP->turn = -hilP->turn;
-            temp = hilP->dy;
-            hilP->dy = -hilP->turn * hilP->dx;
-            hilP->dx = hilP->turn * temp;
-            if (hilP->ord > 0) { 
+        }
+        case 2: {
+            int const origDy = hilbertP->dy;
+
+            hilbertP->turn = -hilbertP->turn;
+            hilbertP->dy = -hilbertP->turn * hilbertP->dx;
+            hilbertP->dx = hilbertP->turn * origDy;
+            if (hilbertP->ord > 0) {
                 /* recurse */
 
-                hilP->stage[hilP->ord] = 3;
-                hilP->ord--;
-                hilP->stage[hilP->ord]=0;
+                hilbertP->stage[hilbertP->ord] = 3;
+                --hilbertP->ord;
+                hilbertP->stage[hilbertP->ord]=0;
                 continue;
             }
-        case 3:
-            hilP->x += hilP->dx;
-            hilP->y += hilP->dy;
-            if (hilP->x < hilP->width && hilP->y < hilP->height) {
-                hilP->stage[hilP->ord] = 4;
-                *px = hilP->x;
-                *py = hilP->y;
-                return true;
+        }
+        case 3: {
+            hilbertP->x += hilbertP->dx;
+            hilbertP->y += hilbertP->dy;
+            if (hilbertP->x < hilbertP->width &&
+                hilbertP->y < hilbertP->height) {
+
+                hilbertP->stage[hilbertP->ord] = 4;
+
+                pointP->x = hilbertP->x;
+                pointP->y = hilbertP->y;
+                *gotPointP = true;
+                return;
             }
-        case 4:
-            if (hilP->ord > 0) {
+        }
+        case 4: {
+            if (hilbertP->ord > 0) {
                 /* recurse */
-                hilP->stage[hilP->ord] = 5;
-                hilP->ord--;
-                hilP->stage[hilP->ord]=0;
+                hilbertP->stage[hilbertP->ord] = 5;
+                --hilbertP->ord;
+                hilbertP->stage[hilbertP->ord]=0;
                 continue;
             }
-        case 5:
-            temp = hilP->dy;
-            hilP->dy = -hilP->turn * hilP->dx;
-            hilP->dx = hilP->turn * temp;
-            hilP->turn = -hilP->turn;
-            hilP->x += hilP->dx;
-            hilP->y += hilP->dy;
-            if (hilP->x < hilP->width && hilP->y < hilP->height) {
-                hilP->stage[hilP->ord] = 6;
-                *px = hilP->x;
-                *py = hilP->y;
-                return true;
+        }
+        case 5: {
+            int const origDy = hilbertP->dy;
+
+            hilbertP->dy = -hilbertP->turn * hilbertP->dx;
+            hilbertP->dx = hilbertP->turn * origDy;
+            hilbertP->turn = -hilbertP->turn;
+            hilbertP->x += hilbertP->dx;
+            hilbertP->y += hilbertP->dy;
+            if (hilbertP->x < hilbertP->width &&
+                hilbertP->y < hilbertP->height) {
+
+                hilbertP->stage[hilbertP->ord] = 6;
+
+                pointP->x = hilbertP->x;
+                pointP->y = hilbertP->y;
+                *gotPointP = true;
+                return;
             }
-        case 6:
-            if (hilP->ord > 0) {
+        }
+        case 6: {
+            if (hilbertP->ord > 0) {
                 /* recurse */
-                hilP->stage[hilP->ord] = 7;
-                hilP->ord--;
-                hilP->stage[hilP->ord]=0;
+                hilbertP->stage[hilbertP->ord] = 7;
+                --hilbertP->ord;
+                hilbertP->stage[hilbertP->ord]=0;
                 continue;
             }
-        case 7:
-            temp = hilP->dy;
-            hilP->dy = -hilP->turn * hilP->dx;
-            hilP->dx = hilP->turn * temp;
-            hilP->turn = -hilP->turn;
+        }
+        case 7: {
+            int const origDy = hilbertP->dy;
+
+            hilbertP->dy = -hilbertP->turn * hilbertP->dx;
+            hilbertP->dx = hilbertP->turn * origDy;
+            hilbertP->turn = -hilbertP->turn;
             /* Return from a recursion */
-            if (hilP->ord < hilP->order)
-                hilP->ord++;
-            else
-                return false;
+            if (hilbertP->ord < hilbertP->order)
+                ++hilbertP->ord;
+            else {
+                *gotPointP = false;
+                return;
+            }
         }
+        }
+    }
+}
+
+
+
+static void
+hilbert_trace(Hilbert * const hilbertP,
+              bool *    const gotPointP,
+              Point *   const pointP) {
+/*----------------------------------------------------------------------------
+  ...
+  Return *gotPointP true iff we got another point
+-----------------------------------------------------------------------------*/
+    if (!hilbertP->firstPointDone) {
+        hilbert_doFirstPoint(hilbertP, gotPointP, pointP);
+    } else {
+        hilbert_advanceStateMachine(hilbertP, gotPointP, pointP);
     }
 }
 
 
 
-static void 
+static void
 doHilbert(FILE *       const ifP,
           unsigned int const clumpSize) {
 /*----------------------------------------------------------------------------
@@ -356,10 +417,10 @@ doHilbert(FILE *       const ifP,
     tuple ** grays;
     tuple ** bits;
 
-    struct Hil hil;
+    Hilbert hilbert;
 
     int end;
-    int *x,*y;
+    Point * point;
     int sum;
 
     grays = pnm_readpam(ifP, &graypam, PAM_STRUCT_SIZE(tuple_type));
@@ -368,11 +429,11 @@ doHilbert(FILE *       const ifP,
 
     bits = pnm_allocpamarray(&bitpam);
 
-    MALLOCARRAY(x, clumpSize);
-    MALLOCARRAY(y, clumpSize);
-    if (x == NULL  || y == NULL)
-        pm_error("out of memory");
-    initHilbert(graypam.width, graypam.height, &hil);
+    MALLOCARRAY(point, clumpSize);
+    if (!point)
+        pm_error("Unable to get memory for clump of %u points", clumpSize);
+
+    hilbert_init(&hilbert, graypam.width, graypam.height);
 
     sum = 0;
     end = clumpSize;
@@ -380,19 +441,20 @@ doHilbert(FILE *       const ifP,
     while (end == clumpSize) {
         unsigned int i;
         /* compute the next cluster co-ordinates along hilbert path */
-        for (i = 0; i < end; i++) {
+        for (i = 0; i < end; ++i) {
             bool gotPoint;
-            gotPoint = hilbert(&x[i], &y[i], &hil);
+            hilbert_trace(&hilbert, &gotPoint, &point[i]);
             if (!gotPoint)
                 end = i;    /* we reached the end */
         }
         /* sum levels */
-        for (i = 0; i < end; i++)
-            sum += grays[y[i]][x[i]][0];
+        for (i = 0; i < end; ++i)
+            sum += grays[point[i].y][point[i].x][0];
         /* dither half and half along path */
-        for (i = 0; i < end; i++) {
-            unsigned int const row = y[i];
-            unsigned int const col = x[i];
+        for (i = 0; i < end; ++i) {
+            unsigned int const row = point[i].y;
+            unsigned int const col = point[i].x;
+
             if (sum >= graypam.maxval) {
                 bits[row][col][0] = 1;
                 sum -= graypam.maxval;
@@ -400,7 +462,7 @@ doHilbert(FILE *       const ifP,
                 bits[row][col][0] = 0;
         }
     }
-    free(x);    free(y); 
+    free(point);
     pnm_writepam(&bitpam, bits);
 
     pnm_freepamarray(bits, &bitpam);
@@ -412,7 +474,7 @@ doHilbert(FILE *       const ifP,
 struct converter {
     void (*convertRow)(struct converter * const converterP,
                        unsigned int       const row,
-                       tuplen                   grayrow[], 
+                       tuplen                   grayrow[],
                        tuple                    bitrow[]);
     void (*destroy)(struct converter * const converterP);
     unsigned int cols;
@@ -423,11 +485,11 @@ struct converter {
 
 struct fsState {
     float * thiserr;
-        /* thiserr[N] is the power from previous pixels to include in 
+        /* thiserr[N] is the power from previous pixels to include in
            future column N of the current row.
         */
     float * nexterr;
-        /* nexterr[N] is the power from previous pixels to include in 
+        /* nexterr[N] is the power from previous pixels to include in
            future column N of the next row.
         */
     bool fs_forward;
@@ -455,7 +517,7 @@ fsConvertRow(struct converter * const converterP,
 
     unsigned int limitcol;
     unsigned int col;
-    
+
     for (col = 0; col < converterP->cols + 2; ++col)
         nexterr[col] = 0.0;
 
@@ -494,18 +556,18 @@ fsConvertRow(struct converter * const converterP,
             nexterr[col    ] += (accum * 3) / 16;
             nexterr[col + 1] += (accum * 5) / 16;
             nexterr[col + 2] += (accum * 1) / 16;
-            
+
             ++col;
         } else {
             thiserr[col    ] += (accum * 7) / 16;
             nexterr[col + 2] += (accum * 3) / 16;
             nexterr[col + 1] += (accum * 5) / 16;
             nexterr[col    ] += (accum * 1) / 16;
-            
+
             --col;
         }
     } while (col != limitcol);
-    
+
     stateP->thiserr = nexterr;
     stateP->nexterr = thiserr;
     stateP->fs_forward = ! stateP->fs_forward;
@@ -528,7 +590,9 @@ fsDestroy(struct converter * const converterP) {
 
 static struct converter
 createFsConverter(struct pam * const graypamP,
-                  float        const threshFraction) {
+                  float        const threshFraction,
+                  bool         const randomseedSpec,
+                  unsigned int const randomseed) {
 
     struct fsState * stateP;
     struct converter converter;
@@ -545,9 +609,17 @@ createFsConverter(struct pam * const graypamP,
 
     {
         /* (random errors in [-1/8 .. 1/8]) */
+
         unsigned int col;
+        struct pm_randSt randSt;
+
+        pm_randinit(&randSt);
+        pm_srand2(&randSt, randomseedSpec, randomseed);
+
         for (col = 0; col < graypamP->width + 2; ++col)
-            stateP->thiserr[col] = ((float)rand()/RAND_MAX - 0.5) / 4;
+            stateP->thiserr[col] = (pm_drand(&randSt) - 0.5) / 4;
+
+        pm_randterm(&randSt);
     }
 
     stateP->halfWhite = threshFraction;
@@ -584,7 +656,7 @@ struct atkinsonState {
 
 static void
 moveAtkinsonErrorWindowDown(struct converter * const converterP) {
-                            
+
     struct atkinsonState * const stateP = converterP->stateP;
 
     float * const oldError0 = stateP->error[0];
@@ -628,7 +700,7 @@ atkinsonConvertRow(struct converter * const converterP,
             accum -= stateP->white;
         } else
             bitrow[col] = blackTuple;
-        
+
         /* Forward to future output pixels 3/4 of the power from current
            input pixel and the power forwarded from previous input
            pixels to the current pixel, less any power we put into the
@@ -642,7 +714,7 @@ atkinsonConvertRow(struct converter * const converterP,
         error[1][col+1] += accum/8;
         error[2][col  ] += accum/8;
     }
-    
+
     moveAtkinsonErrorWindowDown(converterP);
 }
 
@@ -665,12 +737,14 @@ atkinsonDestroy(struct converter * const converterP) {
 
 static struct converter
 createAtkinsonConverter(struct pam * const graypamP,
-                        float        const threshFraction) {
+                        float        const threshFraction,
+                        bool         const randomseedSpec,
+                        unsigned int const randomseed) {
 
     struct atkinsonState * stateP;
     struct converter converter;
     unsigned int relRow;
-    
+
     converter.cols       = graypamP->width;
     converter.convertRow = &atkinsonConvertRow;
     converter.destroy    = &atkinsonDestroy;
@@ -683,11 +757,18 @@ createAtkinsonConverter(struct pam * const graypamP,
     {
         /* (random errors in [-1/8 .. 1/8]) */
         unsigned int col;
+        struct pm_randSt randSt;
+
+        pm_randinit(&randSt);
+        pm_srand2(&randSt, randomseedSpec, randomseed);
+
         for (col = 0; col < graypamP->width + 2; ++col) {
-            stateP->error[0][col] = ((float)rand()/RAND_MAX - 0.5) / 4;
+            stateP->error[0][col] = (pm_drand(&randSt) - 0.5) / 4;
             stateP->error[1][col] = 0.0;
             stateP->error[2][col] = 0.0;
         }
+
+        pm_randterm(&randSt);
     }
 
     stateP->halfWhite = threshFraction;
@@ -710,7 +791,7 @@ threshConvertRow(struct converter * const converterP,
                  unsigned int       const row,
                  tuplen                   grayrow[],
                  tuple                    bitrow[]) {
-    
+
     struct threshState * const stateP = converterP->stateP;
 
     unsigned int col;
@@ -740,7 +821,7 @@ createThreshConverter(struct pam * const graypamP,
     converter.cols       = graypamP->width;
     converter.convertRow = &threshConvertRow;
     converter.destroy    = &threshDestroy;
-    
+
     stateP->threshval    = threshFraction;
     converter.stateP     = stateP;
 
@@ -768,7 +849,7 @@ clusterConvertRow(struct converter * const converterP,
     unsigned int col;
 
     for (col = 0; col < converterP->cols; ++col) {
-        float const threshold = 
+        float const threshold =
             stateP->clusterMatrix[row % diameter][col % diameter];
         bitrow[col] =
             grayrow[col][0] > threshold ? whiteTuple : blackTuple;
@@ -789,7 +870,7 @@ clusterDestroy(struct converter * const converterP) {
         free(stateP->clusterMatrix[row]);
 
     free(stateP->clusterMatrix);
-    
+
     free(stateP);
 }
 
@@ -799,14 +880,14 @@ static struct converter
 createClusterConverter(struct pam *    const graypamP,
                        enum ditherType const ditherType,
                        unsigned int    const radius) {
-    
+
     /* TODO: We create a floating point normalized, gamma-adjusted
-       dither matrix from the old integer dither matrices that were 
+       dither matrix from the old integer dither matrices that were
        developed for use with integer arithmetic.  We really should
        just change the literal values in dither.h instead of computing
        the matrix from the integer literal values here.
     */
-    
+
     int const clusterNormalizer = radius * radius * 2;
     unsigned int const diameter = 2 * radius;
 
@@ -827,16 +908,16 @@ createClusterConverter(struct pam *    const graypamP,
         unsigned int col;
 
         MALLOCARRAY_NOFAIL(stateP->clusterMatrix[row], diameter);
-        
+
         for (col = 0; col < diameter; ++col) {
             switch (ditherType) {
-            case DT_REGULAR: 
+            case DT_REGULAR:
                 switch (radius) {
-                case 8: 
-                    stateP->clusterMatrix[row][col] = 
+                case 8:
+                    stateP->clusterMatrix[row][col] =
                         pm_gamma709((float)dither8[row][col] / 256);
                     break;
-                default: 
+                default:
                     pm_error("INTERNAL ERROR: invalid radius");
                 }
                 break;
@@ -849,13 +930,13 @@ createClusterConverter(struct pam *    const graypamP,
                 default:
                     pm_error("INTERNAL ERROR: invalid radius");
                 }
-                stateP->clusterMatrix[row][col] = 
+                stateP->clusterMatrix[row][col] =
                     pm_gamma709((float)val / clusterNormalizer);
             }
             break;
             }
         }
-    }            
+    }
 
     converter.stateP = stateP;
 
@@ -874,8 +955,6 @@ main(int argc, char *argv[]) {
 
     parseCommandLine(argc, argv, &cmdline);
 
-    srand(cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed());
-
     ifP = pm_openr(cmdline.inputFilespec);
 
     if (cmdline.halftone == QT_HILBERT)
@@ -891,28 +970,32 @@ main(int argc, char *argv[]) {
         pnm_readpaminit(ifP, &graypam, PAM_STRUCT_SIZE(tuple_type));
 
         bitpam = makeOutputPam(graypam.width, graypam.height);
-        
+
         pnm_writepaminit(&bitpam);
 
         switch (cmdline.halftone) {
         case QT_FS:
-            converter = createFsConverter(&graypam, cmdline.threshval);
+            converter = createFsConverter(&graypam, cmdline.threshval,
+                                          cmdline.randomseedSpec,
+                                          cmdline.randomseed);
             break;
         case QT_ATKINSON:
-            converter = createAtkinsonConverter(&graypam, cmdline.threshval);
+            converter = createAtkinsonConverter(&graypam, cmdline.threshval,
+                                                cmdline.randomseedSpec,
+                                                cmdline.randomseed);
             break;
         case QT_THRESH:
             converter = createThreshConverter(&graypam, cmdline.threshval);
             break;
-        case QT_DITHER8: 
-            converter = createClusterConverter(&graypam, DT_REGULAR, 8); 
+        case QT_DITHER8:
+            converter = createClusterConverter(&graypam, DT_REGULAR, 8);
             break;
-        case QT_CLUSTER: 
-            converter = createClusterConverter(&graypam, 
-                                               DT_CLUSTER, 
+        case QT_CLUSTER:
+            converter = createClusterConverter(&graypam,
+                                               DT_CLUSTER,
                                                cmdline.clusterRadius);
             break;
-        case QT_HILBERT: 
+        case QT_HILBERT:
                 pm_error("INTERNAL ERROR: halftone is QT_HILBERT where it "
                          "shouldn't be.");
                 break;
@@ -925,7 +1008,7 @@ main(int argc, char *argv[]) {
             pnm_readpamrown(&graypam, grayrow);
 
             converter.convertRow(&converter, row, grayrow, bitrow);
-            
+
             pnm_writepamrow(&bitpam, bitrow);
         }
         free(bitrow);
diff --git a/editor/pamenlarge.c b/editor/pamenlarge.c
index 56a8c6f7..eb3b6ba2 100644
--- a/editor/pamenlarge.c
+++ b/editor/pamenlarge.c
@@ -690,6 +690,7 @@ enlargePbm(struct pam * const inpamP,
         unsigned int const rightPadding =
             scaleMethod == METHOD_GENERAL ? 0 : (xScaleFactor - 1) * 8;
 
+        assert (outcols < UINT_MAX - rightPadding);
         outrow = pbm_allocrow_packed(outcols + rightPadding);
 
         if (scaleMethod == METHOD_GENERAL)
diff --git a/editor/pamflip/pamflip.c b/editor/pamflip/pamflip.c
index bc752208..d3aa76df 100644
--- a/editor/pamflip/pamflip.c
+++ b/editor/pamflip/pamflip.c
@@ -1007,7 +1007,7 @@ stitchCellsToOutput(outputMap *  const outputMapP,
                 outCol += outCellPamP->width;
             }
 
-            assert(outCol = outpamP->width);
+            assert(outCol == outpamP->width);
 
             pnm_writepamrow(outpamP, tupleRow);
         }
diff --git a/editor/pamfunc.c b/editor/pamfunc.c
index 454e6d63..b85cfe9b 100644
--- a/editor/pamfunc.c
+++ b/editor/pamfunc.c
@@ -10,7 +10,7 @@
   ENHANCEMENT IDEAS:
 
   1) speed up by doing integer arithmetic instead of floating point for
-  multiply/divide where possible.  Especially when multiplying by an 
+  multiply/divide where possible.  Especially when multiplying by an
   integer.
 
   2) speed up by not transforming the raster in the idempotent cases
@@ -20,6 +20,7 @@
 
 #include "pm_c_util.h"
 #include "mallocvar.h"
+#include "nstring.h"
 #include "shhopt.h"
 #include "pam.h"
 
@@ -78,7 +79,7 @@ parseHex(const char * const hexString) {
     return retval;
 }
 
-         
+
 
 static void
 parseCommandLine(int argc, const char ** const argv,
@@ -103,7 +104,7 @@ parseCommandLine(int argc, const char ** const argv,
     MALLOCARRAY(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENT3 */
-    OPTENT3(0,   "multiplier", OPT_FLOAT,  &cmdlineP->u.multiplier, 
+    OPTENT3(0,   "multiplier", OPT_FLOAT,  &cmdlineP->u.multiplier,
             &multiplierSpec, 0);
     OPTENT3(0,   "divisor",    OPT_FLOAT,  &cmdlineP->u.divisor,
             &divisorSpec,    0);
@@ -150,12 +151,12 @@ parseCommandLine(int argc, const char ** const argv,
     if (multiplierSpec) {
         cmdlineP->function = FN_MULTIPLY;
         if (cmdlineP->u.multiplier < 0)
-            pm_error("Multiplier must be nonnegative.  You specified %f", 
+            pm_error("Multiplier must be nonnegative.  You specified %f",
                      cmdlineP->u.multiplier);
     } else if (divisorSpec) {
         cmdlineP->function = FN_DIVIDE;
         if (cmdlineP->u.divisor < 0)
-            pm_error("Divisor must be nonnegative.  You specified %f", 
+            pm_error("Divisor must be nonnegative.  You specified %f",
                      cmdlineP->u.divisor);
     } else if (adderSpec) {
         cmdlineP->function = FN_ADD;
@@ -180,20 +181,20 @@ parseCommandLine(int argc, const char ** const argv,
         cmdlineP->function = FN_SHIFTLEFT;
     } else if (shiftrightSpec) {
         cmdlineP->function = FN_SHIFTRIGHT;
-    } else 
+    } else
         pm_error("You must specify one of -multiplier, -divisor, "
                  "-adder, -subtractor, -min, -max, "
                  "-and, -or, -xor, -not, -shiftleft, or -shiftright");
-        
+
     if (argc-1 > 1)
         pm_error("Too many arguments (%d).  File spec is the only argument.",
                  argc-1);
 
     if (argc-1 < 1)
         cmdlineP->inputFileName = "-";
-    else 
+    else
         cmdlineP->inputFileName = argv[1];
-    
+
     free(option_def);
 }
 
@@ -336,7 +337,7 @@ applyFunction(struct CmdlineInfo const cmdline,
            1/cmdline.u.divisor instead of divide by cmdline.u.divisor,
            so we compute that here.  Note that if the function isn't
            divide, both cmdline.u.divisor and oneOverDivisor are
-           meaningless.  
+           meaningless.
         */
     unsigned int col;
 
@@ -388,7 +389,7 @@ applyFunction(struct CmdlineInfo const cmdline,
             outputRow[col][plane] = MIN(outpam.maxval, outSample);
         }
     }
-}                
+}
 
 
 
@@ -422,6 +423,9 @@ main(int argc, const char *argv[]) {
     planTransform(cmdline, inpam.maxval, outpam.format,
                   &outpam.maxval, &mustChangeRaster);
 
+    if (outpam.maxval > 1 && strneq(outpam.tuple_type, "BLACKANDWHITE", 13))
+        strcpy(outpam.tuple_type, "");
+
     pnm_writepaminit(&outpam);
 
     outputRow = pnm_allocpamrow(&outpam);
@@ -440,7 +444,7 @@ main(int argc, const char *argv[]) {
     pnm_freepamrow(inputRow);
     pm_close(inpam.file);
     pm_close(outpam.file);
-    
+
     return 0;
 }
 
diff --git a/editor/pamhomography.c b/editor/pamhomography.c
new file mode 100644
index 00000000..02c0fd72
--- /dev/null
+++ b/editor/pamhomography.c
@@ -0,0 +1,799 @@
+/* ----------------------------------------------------------------------
+ *
+ * Map one quadrilateral to another
+ * by Scott Pakin <scott+pbm@pakin.org>
+ *
+ * ----------------------------------------------------------------------
+ *
+ * Copyright (C) 2020 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.
+ *
+ * ----------------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <math.h>
+#include "pm_c_util.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+#include "pam.h"
+
+#define MIN4(A, B, C, D) MIN(MIN(A, B), MIN(C, D))
+#define MAX4(A, B, C, D) MAX(MAX(A, B), MAX(C, D))
+
+typedef struct {
+/*----------------------------------------------------------------------------
+  A point on the image plane.  It may or may not lie within the
+  bounds of the image itself.
+-----------------------------------------------------------------------------*/
+    int x;
+    int y;
+} Point;
+
+
+static Point
+pointXy(int const x,
+        int const y) {
+
+    Point retval;
+
+    retval.x = x;
+    retval.y = y;
+
+    return retval;
+}
+
+
+
+typedef struct {
+/*----------------------------------------------------------------------------
+  A quadrilateral on the image plane.
+-----------------------------------------------------------------------------*/
+    Point ul;
+    Point ur;
+    Point lr;
+    Point ll;
+} Quad;
+
+typedef struct {
+/*----------------------------------------------------------------------------
+  A specification of a quadrilateral on the image plane, either explicitly
+  or just as "the whole image".
+-----------------------------------------------------------------------------*/
+    bool wholeImage;
+    Quad explicit;  /* Meaningful only if 'wholeImage' is false */
+} QuadSpec;
+
+typedef struct {
+/*----------------------------------------------------------------------------
+   Specification of a mapping from one quadrilateral to another
+-----------------------------------------------------------------------------*/
+    QuadSpec from;
+    QuadSpec to;
+} QuadMap;
+
+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 */
+    QuadMap      qmap;
+        /* Source and target quadrilaterals as specified by -to and -from;
+           Note that the file identified by 'mapfile' also supplies such
+           information.
+        */
+    QuadSpec     view;
+        /* Bounding box for the target image */
+    const char * mapfile;        /* Null if not specified */
+    const char * fill;           /* Null if not specified */
+    unsigned int verbose;
+};
+
+
+
+static void
+parseCoords(const char *   const str,
+            int *          const coords,
+            unsigned int * const nP) {
+/*----------------------------------------------------------------------------
+  Parse a list of up to 16 integers.  Return as *nP how may there are.
+-----------------------------------------------------------------------------*/
+    const char * p;
+    char * pnext;
+    unsigned int i;
+
+    for (i = 0, p = str; i < 16; ++i, p = pnext) {
+        long int val;
+
+        /* Skip punctuation, except "+" and "-", and white space. */
+        while (*p != '\0' && *p != '+' && *p != '-' &&
+               (isspace(*p) || ispunct(*p)))
+            ++p;
+
+        /* Parse the next integer. */
+        errno = 0;  /* strtol() sets errno on error. */
+        val = strtol(p, &pnext, 10);
+        if (errno == ERANGE)
+            break;  /* Integer lies out of long int range */
+        if (errno != 0 || pnext == p)
+            break;  /* Too few integers */
+        coords[i] = (int)val;
+        if ((long int)coords[i] != val)
+            break;  /* Integer lies out of int range */
+    }
+    *nP = i;
+}
+
+
+
+static Quad
+quadFmViewString(const char * const str) {
+/*----------------------------------------------------------------------------
+  Parse a list of four integers in the order {ulx, uly, lrx, lry} into a
+  quadrilateral.
+
+  Abort the program if 'str' is not valid.
+-----------------------------------------------------------------------------*/
+    Quad retval;
+    int coords[16];
+    unsigned int nCoord;
+
+    parseCoords(str, coords, &nCoord);
+
+    if (nCoord != 4)
+        pm_error("failed to parse '%s' as a list of four integers", str);
+
+    retval.ul.x = retval.ll.x = coords[0];
+    retval.ul.y = retval.ur.y = coords[1];
+    retval.lr.x = retval.ur.x = coords[2];
+    retval.lr.y = retval.ll.y = coords[3];
+
+    return retval;
+}
+
+
+
+static Quad
+quadFmIntList(const int * const coords) {
+    Quad retval;
+
+    retval.ul.x = coords[0];
+    retval.ul.y = coords[1];
+    retval.ur.x = coords[2];
+    retval.ur.y = coords[3];
+    retval.lr.x = coords[4];
+    retval.lr.y = coords[5];
+    retval.ll.x = coords[6];
+    retval.ll.y = coords[7];
+
+    return retval;
+}
+
+
+
+static Quad
+quadFmString(const char * const str) {
+/*----------------------------------------------------------------------------
+  Parse a list of eight integers in the order {ulx, uly, urx, ury,
+  lrx, lry, llx, lly} into a quadrilateral.
+
+  Abort the program if 'str' is not a valid list of eight integers.
+-----------------------------------------------------------------------------*/
+    int coords[16];
+    unsigned int nCoord;
+
+    parseCoords(str, coords, &nCoord);
+
+    if (nCoord != 8)
+        pm_error("failed to parse '%s' as a list of eight integers", str);
+
+    return quadFmIntList(coords);
+}
+
+
+
+static void
+parseCommandLine(int                        argc,
+                 const char **        const 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.
+-----------------------------------------------------------------------------*/
+
+    optEntry *option_def;
+        /* Instructions to pm_optParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+
+    unsigned int mapfileSpec, fromSpec, toSpec, viewSpec, fillSpec;
+    const char * from;
+    const char * to;
+    const char * view;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "mapfile",         OPT_STRING, &cmdlineP->mapfile,
+            &mapfileSpec,             0);
+    OPTENT3(0, "from",            OPT_STRING, &from,
+            &fromSpec,                0);
+    OPTENT3(0, "to",              OPT_STRING, &to,
+            &toSpec,                  0);
+    OPTENT3(0, "view",            OPT_STRING, &view,
+            &viewSpec,                0);
+    OPTENT3(0, "fill",            OPT_STRING, &cmdlineP->fill,
+            &fillSpec,                0);
+    OPTENT3(0, "verbose",         OPT_FLAG,   NULL,
+            &cmdlineP->verbose,       0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and local variables. */
+
+    if (!fillSpec)
+        cmdlineP->fill = NULL;
+
+    if (!mapfileSpec)
+        cmdlineP->mapfile = NULL;
+
+    if (fromSpec) {
+        cmdlineP->qmap.from.wholeImage = false;
+        cmdlineP->qmap.from.explicit = quadFmString(from);
+    } else
+        cmdlineP->qmap.from.wholeImage = true;
+
+    if (toSpec) {
+        cmdlineP->qmap.to.wholeImage = false;
+        cmdlineP->qmap.to.explicit = quadFmString(to);
+    } else
+        cmdlineP->qmap.to.wholeImage = true;
+
+    if (viewSpec) {
+        cmdlineP->view.wholeImage = false;
+        cmdlineP->view.explicit   = quadFmViewString(view);
+    } else
+        cmdlineP->view.wholeImage = true;
+
+    if (argc < 2)
+        cmdlineP->inputFilespec = "-";
+    else if (argc == 2)
+        cmdlineP->inputFilespec = argv[1];
+    else
+        pm_error("Too many non-option arguments: %u.  "
+                 "Only possible argument is input file name", argc - 1);
+
+    free((void *) option_def);
+}
+
+
+
+static void
+readMapFile(const char * const fname,
+            QuadMap *    const qmapP) {
+/*----------------------------------------------------------------------------
+  Read from a file either 16 numbers in the order {ulx1, uly1, urx1, ury1,
+  lrx1, lry1, llx1, lly1, ulx2, uly2, urx2, ury2, lrx2, lry2, llx2, lly2}
+  or 8 numbers in the order {ulx2, uly2, urx2, ury2, lrx2, lry2, llx2,
+  lly2}.
+
+  Abort the program if the file does not contain data in this format.
+-----------------------------------------------------------------------------*/
+    FILE * fp;
+    char * str;      /* Entire file contents */
+    int coords[16];  /* File as a list of up to 16 coordinates */
+    unsigned int nCoord;
+    long int nread;
+
+    /* Read the entire file. */
+    fp = pm_openr(fname);
+    str = pm_read_unknown_size(fp, &nread);
+    REALLOCARRAY_NOFAIL(str, nread + 1);
+    str[nread] = '\0';
+    pm_close(fp);
+
+    {
+        unsigned int i;
+        /* Replace newlines and tabs with spaces to prettify error
+           reporting.
+        */
+        for (i = 0; str[i]; ++i)
+            if (isspace(str[i]))
+                str[i] = ' ';
+    }
+    parseCoords(str, coords, &nCoord);
+
+    /* Read either {from, to} or just a {to} quadrilateral. */
+    switch (nCoord) {
+    case 16:
+        /* 16 integers: assign both the "from" and the "to" quadrilateral. */
+        qmapP->from.wholeImage = false;
+        qmapP->from.explicit   = quadFmIntList(&coords[0]);
+        qmapP->to.wholeImage   = false;
+        qmapP->to.explicit     = quadFmIntList(&coords[8]);
+        break;
+    case 8:
+        /* 8 integers: assign only the "to" quadrilateral. */
+        qmapP->from.wholeImage = true;
+        qmapP->to.explicit     = quadFmIntList(coords);
+        break;
+    default:
+        /* Not valid input */
+        pm_error("failed to parse contents of map file '%s' ('%s') "
+                 "as a list of either 8 or 16 integers",
+                 fname, str);
+        break;
+    }
+
+    free(str);
+}
+
+
+
+static void
+reportQuads(Quad const qfrom,
+            Quad const qto) {
+
+    pm_message("Copying from ((%d,%d),(%d,%d),(%d,%d),(%d,%d)) "
+               "to ((%d,%d),(%d,%d),(%d,%d),(%d,%d))",
+               qfrom.ul.x, qfrom.ul.y,
+               qfrom.ur.x, qfrom.ur.y,
+               qfrom.lr.x, qfrom.lr.y,
+               qfrom.ll.x, qfrom.ll.y,
+               qto.ul.x,   qto.ul.y,
+               qto.ur.x,   qto.ur.y,
+               qto.lr.x,   qto.lr.y,
+               qto.ll.x,   qto.ll.y
+        );
+}
+
+
+
+static void
+reportBbox(Quad const bbox) {
+
+    pm_message("The bounding box is ((%d,%d),(%d,%d),(%d,%d),(%d,%d))",
+               bbox.ul.x, bbox.ul.y,
+               bbox.ur.x, bbox.ur.y,
+               bbox.lr.x, bbox.lr.y,
+               bbox.ll.x, bbox.ll.y
+        );
+}
+
+
+
+static tuple
+parseFillColor(const struct pam * const pamP,
+               const char *       const fillColorSpec) {
+/*----------------------------------------------------------------------------
+  Parse the fill color into the correct format for the given PAM metadata.
+-----------------------------------------------------------------------------*/
+    tuple retval;
+
+    if (!fillColorSpec)
+        pnm_createBlackTuple(pamP, &retval);
+    else {
+        tuple const rgb = pnm_parsecolor(fillColorSpec, pamP->maxval);
+
+        retval = pnm_allocpamtuple(pamP);
+
+        switch (pamP->depth) {
+        case 1:
+            /* Grayscale */
+            retval[0] = (rgb[PAM_RED_PLANE]*299 +
+                         rgb[PAM_GRN_PLANE]*587 +
+                         rgb[PAM_BLU_PLANE]*114)/1000;
+            break;
+        case 2:
+            /* Grayscale + alpha */
+            retval[0] = (rgb[PAM_RED_PLANE]*299 +
+                         rgb[PAM_GRN_PLANE]*587 +
+                         rgb[PAM_BLU_PLANE]*114)/1000;
+            retval[PAM_GRAY_TRN_PLANE] = pamP->maxval;
+            break;
+        case 3:
+            /* RGB */
+            pnm_assigntuple(pamP, retval, rgb);
+            break;
+        case 4:
+            /* RGB + alpha */
+            pnm_assigntuple(pamP, retval, rgb);
+            retval[PAM_TRN_PLANE] = pamP->maxval;
+            break;
+        default:
+            pm_error("unexpected image depth %d", pamP->depth);
+            break;
+        }
+    }
+    return retval;
+}
+
+
+
+static tuple **
+initOutputImage(const struct pam * const pamP,
+                const char *       const fillColorSpec) {
+/*----------------------------------------------------------------------------
+  Allocate and initialize the output image data structure.
+-----------------------------------------------------------------------------*/
+    tuple fillColor;    /* Fill color to use for unused coordinates */
+    tuple ** outImg;    /* Output image */
+    unsigned int row;
+
+    outImg = pnm_allocpamarray(pamP);
+
+    fillColor = parseFillColor(pamP, fillColorSpec);
+    for (row = 0; row < pamP->height; ++row) {
+        unsigned int col;
+
+        for (col = 0; col < pamP->width; ++col) {
+            pnm_assigntuple(pamP, outImg[row][col], fillColor);
+        }
+    }
+
+    free((void *) fillColor);
+    return outImg;
+}
+
+
+
+static void
+computeSteps(Quad     const qfrom,
+             Quad     const qto,
+             double * const ustepP,
+             double * const vstepP) {
+/*----------------------------------------------------------------------------
+  Compute increments for u and v as these range from 0.0 to 1.0.
+-----------------------------------------------------------------------------*/
+    double fx0, fx1, fxd;
+    double tx0, tx1, txd;
+    double fy0, fy1, fyd;
+    double ty0, ty1, tyd;
+
+    /* Compute ustep as the inverse of the maximum possible x delta across
+       either the "from" or "to" quadrilateral.
+    */
+    fx0 = MIN4((double)qfrom.ur.x,
+               (double)qfrom.ul.x,
+               (double)qfrom.lr.x,
+               (double)qfrom.ll.x);
+    fx1 = MAX4((double)qfrom.ur.x,
+               (double)qfrom.ul.x,
+               (double)qfrom.lr.x,
+               (double)qfrom.ll.x);
+    fxd = fx1 - fx0;
+
+    tx0 = MIN4((double)qto.ur.x,
+               (double)qto.ul.x,
+               (double)qto.lr.x,
+               (double)qto.ll.x);
+    tx1 = MAX4((double)qto.ur.x,
+               (double)qto.ul.x,
+               (double)qto.lr.x,
+               (double)qto.ll.x);
+    txd = tx1 - tx0;
+
+    if (fxd == 0.0 && txd == 0.0)
+        *ustepP = 1.0;  /* Arbitrary nonzero step */
+    else
+        *ustepP = 0.5/MAX(fxd, txd);
+            /* Divide into 0.5 instead of 1.0 for additional smoothing. */
+
+    /* Compute vstep as the inverse of the maximum possible y delta across
+       either the "from" or "to" quadrilateral.
+    */
+    fy0 = MIN4((double)qfrom.ur.y,
+               (double)qfrom.ul.y,
+               (double)qfrom.lr.y,
+               (double)qfrom.ll.y);
+    fy1 = MAX4((double)qfrom.ur.y,
+               (double)qfrom.ul.y,
+               (double)qfrom.lr.y,
+               (double)qfrom.ll.y);
+    fyd = fy1 - fy0;
+    ty0 = MIN4((double)qto.ur.y,
+               (double)qto.ul.y,
+               (double)qto.lr.y,
+               (double)qto.ll.y);
+    ty1 = MAX4((double)qto.ur.y,
+               (double)qto.ul.y,
+               (double)qto.lr.y,
+               (double)qto.ll.y);
+    tyd = ty1 - ty0;
+
+    if (fyd == 0.0 && tyd == 0.0)
+        *vstepP = 1.0;  /* Arbitrary nonzero step */
+    else
+        *vstepP = 0.5/MAX(fyd, tyd);
+            /* Divide into 0.5 instead of 1.0 for additional smoothing. */
+}
+
+
+
+static Quad
+quadrilateralFmSpec(const struct pam * const pamP,
+                    QuadSpec           const qdata) {
+/*----------------------------------------------------------------------------
+  The quadrilateral specified by 'qdata'.
+-----------------------------------------------------------------------------*/
+    Quad retval;
+
+    if (qdata.wholeImage) {
+        /* Set the quadrilateral to the image's bounding box. */
+        retval.ul = pointXy(0,               0               );
+        retval.ur = pointXy(pamP->width - 1, 0               );
+        retval.ll = pointXy(0,               pamP->height - 1);
+        retval.lr = pointXy(pamP->width - 1, pamP->height - 1);
+    } else {
+        /* Use the quadrilateral as specified. */
+        retval = qdata.explicit;
+    }
+
+    return retval;
+}
+
+
+
+static Point
+coordsAtPercent(Quad   const quad,
+                double const u,
+                double const v) {
+/*----------------------------------------------------------------------------
+  Return the (x, y) coordinates that lie at (u%, v%) from the upper left to
+  the lower right of a given quadrilateral.
+-----------------------------------------------------------------------------*/
+    return pointXy(
+        (int) nearbyint((1.0 - u) * (1.0 - v) * quad.ul.x +   /* x */
+                        u * (1.0 - v) * quad.ur.x +
+                        u * v * quad.lr.x +
+                        (1.0 - u) * v * quad.ll.x),
+        (int) nearbyint((1.0 - u) * (1.0 - v) * quad.ul.y +   /* y */
+                        u * (1.0 - v) * quad.ur.y +
+                        u * v * quad.lr.y +
+                        (1.0 - u) * v * quad.ll.y)
+        );
+}
+
+
+
+static Quad
+boundingBoxOfQuadrilateral(Quad const q) {
+/*----------------------------------------------------------------------------
+  The bounding box of quadrilateral 'q'.
+-----------------------------------------------------------------------------*/
+    Quad retval;
+
+    int const leftLimit = MIN4(q.ul.x, q.ur.x, q.lr.x, q.ll.x);
+    int const rghtLimit = MAX4(q.ul.x, q.ur.x, q.lr.x, q.ll.x);
+    int const topLimit  = MIN4(q.ul.y, q.ur.y, q.lr.y, q.ll.y);
+    int const botLimit  = MAX4(q.ul.y, q.ur.y, q.lr.y, q.ll.y);
+
+    retval.ul = pointXy(leftLimit, topLimit);
+    retval.ur = pointXy(rghtLimit, topLimit);
+    retval.ll = pointXy(leftLimit, botLimit);
+    retval.lr = pointXy(rghtLimit, botLimit);
+
+    return retval;
+}
+
+
+
+static void
+mapQuadrilaterals(const struct pam * const inPamP,
+                  const struct pam * const outPamP,
+                  Quad               const qfrom,
+                  Quad               const qto,
+                  tuple **           const inImg,
+                  tuple **           const outImg,
+                  int                const xofs,
+                  int                const yofs) {
+/*----------------------------------------------------------------------------
+  Map the quadrilateral in the source image to the quadrilateral in the
+  target image.  This is the function that implemens pamhomography's
+  primary functionality.
+-----------------------------------------------------------------------------*/
+    sample ** channel;
+        /* Aggregated values for a single channel */
+    unsigned long ** tally;
+        /* Number of values at each coordinate in the above */
+    double ustep, vstep;
+        /* Steps to use when iterating from 0.0 to 1.0 */
+    unsigned int plane;
+
+    MALLOCARRAY2_NOFAIL(channel, outPamP->height, outPamP->width);
+    MALLOCARRAY2_NOFAIL(tally,   outPamP->height, outPamP->width);
+
+    computeSteps(qfrom, qto, &ustep, &vstep);
+
+    for (plane = 0; plane < outPamP->depth; ++plane) {
+        /* Reset the channel colors and tally for each plane, */
+        unsigned int row;
+        double v;
+        for (row = 0; row < outPamP->height; ++row) {
+            unsigned int col;
+            for (col = 0; col < outPamP->width; ++col) {
+                channel[row][col] = 0;
+                tally  [row][col] = 0;
+            }
+        }
+        /* Iterate from 0% to 100% in the y dimension. */
+        for (v = 0.0; v <= 1.0; v += vstep) {
+            /* Iterate from 0% to 100% in the x dimension. */
+            double u;
+            for (u = 0.0; u <= 1.0; u += ustep) {
+                Point from;  /* "From" coordinate */
+                Point to;    /* "To" coordinate */
+
+                /* Map (u%, v%) of one quadrilateral to (u%, v%) of the other
+                   quadrilateral.
+                */
+                from = coordsAtPercent(qfrom, u, v);
+                to   = coordsAtPercent(qto,   u, v);
+
+                /* Copy the source image's 'from' pixel as the destination
+                   image's 'to' pixel in the current plane.
+                */
+                to.x += xofs;
+                to.y += yofs;
+                if (from.x >= 0 && from.y >= 0 &&
+                    from.x < inPamP->width && from.y < inPamP->height &&
+                    to.x >= 0 && to.y >= 0 &&
+                    to.x < outPamP->width && to.y < outPamP->height) {
+
+                    channel[to.y][to.x] += inImg[from.y][from.x][plane];
+                    ++tally[to.y][to.x];
+                }
+            }
+        }
+
+        /* Assign the current plane in the output image the average color
+           at each point. */
+        for (row = 0; row < outPamP->height; ++row) {
+            unsigned int col;
+            for (col = 0; col < outPamP->width; ++col) {
+                if (tally[row][col] != 0)
+                    outImg[row][col][plane] =
+                        (channel[row][col] + tally[row][col]/2) /
+                        tally[row][col];
+            }
+        }
+    }
+
+    pm_freearray2((void ** const)tally);
+    pm_freearray2((void ** const)channel);
+}
+
+
+
+static void
+processFile(FILE *       const ifP,
+            QuadMap      const qmap,
+            QuadSpec     const view,
+            const char * const fillColorSpec,
+            bool         const verbose) {
+/*----------------------------------------------------------------------------
+  Read the input image, create the output image, and map a quadrilateral in
+  the former to a quadrilateral in the latter.
+-----------------------------------------------------------------------------*/
+    struct pam inPam;    /* PAM metadata for the input file */
+    struct pam outPam;   /* PAM metadata for the output file */
+    tuple ** inImg;      /* Input image */
+    tuple ** outImg;     /* Output image */
+    Quad qfrom, qto;     /* Source and target quadrilaterals */
+    Quad bbox;           /* Bounding box around the transformed input image */
+
+    inImg = pnm_readpam(ifP, &inPam, PAM_STRUCT_SIZE(tuple_type));
+
+    /* Extract quadrilaterals and populate them with the image bounds
+       if necessary. */
+    qfrom = quadrilateralFmSpec(&inPam, qmap.from);
+    qto   = quadrilateralFmSpec(&inPam, qmap.to);
+
+    if (verbose)
+        reportQuads(qfrom, qto);
+
+    /* Allocate storage for the target image. */
+    if (view.wholeImage)
+        bbox = boundingBoxOfQuadrilateral(qto);
+    else
+        bbox = view.explicit;
+
+    if (verbose)
+        reportBbox(bbox);
+
+    outPam = inPam;  /* initial value */
+    outPam.file   = stdout;
+    outPam.width  = bbox.lr.x - bbox.ul.x + 1;
+    outPam.height = bbox.lr.y - bbox.ul.y + 1;
+    outImg        = initOutputImage(&outPam, fillColorSpec);
+
+    mapQuadrilaterals(&inPam, &outPam,
+                      qfrom, qto,
+                      inImg, outImg,
+                      -bbox.ul.x, -bbox.ul.y);
+
+    pnm_writepam(&outPam, outImg);
+
+    pnm_freepamarray(outImg, &outPam);
+    pnm_freepamarray(inImg, &inPam);
+}
+
+
+
+int
+main(int argc, const char *argv[]) {
+
+    struct CmdlineInfo cmdline;      /* Parsed command line */
+    FILE * ifP;
+    QuadMap qmap;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    if (cmdline.mapfile) {
+        /* Use the from and/or to values from the map file where the user
+           didn't explicitly state them
+        */
+        QuadMap mapFileValue;
+
+        readMapFile(cmdline.mapfile, &mapFileValue);
+
+        if (cmdline.qmap.from.wholeImage)
+            qmap.from = mapFileValue.from;
+        else
+            qmap.from = cmdline.qmap.from;
+
+        if (cmdline.qmap.to.wholeImage)
+            qmap.to = mapFileValue.to;
+        else
+            qmap.to = cmdline.qmap.to;
+    } else
+        qmap = cmdline.qmap;
+
+    ifP = pm_openr(cmdline.inputFilespec);
+
+    processFile(ifP, qmap, cmdline.view, cmdline.fill, !!cmdline.verbose);
+
+    pm_close(ifP);
+
+    return 0;
+}
+
+
diff --git a/editor/pamlevels.c b/editor/pamlevels.c
index fbbb2c0b..de2afc45 100644
--- a/editor/pamlevels.c
+++ b/editor/pamlevels.c
@@ -5,7 +5,6 @@
 #include <stdlib.h>
 
 #include "netpbm/pam.h"
-#include "netpbm/pm_system.h"
 #include "netpbm/pm_gamma.h"
 #include "netpbm/nstring.h"
 #include "netpbm/ppm.h"
@@ -482,7 +481,7 @@ pamlevels(CmdlineInfo const cmdline) {
 static void
 freeCmdLineInfo(CmdlineInfo cmdline) {
 /*----------------------------------------------------------------------------
-  Free any memory that has been dynamically allcoated in <cmdline>.
+  Free any memory that has been dynamically allocated in <cmdline>.
 -----------------------------------------------------------------------------*/
     TransSet * const xxP = &cmdline.xlats;
 
diff --git a/editor/pammixmulti.c b/editor/pammixmulti.c
index d303c3de..2b45d807 100644
--- a/editor/pammixmulti.c
+++ b/editor/pammixmulti.c
@@ -13,6 +13,7 @@
 #include "shhopt.h"
 #include "mallocvar.h"
 #include "nstring.h"
+#include "rand.h"
 
 typedef enum {
     BLEND_AVERAGE,   /* Take the average color of all pixels */
@@ -36,6 +37,8 @@ struct ProgramState {
         /* Standard deviation when selecting images via a mask */
     unsigned long ** imageWeights;
         /* Per-image weights as a function of grayscale level */
+    struct pm_randSt randSt;
+        /* Random number generator parameters and internal state */
 };
 
 
@@ -134,9 +137,9 @@ parseCommandLine(int argc, const char ** argv,
 }
 
 static void
-openInputFiles(unsigned int          const inFileCt,
-               const char **         const inFileName,
-               struct ProgramState * const stateP) {
+initInput(unsigned int          const inFileCt,
+          const char **         const inFileName,
+          struct ProgramState * const stateP) {
 /*----------------------------------------------------------------------------
   Open all of the input files.
 
@@ -180,6 +183,25 @@ openInputFiles(unsigned int          const inFileCt,
 }
 
 
+
+static void
+termInput(struct ProgramState * const stateP) {
+/*----------------------------------------------------------------------------
+  Deallocate all of the resources we allocated.
+-----------------------------------------------------------------------------*/
+    unsigned int i;
+
+    for (i = 0; i < stateP->inFileCt; ++i) {
+        pnm_freepamrow(stateP->inTupleRows[i]);
+        pm_close(stateP->inPam[i].file);
+    }
+
+    free(stateP->inTupleRows);
+    free(stateP->inPam);
+}
+
+
+
 static void
 initMask(const char *          const maskFileName,
          struct ProgramState * const stateP) {
@@ -233,6 +255,15 @@ initOutput(FILE *                const ofP,
 }
 
 
+static void
+termOutput(struct ProgramState * const stateP) {
+
+    free(stateP->outTupleRow);
+
+    pm_close(stateP->outPam.file);
+}
+
+
 
 static void
 blendTuplesRandom(struct ProgramState * const stateP,
@@ -243,8 +274,8 @@ blendTuplesRandom(struct ProgramState * const stateP,
   from a random input image.
 -----------------------------------------------------------------------------*/
     unsigned int const depth = stateP->inPam[0].depth;
-    unsigned int const img = (unsigned int) (rand() % stateP->inFileCt);
-
+    unsigned int const img = (unsigned int) (pm_rand(&stateP->randSt) %
+                                             stateP->inFileCt);
     unsigned int samp;
 
     for (samp = 0; samp < depth; ++samp)
@@ -276,23 +307,26 @@ blendTuplesAverage(struct ProgramState * const stateP,
 
 
 
+#if 0
 static void
-randomNormal2(double * const r1P,
-              double * const r2P) {
+randomNormal2(double *           const r1P,
+              double *           const r2P,
+              struct pm_randSt * const randStP) {
 /*----------------------------------------------------------------------------
   Return two normally distributed random numbers.
 -----------------------------------------------------------------------------*/
     double u1, u2;
 
     do {
-        u1 = (double)rand() / RAND_MAX;
-        u2 = (double)rand() / RAND_MAX;
+        u1 = drand48(randStP);
+        u2 = drand48(randStP);
     }
     while (u1 <= DBL_EPSILON);
 
     *r1P = sqrt(-2.0*log(u1)) * cos(2.0*M_PI*u2);
     *r2P = sqrt(-2.0*log(u1)) * sin(2.0*M_PI*u2);
 }
+#endif
 
 
 
@@ -332,7 +366,8 @@ precomputeImageWeights(struct ProgramState * const stateP,
             double r[2];
             unsigned int k;
 
-            randomNormal2(&r[0], &r[1]);
+            pm_gaussrand2(&stateP->randSt, &r[0], &r[1]);
+
             for (k = 0; k < 2; ++k) {
                 int const img =
                     r[k] * sigma + pctGray * stateP->inFileCt * 0.999999;
@@ -453,26 +488,6 @@ blendImages(BlendType             const blend,
 
 
 
-static void
-termState(struct ProgramState * const stateP) {
-/*----------------------------------------------------------------------------
-  Deallocate all of the resources we allocated.
------------------------------------------------------------------------------*/
-    unsigned int i;
-
-    for (i = 0; i < stateP->inFileCt; ++i) {
-        pnm_freepamrow(stateP->inTupleRows[i]);
-        pm_close(stateP->inPam[i].file);
-    }
-
-    free(stateP->outTupleRow);
-    free(stateP->inTupleRows);
-    free(stateP->inPam);
-    pm_close(stateP->outPam.file);
-}
-
-
-
 int
 main(int argc, const char * argv[]) {
 
@@ -483,13 +498,14 @@ main(int argc, const char * argv[]) {
 
     parseCommandLine(argc, argv, &cmdline);
 
-    srand(cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed());
-
-    openInputFiles(cmdline.inFileNameCt, cmdline.inFileName, &state);
+    initInput(cmdline.inFileNameCt, cmdline.inFileName, &state);
 
     if (cmdline.blend == BLEND_MASK)
         initMask(cmdline.maskfile, &state);
 
+    pm_randinit(&state.randSt);
+    pm_srand2(&state.randSt, cmdline.randomseedSpec, cmdline.randomseed);
+
     initOutput(stdout, &state);
 
     if (cmdline.blend == BLEND_MASK)
@@ -497,10 +513,14 @@ main(int argc, const char * argv[]) {
 
     blendImages(cmdline.blend, &state);
 
+    termOutput(&state);
+
+    pm_randterm(&state.randSt);
+
     if (cmdline.blend == BLEND_MASK)
         termMask(&state);
 
-    termState(&state);
+    termInput(&state);
 
     freeCmdline(&cmdline);
 
diff --git a/editor/pamperspective.c b/editor/pamperspective.c
index a206b57f..a8b1cf8f 100644
--- a/editor/pamperspective.c
+++ b/editor/pamperspective.c
@@ -804,7 +804,7 @@ static void determine_world_parallelogram (world_data *const world,
   yw_lr = world->yi_lr * zw_lr;
 
   /* Now we introduce the margin. There are several ways the margin can be
-     defined. margin_spec keeps track of wether one of them has yet been
+     defined. margin_spec keeps track of whether one of them has yet been
      used. As long as margin_spec==FALSE, the variables top_margin to
      bottom_margin are not initialized! */
 
diff --git a/editor/pamrecolor.c b/editor/pamrecolor.c
index 8c5bce12..86c1965c 100644
--- a/editor/pamrecolor.c
+++ b/editor/pamrecolor.c
@@ -1,3 +1,4 @@
+
 /* ----------------------------------------------------------------------
  *
  * Replace every pixel in an image with one of equal luminance
@@ -32,6 +33,7 @@
 
 #include "mallocvar.h"
 #include "nstring.h"
+#include "rand.h"
 #include "shhopt.h"
 #include "pam.h"
 
@@ -42,7 +44,7 @@
 #define CLAMPxy(N, A, B) MAX(MIN((float)(N), (float)(B)), (float)(A))
 
 
-struct rgbfrac {
+struct Rgbfrac {
     /* This structure represents red, green, and blue, each expressed
        as a fraction from 0.0 to 1.0.
     */
@@ -51,19 +53,19 @@ struct rgbfrac {
     float bfrac;
 };
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* This structure represents all of the information the user
        supplied in the command line but in a form that's easy for the
        program to use.
     */
     const char *    inputFileName;  /* '-' if stdin */
     const char *    colorfile;      /* NULL if unspecified */
-    struct rgbfrac  color2gray;
+    struct Rgbfrac  color2gray;
         /* colorspace/rmult/gmult/bmult options.  Negative numbers if
            unspecified.
         */
     unsigned int    targetcolorSpec;
-    struct rgbfrac  targetcolor;
+    struct Rgbfrac  targetcolor;
     unsigned int    randomseed;
     unsigned int    randomseedSpec;
 };
@@ -71,7 +73,7 @@ struct cmdlineInfo {
 
 
 static float
-rgb2gray(struct rgbfrac * const color2grayP,
+rgb2gray(struct Rgbfrac * const color2grayP,
          float            const red,
          float            const grn,
          float            const blu) {
@@ -122,7 +124,7 @@ getColorRow(struct pam  * const pamP,
 
 static void
 convertRowToGray(struct pam     * const pamP,
-                 struct rgbfrac * const color2gray,
+                 struct Rgbfrac * const color2gray,
                  tuplen         * const tupleRow,
                  samplen        * const grayRow) {
 /*----------------------------------------------------------------------
@@ -160,7 +162,7 @@ convertRowToGray(struct pam     * const pamP,
 static void
 explicitlyColorRow(struct pam *   const pamP,
                    tuplen *       const rowData,
-                   struct rgbfrac const tint) {
+                   struct Rgbfrac const tint) {
 
     unsigned int col;
 
@@ -175,17 +177,25 @@ explicitlyColorRow(struct pam *   const pamP,
 
 static void
 randomlyColorRow(struct pam *   const pamP,
-                 tuplen *       const rowData) {
+                 tuplen *       const rowData,
+                 bool           const randomseedSpec,
+                 unsigned int   const randomseed) {
 /*----------------------------------------------------------------------
   Assign each tuple in a row a random color.
 ------------------------------------------------------------------------*/
     unsigned int col;
+    struct pm_randSt randSt;
+
+    pm_randinit(&randSt);
+    pm_srand2(&randSt, randomseedSpec, randomseed);
 
     for (col = 0; col < pamP->width; ++col) {
-        rowData[col][PAM_RED_PLANE] = rand() / (float)RAND_MAX;
-        rowData[col][PAM_GRN_PLANE] = rand() / (float)RAND_MAX;
-        rowData[col][PAM_BLU_PLANE] = rand() / (float)RAND_MAX;
+        rowData[col][PAM_RED_PLANE] = pm_drand(&randSt);
+        rowData[col][PAM_GRN_PLANE] = pm_drand(&randSt);
+        rowData[col][PAM_BLU_PLANE] = pm_drand(&randSt);
     }
+
+    pm_randterm(&randSt);
 }
 
 
@@ -193,7 +203,7 @@ randomlyColorRow(struct pam *   const pamP,
 static void
 recolorRow(struct pam     * const inPamP,
            tuplen         * const inRow,
-           struct rgbfrac * const color2grayP,
+           struct Rgbfrac * const color2grayP,
            tuplen         * const colorRow,
            struct pam     * const outPamP,
            tuplen         * const outRow) {
@@ -293,10 +303,10 @@ recolorRow(struct pam     * const inPamP,
 
 
 
-static struct rgbfrac
+static struct Rgbfrac
 color2GrayFromCsName(const char * const csName) {
 
-    struct rgbfrac retval;
+    struct Rgbfrac retval;
 
     /* Thanks to
        http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
@@ -352,7 +362,7 @@ color2GrayFromCsName(const char * const csName) {
 
 static void
 parseCommandLine(int argc, const char ** const argv,
-                 struct cmdlineInfo * const cmdlineP ) {
+                 struct CmdlineInfo * const cmdlineP ) {
 
     optEntry     * option_def;
         /* Instructions to OptParseOptions3 on how to parse our options */
@@ -445,7 +455,7 @@ parseCommandLine(int argc, const char ** const argv,
 
 int
 main(int argc, const char *argv[]) {
-    struct cmdlineInfo cmdline;          /* Command-line parameters */
+    struct CmdlineInfo cmdline;          /* Command-line parameters */
     struct pam         inPam;
     struct pam         outPam;
     struct pam         colorPam;
@@ -462,8 +472,6 @@ main(int argc, const char *argv[]) {
 
     parseCommandLine(argc, argv, &cmdline);
 
-    srand(cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed());
-
     ifP = pm_openr(cmdline.inputFileName);
     inPam.comment_p = &comments;
     pnm_readpaminit(ifP, &inPam, PAM_STRUCT_SIZE(comment_p));
@@ -474,7 +482,6 @@ main(int argc, const char *argv[]) {
     outPam.depth = 4 - (inPam.depth % 2);
     outPam.allocation_depth = outPam.depth;
     strcpy(outPam.tuple_type, PAM_PPM_TUPLETYPE);
-    pnm_writepaminit(&outPam);
 
     if (cmdline.colorfile) {
         colorfP = pm_openr(cmdline.colorfile);
@@ -492,6 +499,8 @@ main(int argc, const char *argv[]) {
 
     colorRowBuffer = pnm_allocpamrown(&outPam);
 
+    pnm_writepaminit(&outPam);
+
     for (row = 0; row < inPam.height; ++row) {
         tuplen * colorRow;
 
@@ -505,7 +514,8 @@ main(int argc, const char *argv[]) {
             if (cmdline.targetcolorSpec)
                 explicitlyColorRow(&colorPam, colorRow, cmdline.targetcolor);
             else
-                randomlyColorRow(&colorPam, colorRow);
+                randomlyColorRow(&colorPam, colorRow,
+                                 cmdline.randomseedSpec, cmdline.randomseed);
         }
         recolorRow(&inPam, inRow,
                    &cmdline.color2gray, colorRow,
diff --git a/editor/pamrestack.c b/editor/pamrestack.c
new file mode 100644
index 00000000..46321774
--- /dev/null
+++ b/editor/pamrestack.c
@@ -0,0 +1,472 @@
+/*=============================================================================
+                               pamrestack
+===============================================================================
+  Part of the Netpbm package.
+
+  Rearrange pixels of a Netpbm image into different size rows.
+
+  E.g. if an image is 100 pixels wide and 50 pixels high, you can rearrange it
+  to 125 wide and 40 high.  In that case, 25 pixels from the 2nd row of the
+  input would be moved to the end of the 1st row of input, 50 pixels from the
+  3rd row would be moved to the 2nd row, etc.
+
+  If new width is less than the input image width, move the excess pixels
+  to the start (=left edge) of the next row.
+
+  If new width is larger, complete row by bringing pixels from the start
+  of the next row.
+
+  By Akira F. Urushibata
+
+  Contributed to the public domain by its author.
+=============================================================================*/
+
+#include <assert.h>
+#include <math.h>
+#include <limits.h>
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "nstring.h"
+#include "pam.h"
+#include "shhopt.h"
+
+static unsigned int const maxSize = INT_MAX - 10;
+
+static void
+validateWidth(double       const width,
+              const char * const message) {
+/*----------------------------------------------------------------------------
+  Check width.  Ensure it is a value accepted by other Netpbm programs.
+-----------------------------------------------------------------------------*/
+    assert(maxSize < INT_MAX);
+
+    if (width > maxSize)
+        pm_error("%s %.0f is too large.", message, width);
+}
+
+
+
+static void
+validateHeight(double const height) {
+/*----------------------------------------------------------------------------
+  Fail if image height of 'height' is too great for the computations in
+  this program to work.
+-----------------------------------------------------------------------------*/
+    if (height > maxSize)
+        pm_error("Input image is large and -width value is small."
+                 "Calulated height %.0f is too large.", height);
+}
+
+
+
+enum TrimMode {TRIMMODE_NOP, TRIMMODE_FILL, TRIMMODE_CROP, TRIMMODE_ABORT};
+
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char *  inputFileName;
+    unsigned int  width;
+    unsigned int  widthSpec;
+    enum TrimMode trim;
+    unsigned int  verbose;
+};
+
+static void
+parseCommandLine(int argc, const char ** const argv,
+                 struct CmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   Note that the file spec array we return is stored in the storage that
+   was passed to us as the argv array.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;
+        /* Instructions to OptParseOptions3 on how to parse our options. */
+    optStruct3 opt;
+
+    const char * trimOpt;
+    unsigned int trimSpec;
+
+    unsigned int option_def_index;
+
+    MALLOCARRAY(option_def, 100);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = false;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = true;  /* We have no parms that are negative numbers */
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "width",         OPT_UINT,    &cmdlineP->width,
+            &cmdlineP->widthSpec,     0);
+    OPTENT3(0, "trim",          OPT_STRING, &trimOpt,
+            &trimSpec,                0);
+    OPTENT3(0, "verbose",       OPT_FLAG,   NULL,
+            &cmdlineP->verbose,       0);
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+    /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    free(option_def);
+
+    if (cmdlineP->widthSpec) {
+        if (cmdlineP->width == 0)
+            pm_error("Width value must be positive.  You specified 0");
+        else
+            validateWidth((double) cmdlineP->width,
+                          "Specified -width value");
+    }
+
+    if (trimSpec) {
+        if (streq(trimOpt, "fill")) {
+            cmdlineP->trim = TRIMMODE_FILL;
+        } else if (streq(trimOpt, "crop")) {
+            cmdlineP->trim = TRIMMODE_CROP;
+        } else if (streq(trimOpt, "abort")) {
+            cmdlineP->trim = TRIMMODE_ABORT;
+        } else
+            /* NOP is not specified from the command line */
+            pm_error("Invalid value for -trim: '%s'", trimOpt);
+    } else
+        cmdlineP->trim = TRIMMODE_FILL;  /* default */
+
+    if (argc-1 < 1)
+        cmdlineP->inputFileName = "-";
+    else {
+        cmdlineP->inputFileName = argv[1];
+
+        if (argc-1 > 1)
+            pm_error("Too many arguments (%u). "
+                     "The only possible argument is the input file name.",
+                     argc-1);
+    }
+}
+
+
+
+static void
+adjustTrimMode(double          const inPixels,
+               double          const outWidth,
+               double          const outHeight,
+               bool            const verbose,
+               enum TrimMode   const originalMode,
+               enum TrimMode * const adjustedModeP) {
+/*----------------------------------------------------------------------------
+   Adjust trim mode, taking into account the number of pixels in the
+   input image and the width and height of the output image.
+
+   Check whether conditions are met for abort.
+   Set mode to NOP if all output rows will be full.
+-----------------------------------------------------------------------------*/
+    double const outPixels = outWidth * outHeight;
+
+    enum TrimMode adjustedMode;
+
+    if (inPixels == outPixels)
+        adjustedMode = TRIMMODE_NOP;
+    else {
+        if (originalMode == TRIMMODE_ABORT)
+            pm_error("Abort mode specified and input image has %.0f pixels "
+                     "which is %s specified width value %.0f",
+                     inPixels,
+                     inPixels < outWidth ? "less than" : "not a multiple of",
+                     outWidth);
+        else
+            adjustedMode = originalMode;
+    }
+
+    validateHeight(outHeight + (adjustedMode == TRIMMODE_FILL) ? 1 : 0);
+
+    switch (adjustedMode) {
+    case TRIMMODE_NOP:
+        if (verbose)
+            pm_message("Input image and output image have the same "
+                       "number of pixels.");
+        break;
+    case TRIMMODE_FILL:
+        if (verbose)
+            pm_message("Output image will have %.0f more pixels "
+                       "than input image.  Incomplete final row "
+                       "will be padded.", inPixels - outPixels);
+        break;
+    case TRIMMODE_CROP:
+        if (outHeight == 0)
+            pm_error("No row left after cropping incomplete row. "
+                     "Aborting.");
+        else if (verbose)
+            pm_message("Incomplete final row will be cropped.  %.0f "
+                       "pixels lost.", inPixels - outPixels);
+        break;
+    case TRIMMODE_ABORT:
+        pm_error("internal error");  /* Suppress compiler warning */
+        break;
+    }
+
+    *adjustedModeP = adjustedMode;
+}
+
+
+
+/*----------------------------------------------------------------------------
+  Width conversion using pointer arrays
+
+  This program reads input rows and converts to output rows of desired
+  width using a device which employs pointer arrays on both sides.
+  Conceptually similar, yet more simple, devices are used in pamcut,
+  pnmpad, pamflip and pnmcat.
+
+  inputPointers[] is an expanded version of incols[] seen in many pam
+  programs.  It reads multiple rows: as many rows as necessary to
+  complete at least one output row.
+
+  The read positions within inputPointers[] are fixed.  For example, if
+  the input row width is 100 and inputPointers has 400 elements, the read
+  positions will be: 0-99, 100-199, 200-299, 300-399.
+
+  The outPointers[] array is set up to allow selecting elements for
+  write from inputPointers[].  outPointers[] is at least as large as
+  inPointers[].  The write position migrates as necessary in a cycle.
+  If input width and output width are coprime and output has a
+  sufficient number of rows, all positions within outPointers[]
+  will be utilized.
+
+  Once set up, the conversion device is not altered until the input image
+  is completely read.
+
+  The following are special cases in which inPointers[] and outPointers[]
+  are set to the same size:
+
+  (1) Input width and output width are equal.
+  (2) Output width is an integer multiple of input width.
+  (3) Input width is an integer multiple of output width.
+
+  In cases (1) (2), the output position is fixed.
+  In case (3) the output position is mobile, but all of them will start
+  at integer multiples of output width.
+
+  Note that width, height and width * height variables are of type
+  "double" as a safeguard against overflows.
+-----------------------------------------------------------------------------*/
+
+
+
+static void
+setOutputDimensions(struct CmdlineInfo * const cmdlineP,
+                    double               const inPixelCt,
+                    int *                const outWidthP,
+                    int *                const outHeightP,
+                    enum TrimMode *      const trimModeP) {
+/*-----------------------------------------------------------------------------
+  Calculate the width and height of output from the number of pixels in
+  the input and command line arguments, most notably desired width.
+-----------------------------------------------------------------------------*/
+    double outWidth, outHeight;
+    enum TrimMode adjustedMode;
+
+    if (!cmdlineP->widthSpec) {
+        outWidth = inPixelCt;
+        outHeight = 1;
+        validateWidth(outWidth,
+                      "Input image is large and -width not specified. "
+                      "Output width");
+        adjustedMode = cmdlineP->trim;
+    } else {
+        double preAdjustedOutHeight;
+
+        outWidth  = cmdlineP->width;
+        preAdjustedOutHeight = floor(inPixelCt / outWidth);
+
+        adjustTrimMode(inPixelCt, outWidth, preAdjustedOutHeight,
+                       cmdlineP->verbose,
+                       cmdlineP->trim, &adjustedMode);
+
+        outHeight = adjustedMode == TRIMMODE_FILL ?
+            preAdjustedOutHeight + 1 : preAdjustedOutHeight;
+    }
+
+    *outWidthP  = (unsigned int)outWidth;
+    *outHeightP = (unsigned int)outHeight;
+    *trimModeP  = adjustedMode;
+}
+
+
+
+static void
+calculateInOutSize(unsigned int   const inWidth,
+                   unsigned int   const outWidth,
+                   unsigned int * const inputPointersWidthP,
+                   unsigned int * const outputPointersWidthP) {
+/*----------------------------------------------------------------------------
+  Calculate array size of inPointers[] and outPointers[] from
+  input width and output width.
+-----------------------------------------------------------------------------*/
+    double inputPointersWidth;
+    double outputPointersWidth;
+
+    if (outWidth > inWidth) {
+        if (outWidth % inWidth == 0)
+            inputPointersWidth = outputPointersWidth = outWidth;
+        else {
+            inputPointersWidth =
+              (outWidth / inWidth + 1) * inWidth * 2;
+            outputPointersWidth = inputPointersWidth + outWidth - 1;
+        }
+    }
+    else if (outWidth == inWidth)
+            inputPointersWidth = outputPointersWidth = outWidth;
+    else { /* outWidth < inWidth) */
+        if (inWidth % outWidth == 0)
+            inputPointersWidth = outputPointersWidth = inWidth;
+        else {
+            inputPointersWidth = inWidth * 2;
+            outputPointersWidth = inputPointersWidth + outWidth - 1;
+        }
+    }
+
+    if(inputPointersWidth > SIZE_MAX || outputPointersWidth > SIZE_MAX)
+        pm_error("Failed to set up conversion array.  Either input width, "
+                 "output width or their difference is too large.");
+
+    *inputPointersWidthP  = (unsigned int) inputPointersWidth;
+    *outputPointersWidthP = (unsigned int) outputPointersWidth;
+}
+
+
+
+static void
+restack(struct pam    * const inpamP,
+        struct pam    * const outpamP,
+        tuple         * const inputPointers,
+        tuple         * const outputPointers,
+        unsigned int    const inputPointersWidth,
+        unsigned int    const outputPointersWidth,
+        enum TrimMode   const trimMode) {
+/*----------------------------------------------------------------------------
+  Convert image, using inputPointers[] and outputPointers[]
+-----------------------------------------------------------------------------*/
+    unsigned int inoffset;
+    unsigned int outoffset;
+    unsigned int inPixelCt; /* Count of pixels read since last write */
+    unsigned int row;
+
+    /* Read all input and write all rows with the exception of the final
+       partial row */
+
+    for (row = 0, inoffset = 0, outoffset = 0, inPixelCt = 0;
+         row < inpamP->height; ++row) {
+
+        pnm_readpamrow(inpamP, &inputPointers[inoffset]);
+        inPixelCt += inpamP->width;
+
+        for ( ; inPixelCt >= outpamP->width; inPixelCt -= outpamP->width) {
+            pnm_writepamrow(outpamP, &outputPointers[outoffset]);
+            outoffset = (outoffset + outpamP->width ) % inputPointersWidth;
+        }
+        inoffset = (inoffset + inpamP->width) % inputPointersWidth;
+    }
+
+    /* Fill remainder of last row with black pixels and output */
+
+    if (inPixelCt > 0 && trimMode == TRIMMODE_FILL) {
+        tuple blackTuple;
+        unsigned int col;
+
+        pnm_createBlackTuple(outpamP, &blackTuple);
+
+        for (col = inPixelCt; col < outpamP->width; ++col) {
+            unsigned int const outoffset2 =
+                (outoffset + col) % outputPointersWidth;
+            outputPointers[outoffset2] = blackTuple;
+        }
+
+        /* output final row */
+        pnm_writepamrow(outpamP, &outputPointers[outoffset]);
+    }
+}
+
+
+
+static void
+restackSingleImage(FILE *               const ifP,
+                   struct CmdlineInfo * const cmdlineP) {
+
+    struct pam inpam;   /* Input PAM image */
+    struct pam mpam;    /* Adjusted PAM structure to read multiple rows */
+    struct pam outpam;  /* Output PAM image */
+
+    double        inPixelCt;
+    enum TrimMode trimMode;
+    tuple *       inputPointers;
+    tuple *       outputPointers;
+    unsigned int  inputPointersWidth;
+    unsigned int  outputPointersWidth;
+
+    pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
+
+    inPixelCt = inpam.width * inpam.height;
+
+    outpam = inpam;
+
+    setOutputDimensions(cmdlineP, inPixelCt, &outpam.width, &outpam.height,
+                        &trimMode);
+
+    outpam.file = stdout;
+
+    pnm_writepaminit(&outpam);
+
+    calculateInOutSize(inpam.width, outpam.width,
+                       &inputPointersWidth, &outputPointersWidth);
+
+    mpam = inpam;
+    mpam.width = inputPointersWidth;
+
+    inputPointers = pnm_allocpamrow(&mpam);
+
+    if (outputPointersWidth > inputPointersWidth) {
+        unsigned int col;
+
+        MALLOCARRAY(outputPointers, outputPointersWidth);
+
+        if (!outputPointers) {
+            pm_error("Unable to allocate memory for %u output pointers",
+                     outputPointersWidth);
+        }
+
+        /* Copy pointers as far as inputPointers[] goes, then wrap around */
+        for (col = 0; col < outputPointersWidth; ++col)
+            outputPointers[col] = inputPointers[col % inputPointersWidth];
+
+    } else
+        outputPointers = inputPointers;
+
+    restack(&inpam, &outpam, inputPointers, outputPointers,
+            inputPointersWidth, outputPointersWidth, trimMode);
+
+    if (inputPointers != outputPointers)
+        free(outputPointers);
+
+    pnm_freepamrow(inputPointers);
+}
+
+
+
+int
+main(int argc, const char * argv[]) {
+
+    struct CmdlineInfo cmdline;
+    FILE * ifP;
+    int    eof;     /* no more images in input stream */
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    for (eof = false; !eof; ) {
+        restackSingleImage(ifP, &cmdline);
+        pnm_nextimage(ifP, &eof);
+    }
+
+    pm_close(ifP);
+
+    return 0;
+}
diff --git a/editor/pamrubber.c b/editor/pamrubber.c
index 7169dbcf..f68e36fe 100644
--- a/editor/pamrubber.c
+++ b/editor/pamrubber.c
@@ -1,20 +1,18 @@
-/*----------------------------------------------------------------------------*/
-
-/* pamrubber.c - transform images using Rubber Sheeting algorithm
-**               see: http://www.schaik.com/netpbm/rubber/
-**
-** Copyright (C) 2011 by 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.
-*/
-
-/*----------------------------------------------------------------------------*/
-
+/*=============================================================================
+                              pamrubber
+===============================================================================
+  Transform images using Rubber Sheeting algorithm
+  See: http://www.schaik.com/netpbm/rubber/
+
+  Copyright (C) 2011 by 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.
+=============================================================================*/
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -25,12 +23,12 @@
 
 #include "pm_c_util.h"
 #include "mallocvar.h"
+#include "rand.h"
 #include "shhopt.h"
 #include "pam.h"
 #include "pamdraw.h"
 
 
-
 typedef struct {
   double x;
   double y;
@@ -54,7 +52,7 @@ typedef struct {
     point br;  /* bottom right */
 } quadrilateral;
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     unsigned int nCP;
     point        oldCP[4];
     point        newCP[4];
@@ -64,14 +62,14 @@ struct cmdlineInfo {
     unsigned int frame;
     unsigned int linear;
     unsigned int verbose;
-    unsigned int randseedSpec;
-    unsigned int randseed;
+    unsigned int randomseedSpec;
+    unsigned int randomseed;
 };
 
 
 static void
 parseCmdline(int argc, const char ** argv,
-             struct cmdlineInfo * const cmdlineP) {
+             struct CmdlineInfo * const cmdlineP) {
 
 /* parse all parameters from the command line */
 
@@ -83,7 +81,7 @@ parseCmdline(int argc, const char ** argv,
     /* instructions to optParseOptions3 on how to parse our options. */
     optEntry * option_def;
     optStruct3 opt;
-    
+
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENT3 */
@@ -92,10 +90,10 @@ parseCmdline(int argc, const char ** argv,
     OPTENT3(0, "frame",    OPT_FLAG, NULL, &cmdlineP->frame,    0);
     OPTENT3(0, "linear",   OPT_FLAG, NULL, &cmdlineP->linear,   0);
     OPTENT3(0, "verbose",  OPT_FLAG, NULL, &cmdlineP->verbose,  0);
-    OPTENT3(0, "randseed", OPT_UINT, &cmdlineP->randseed,
-            &cmdlineP->randseedSpec, 0);
-    OPTENT3(0, "randomseed", OPT_UINT, &cmdlineP->randseed,
-            &cmdlineP->randseedSpec, 0);
+    OPTENT3(0, "randseed", OPT_UINT, &cmdlineP->randomseed,
+            &cmdlineP->randomseedSpec, 0);
+    OPTENT3(0, "randomseed", OPT_UINT, &cmdlineP->randomseed,
+            &cmdlineP->randomseedSpec, 0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* we have no short (old-fashioned) options */
@@ -195,38 +193,39 @@ makeline(point const p1,
 
 
 
-static bool
-intersect(line *  const l1P,
-          line *  const l2P,
-          point * const pP) {
+static void
+findIntersection(const line *  const l1P,
+                 const line *  const l2P,
+                 bool *        const theyIntersectP,
+                 point *       const intersectionP) {
 
-    bool cross;
+    bool theyIntersect;
 
     if (((l2P->p2.y - l2P->p1.y) * (l1P->p2.x - l1P->p1.x) -
          (l2P->p2.x - l2P->p1.x) * (l1P->p2.y - l1P->p1.y)) == 0) {
         /* parallel lines */
 
-        cross = false;
+        theyIntersect = false;
 
         if ((l1P->p1.x == l1P->p2.x) && (l2P->p1.x == l2P->p2.x)) {
             /* two vertical lines */
-            pP->x = (l1P->p1.x + l2P->p1.x) / 2.0;
-            pP->y = 1e10;
+            intersectionP->x = (l1P->p1.x + l2P->p1.x) / 2.0;
+            intersectionP->y = 1e10;
         } else if ((l1P->p1.y == l1P->p2.y) && (l2P->p1.y == l2P->p2.y)) {
             /* two horizontal lines */
-            pP->x = 1e10;
-            pP->y = (l1P->p1.y + l2P->p1.y) / 2.0;
+            intersectionP->x = 1e10;
+            intersectionP->y = (l1P->p1.y + l2P->p1.y) / 2.0;
         } else {
             if (fabs(l1P->p2.y - l1P->p1.y) > fabs(l1P->p2.x - l1P->p1.x)) {
                 /* steep slope */
-                pP->y = 1e10;
-                pP->x = (l1P->p2.x - l1P->p1.x) / (l1P->p2.y - l1P->p1.y)
-                    * 1e10;
+                intersectionP->y = 1e10;
+                intersectionP->x =
+                    (l1P->p2.x - l1P->p1.x) / (l1P->p2.y - l1P->p1.y) * 1e10;
             } else {
                 /* even slope */
-                pP->x = 1e10;
-                pP->y = (l1P->p2.y - l1P->p1.y) / (l1P->p2.x - l1P->p1.x)
-                    * 1e10;
+                intersectionP->x = 1e10;
+                intersectionP->y =
+                    (l1P->p2.y - l1P->p1.y) / (l1P->p2.x - l1P->p1.x) * 1e10;
             }
         }
     } else {
@@ -244,16 +243,16 @@ intersect(line *  const l1P,
                * (l1P->p2.x - l1P->p1.x) - (l2P->p2.x - l2P->p1.x)
                * (l1P->p2.y - l1P->p1.y));
 
-        pP->x = l1P->p1.x + ua * (l1P->p2.x - l1P->p1.x);
-        pP->y = l1P->p1.y + ua * (l1P->p2.y - l1P->p1.y);
+        intersectionP->x = l1P->p1.x + ua * (l1P->p2.x - l1P->p1.x);
+        intersectionP->y = l1P->p1.y + ua * (l1P->p2.y - l1P->p1.y);
 
         if ((ua >= 0.0) && (ua <= 1.0) && (ub >= 0.0) && (ub <= 1.0))
-            cross = true;
+            theyIntersect = true;
         else
-            cross = false;
+            theyIntersect = false;
     }
-
-    return cross;
+    if (theyIntersectP)
+        *theyIntersectP = theyIntersect;
 }
 
 
@@ -268,7 +267,7 @@ maketriangle(point const p1,
     retval.p1 = p1;
     retval.p2 = p2;
     retval.p3 = p3;
-    
+
     return retval;
 }
 
@@ -309,28 +308,29 @@ insidetri(triangle * const triP,
 
 
 static bool
-windtriangle(triangle * const tP,
+windtriangle(triangle * const triP,
              point      const p1,
              point      const p2,
              point      const p3) {
     point f, c;
-    line le, lv;
     bool cw;
 
     /* find cross of vertical through p3 and the edge p1-p2 */
     f.x = p3.x;
     f.y = -1.0;
-    lv = makeline(p3, f);
-    le = makeline(p1, p2);
-    intersect(&le, &lv, &c);
+    {
+        line const lv = makeline(p3, f);
+        line const le = makeline(p1, p2);
+        findIntersection(&le, &lv, NULL, &c);
+    }
 
     /* check for clockwise winding triangle */
     if (((p1.x > p2.x) && (p3.y < c.y)) ||
         ((p1.x < p2.x) && (p3.y > c.y))) {
-        *tP = maketriangle(p1, p2, p3);
+        *triP = maketriangle(p1, p2, p3);
         cw = true;
     } else { /* p1/2/3 were counter clockwise */
-        *tP = maketriangle(p1, p3, p2);
+        *triP = maketriangle(p1, p3, p2);
         cw = false;
     }
     return cw;
@@ -339,28 +339,29 @@ windtriangle(triangle * const tP,
 
 
 static double
-tiny(void) {
+tiny(struct pm_randSt * const randStP) {
 
-    if (rand() % 2)
-        return +1E-6 * (double) ((rand() % 90) + 9);
+    if (pm_rand(randStP) % 2)
+        return +1E-6 * (double) ((pm_rand(randStP) % 90) + 9);
     else
-        return -1E-6 * (double) ((rand() % 90) + 9);
+        return -1E-6 * (double) ((pm_rand(randStP) % 90) + 9);
 }
 
 
 
 static void
 angle(point * const p1P,
-      point * const p2P) {
+      point * const p2P,
+      struct pm_randSt * const randStP) {
 /*----------------------------------------------------------------------------
    Move *p2P slightly if necessary to make sure the line (*p1P, *p2P)
    is not horizontal or vertical.
 -----------------------------------------------------------------------------*/
     if (p1P->x == p2P->x) { /* vertical line */
-        p2P->x += tiny();
+        p2P->x += tiny(randStP);
     }
     if (p1P->y == p2P->y) { /* horizontal line */
-        p2P->y += tiny();
+        p2P->y += tiny(randStP);
     }
 }
 
@@ -382,11 +383,11 @@ sideTriangleVerticalEdge(unsigned int const n,
                          point        const p24,
                          point        const r21,
                          point        const r22) {
-                                   
+
     if (((n >= 4) && (r11.x < p11.x)
          && (p14.x < p13.x) && (p14.x < p12.x)
          && (p14.x < p11.x)) /* left edge */
-        || 
+        ||
         ((n >= 4) && (r11.x > p11.x)
          && (p14.x > p13.x) && (p14.x > p12.x)
          && (p14.x > p11.x))) /* right edge */ {
@@ -394,7 +395,7 @@ sideTriangleVerticalEdge(unsigned int const n,
         *trig2P = maketriangle(r21, r22, p24);
     } else if (((n >= 3) && (r11.x < p11.x) && (p13.x < p12.x)
                 && (p13.x < p11.x)) /* left edge */
-               || 
+               ||
                ((n >= 3) && (r11.x > p11.x) && (p13.x > p12.x)
                 && (p13.x > p11.x))) /* right edge */ {
         *trig1P = maketriangle(r11, r12, p13);
@@ -403,7 +404,7 @@ sideTriangleVerticalEdge(unsigned int const n,
                 && (p12.x < p11.x)) /* left edge */
                ||
                ((n >= 2) && (r11.x > p11.x)
-                && (p12.x > p11.x))) /* right edge */ { 
+                && (p12.x > p11.x))) /* right edge */ {
         *trig1P = maketriangle(r11, r12, p12);
         *trig2P = maketriangle(r21, r22, p22);
     } else if (n >= 1) {
@@ -430,24 +431,24 @@ sideTriangleHorizontalEdge(unsigned int const n,
                            point        const p24,
                            point        const r21,
                            point        const r22) {
-                                   
+
     if (((n >= 4) && (r11.y < p11.y) && (p14.y < p13.y)
          && (p14.y < p12.y) && (p14.y < p11.y)) /* top edge */
-        || 
+        ||
         ((n >= 4) && (r11.y > p11.y) && (p14.y > p13.y)
          && (p14.y > p12.y) && (p14.y > p11.y))) /* bottom edge */ {
         *trig1P = maketriangle(r11, r12, p14);
         *trig2P = maketriangle(r21, r22, p24);
     } else if (((n >= 3) && (r11.y < p11.y) && (p13.y < p12.y)
                 && (p13.y < p11.y)) /* top edge */
-               || 
+               ||
                ((n >= 3) && (r11.y > p11.y) && (p13.y > p12.y)
                 && (p13.y > p11.y))) /* bottom edge */ {
         *trig1P = maketriangle(r11, r12, p13);
         *trig2P = maketriangle(r21, r22, p23);
     } else if (((n >= 2) && (r11.y < p11.y)
                 && (p12.y < p11.y)) /* top edge */
-               || 
+               ||
                ((n >= 2) && (r11.y > p11.y)
                 && (p12.y > p11.y))) /* bottom edge */ {
         *trig1P = maketriangle(r11, r12, p12);
@@ -505,7 +506,7 @@ edgeTriangle(triangle * const trig1P,
              point      const tr2,
              point      const bl2,
              point      const br2) {
-             
+
     if ((p11.x < p12.x) && (p11.y < p12.y)) {
         /* up/left to down/right */
         *trig1P = maketriangle(tr1, p12, p11);
@@ -613,12 +614,16 @@ quadCorner(point           const p0,
 
     /* p0-p1 and p2-p3 are the diagonals */
 
+    triangle tri;
+
     if (fabs(p0.x - p1.x) + fabs(p0.y - p1.y) >=
         fabs(p2.x - p3.x) + fabs(p2.y - p3.y)) {
-        quadCornerSized(p0, p1, p2, p3, mid, quadP, triP);
+        quadCornerSized(p0, p1, p2, p3, mid, quadP, &tri);
     } else {
-        quadCornerSized(p2, p3, p0, p1, mid, quadP, triP);
+        quadCornerSized(p2, p3, p0, p1, mid, quadP, &tri);
     }
+    if (triP)
+        *triP = tri;
 }
 
 
@@ -633,7 +638,7 @@ frameDrawproc (tuple **     const tuples,
                sample       const maxval,
                pamd_point   const p,
                const void * const clientdata) {
-    
+
     int yy;
 
     for (yy = p.y - 1; yy <= p.y + 1; ++yy) {
@@ -688,14 +693,14 @@ clippedPoint(const struct pam * const pamP,
         clippedX = pamP->width - 2;
     else
         clippedX = roundedX;
-        
+
     if (roundedY <= 0)
         clippedY = 1;
     else if (roundedY > pamP->height - 1)
         clippedY = pamP->height - 2;
     else
         clippedY = roundedY;
-        
+
     return pamd_makePoint(clippedX, clippedY);
 }
 
@@ -720,8 +725,10 @@ static void drawClippedTriangle(const struct pam * const pamP,
 
 
 static void
-prepTrig(int const wd,
-         int const ht) {
+prepTrig(int          const wd,
+         int          const ht,
+         bool         const randomseedSpec,
+         unsigned int const randomseed) {
 
 /* create triangles using control points */
 
@@ -729,18 +736,21 @@ prepTrig(int const wd,
     point rtl2, rtr2, rbl2, rbr2;
     point c1p1, c1p2, c1p3, c1p4;
     point c2p1, c2p2, c2p3, c2p4;
-    line l1, l2;
     point p0;
+    struct pm_randSt randSt;
+
+    pm_randinit(&randSt);
+    pm_srand2(&randSt, randomseedSpec, randomseed);
 
-    rtl1 = makepoint(0.0 + tiny(),               0.0 + tiny());
-    rtr1 = makepoint((double) wd - 1.0 + tiny(), 0.0 + tiny());
-    rbl1 = makepoint(0.0 + tiny(),               (double) ht - 1.0 + tiny());
-    rbr1 = makepoint((double) wd - 1.0 + tiny(), (double) ht - 1.0 + tiny());
+    rtl1 = makepoint(0.0 + tiny(&randSt),               0.0 + tiny(&randSt));
+    rtr1 = makepoint((double) wd - 1.0 + tiny(&randSt), 0.0 + tiny(&randSt));
+    rbl1 = makepoint(0.0 + tiny(&randSt),               (double) ht - 1.0 + tiny(&randSt));
+    rbr1 = makepoint((double) wd - 1.0 + tiny(&randSt), (double) ht - 1.0 + tiny(&randSt));
 
-    rtl2 = makepoint(0.0 + tiny(),               0.0 + tiny());
-    rtr2 = makepoint((double) wd - 1.0 + tiny(), 0.0 + tiny());
-    rbl2 = makepoint(0.0 + tiny(),               (double) ht - 1.0 + tiny());
-    rbr2 = makepoint((double) wd - 1.0 + tiny(), (double) ht - 1.0 + tiny());
+    rtl2 = makepoint(0.0 + tiny(&randSt),               0.0 + tiny(&randSt));
+    rtr2 = makepoint((double) wd - 1.0 + tiny(&randSt), 0.0 + tiny(&randSt));
+    rbl2 = makepoint(0.0 + tiny(&randSt),               (double) ht - 1.0 + tiny(&randSt));
+    rbr2 = makepoint((double) wd - 1.0 + tiny(&randSt), (double) ht - 1.0 + tiny(&randSt));
 
     if (nCP == 1) {
         c1p1 = oldCP[0];
@@ -749,19 +759,19 @@ prepTrig(int const wd,
         /* connect control point to all corners to get 4 triangles */
         /* left side triangle */
         sideTriangle(nCP,
-                     &tri1s[0], c1p1, p0, p0, p0, rbl1, rtl1, 
+                     &tri1s[0], c1p1, p0, p0, p0, rbl1, rtl1,
                      &tri2s[0], c2p1, p0, p0, p0, rbl2, rtl2);
         /* top side triangle */
         sideTriangle(nCP,
-                     &tri1s[1], c1p1, p0, p0, p0, rtl1, rtr1, 
+                     &tri1s[1], c1p1, p0, p0, p0, rtl1, rtr1,
                      &tri2s[1], c2p1, p0, p0, p0, rtl2, rtr2);
         /* right side triangle */
         sideTriangle(nCP,
-                     &tri1s[2], c1p1, p0, p0, p0, rtr1, rbr1, 
+                     &tri1s[2], c1p1, p0, p0, p0, rtr1, rbr1,
                      &tri2s[2], c2p1, p0, p0, p0, rtr2, rbr2);
         /* bottom side triangle */
         sideTriangle(nCP,
-                     &tri1s[3], c1p1, p0, p0, p0, rbr1, rbl1, 
+                     &tri1s[3], c1p1, p0, p0, p0, rbr1, rbl1,
                      &tri2s[3], c2p1, p0, p0, p0, rbr2, rbl2);
 
         nTri = 4;
@@ -772,25 +782,25 @@ prepTrig(int const wd,
         c2p2 = newCP[1];
 
         /* check for hor/ver edges */
-        angle (&c1p1, &c1p2);
-        angle (&c2p1, &c2p2);
+        angle (&c1p1, &c1p2, &randSt);
+        angle (&c2p1, &c2p2, &randSt);
 
         /* connect two control points to corners to get 6 triangles */
         /* left side */
         sideTriangle(nCP,
-                     &tri1s[0], c1p1, c1p2, p0, p0, rbl1, rtl1, 
+                     &tri1s[0], c1p1, c1p2, p0, p0, rbl1, rtl1,
                      &tri2s[0], c2p1, c2p2, p0, p0, rbl2, rtl2);
         /* top side */
-        sideTriangle(nCP, 
-                     &tri1s[1], c1p1, c1p2, p0, p0, rtl1, rtr1, 
+        sideTriangle(nCP,
+                     &tri1s[1], c1p1, c1p2, p0, p0, rtl1, rtr1,
                      &tri2s[1], c2p1, c2p2, p0, p0, rtl2, rtr2);
         /* right side */
-        sideTriangle(nCP, 
-                     &tri1s[2], c1p1, c1p2, p0, p0, rtr1, rbr1, 
+        sideTriangle(nCP,
+                     &tri1s[2], c1p1, c1p2, p0, p0, rtr1, rbr1,
                      &tri2s[2], c2p1, c2p2, p0, p0, rtr2, rbr2);
         /* bottom side */
-        sideTriangle(nCP, 
-                     &tri1s[3], c1p1, c1p2, p0, p0, rbr1, rbl1, 
+        sideTriangle(nCP,
+                     &tri1s[3], c1p1, c1p2, p0, p0, rbr1, rbl1,
                      &tri2s[3], c2p1, c2p2, p0, p0, rbr2, rbl2);
 
         /* edge to corner triangles */
@@ -803,7 +813,7 @@ prepTrig(int const wd,
         c1p1 = oldCP[0];
         c1p2 = oldCP[1];
         c1p3 = oldCP[2];
-         
+
         c2p1 = newCP[0];
         c2p2 = newCP[1];
         c2p3 = newCP[2];
@@ -811,13 +821,13 @@ prepTrig(int const wd,
         /* Move vertices slightly if necessary to make sure no edge is
            horizontal or vertical.
         */
-        angle(&c1p1, &c1p2);
-        angle(&c1p2, &c1p3);
-        angle(&c1p3, &c1p1);
+        angle(&c1p1, &c1p2, &randSt);
+        angle(&c1p2, &c1p3, &randSt);
+        angle(&c1p3, &c1p1, &randSt);
 
-        angle(&c2p1, &c2p2);
-        angle(&c2p2, &c2p3);
-        angle(&c2p3, &c2p1);
+        angle(&c2p1, &c2p2, &randSt);
+        angle(&c2p2, &c2p3, &randSt);
+        angle(&c2p3, &c2p1, &randSt);
 
         if (windtriangle(&tri1s[0], c1p1, c1p2, c1p3)) {
             tri2s[0] = maketriangle(c2p1, c2p2, c2p3);
@@ -828,7 +838,7 @@ prepTrig(int const wd,
         c1p1 = tri1s[0].p1;
         c1p2 = tri1s[0].p2;
         c1p3 = tri1s[0].p3;
-         
+
         c2p1 = tri2s[0].p1;
         c2p2 = tri2s[0].p2;
         c2p3 = tri2s[0].p3;
@@ -836,19 +846,19 @@ prepTrig(int const wd,
         /* point to side triangles */
         /* left side */
         sideTriangle(nCP,
-                     &tri1s[1], c1p1, c1p2, c1p3, p0, rbl1, rtl1, 
+                     &tri1s[1], c1p1, c1p2, c1p3, p0, rbl1, rtl1,
                      &tri2s[1], c2p1, c2p2, c2p3, p0, rbl2, rtl2);
         /* top side */
-        sideTriangle(nCP, 
-                     &tri1s[2], c1p1, c1p2, c1p3, p0, rtl1, rtr1, 
+        sideTriangle(nCP,
+                     &tri1s[2], c1p1, c1p2, c1p3, p0, rtl1, rtr1,
                      &tri2s[2], c2p1, c2p2, c2p3, p0, rtl2, rtr2);
         /* right side */
-        sideTriangle(nCP, 
-                     &tri1s[3], c1p1, c1p2, c1p3, p0, rtr1, rbr1, 
+        sideTriangle(nCP,
+                     &tri1s[3], c1p1, c1p2, c1p3, p0, rtr1, rbr1,
                      &tri2s[3], c2p1, c2p2, c2p3, p0, rtr2, rbr2);
         /* bottom side */
-        sideTriangle(nCP, 
-                     &tri1s[4], c1p1, c1p2, c1p3, p0, rbr1, rbl1, 
+        sideTriangle(nCP,
+                     &tri1s[4], c1p1, c1p2, c1p3, p0, rbr1, rbl1,
                      &tri2s[4], c2p1, c2p2, c2p3, p0, rbr2, rbl2);
 
         /* edge to corner triangles */
@@ -864,26 +874,26 @@ prepTrig(int const wd,
         c1p2 = oldCP[1];
         c1p3 = oldCP[2];
         c1p4 = oldCP[3];
-         
+
         c2p1 = newCP[0];
         c2p2 = newCP[1];
         c2p3 = newCP[2];
         c2p4 = newCP[3];
 
         /* check for hor/ver edges */
-        angle (&c1p1, &c1p2);
-        angle (&c1p2, &c1p3);
-        angle (&c1p3, &c1p4);
-        angle (&c1p4, &c1p1);
-        angle (&c1p1, &c1p3);
-        angle (&c1p2, &c1p4);
-
-        angle (&c2p1, &c2p2);
-        angle (&c2p2, &c2p3);
-        angle (&c2p3, &c2p4);
-        angle (&c2p4, &c2p1);
-        angle (&c2p1, &c2p3);
-        angle (&c2p2, &c2p4);
+        angle (&c1p1, &c1p2, &randSt);
+        angle (&c1p2, &c1p3, &randSt);
+        angle (&c1p3, &c1p4, &randSt);
+        angle (&c1p4, &c1p1, &randSt);
+        angle (&c1p1, &c1p3, &randSt);
+        angle (&c1p2, &c1p4, &randSt);
+
+        angle (&c2p1, &c2p2, &randSt);
+        angle (&c2p2, &c2p3, &randSt);
+        angle (&c2p3, &c2p4, &randSt);
+        angle (&c2p4, &c2p1, &randSt);
+        angle (&c2p1, &c2p3, &randSt);
+        angle (&c2p2, &c2p4, &randSt);
 
         /*-------------------------------------------------------------------*/
         /*        -1-      -2-        -3-      -4-        -5-      -6-       */
@@ -892,47 +902,58 @@ prepTrig(int const wd,
         /*       3   4    2   4      4   3    2   3      4   2    3   2      */
         /*-------------------------------------------------------------------*/
 
-        /* center two triangles */
-        l1 = makeline(c1p1, c1p4);
-        l2 = makeline(c1p2, c1p3);
-        if (intersect(&l1, &l2, &p0)) {
-            if (windtriangle(&tri1s[0], c1p1, c1p2, c1p3)) {
-                tri1s[1] = maketriangle(c1p4, c1p3, c1p2);
-                tri2s[0] = maketriangle(c2p1, c2p2, c2p3);
-                tri2s[1] = maketriangle(c2p4, c2p3, c2p2);
-            } else {
-                tri1s[1] = maketriangle(c1p4, c1p2, c1p3);
-                tri2s[0] = maketriangle(c2p1, c2p3, c2p2);
-                tri2s[1] = maketriangle(c2p4, c2p2, c2p3);
+        {
+            /* center two triangles */
+            line const l1 = makeline(c1p1, c1p4);
+            line const l2 = makeline(c1p2, c1p3);
+            bool theyIntersect;
+            findIntersection(&l1, &l2, &theyIntersect, &p0);
+            if (theyIntersect) {
+                if (windtriangle(&tri1s[0], c1p1, c1p2, c1p3)) {
+                    tri1s[1] = maketriangle(c1p4, c1p3, c1p2);
+                    tri2s[0] = maketriangle(c2p1, c2p2, c2p3);
+                    tri2s[1] = maketriangle(c2p4, c2p3, c2p2);
+                } else {
+                    tri1s[1] = maketriangle(c1p4, c1p2, c1p3);
+                    tri2s[0] = maketriangle(c2p1, c2p3, c2p2);
+                    tri2s[1] = maketriangle(c2p4, c2p2, c2p3);
+                }
             }
         }
-        l1 = makeline(c1p1, c1p3);
-        l2 = makeline(c1p2, c1p4);
-        if (intersect(&l1, &l2, &p0)) {
-            if (windtriangle(&tri1s[0], c1p1, c1p2, c1p4)) {
-                tri1s[1] = maketriangle(c1p3, c1p4, c1p2);
-                tri2s[0] = maketriangle(c2p1, c2p2, c2p4);
-                tri2s[1] = maketriangle(c2p3, c2p4, c2p2);
-            } else {
-                tri1s[1] = maketriangle(c1p3, c1p2, c1p4);
-                tri2s[0] = maketriangle(c2p1, c2p4, c2p2);
-                tri2s[1] = maketriangle(c2p3, c2p2, c2p4);
+        {
+            line const l1 = makeline(c1p1, c1p3);
+            line const l2 = makeline(c1p2, c1p4);
+            bool theyIntersect;
+            findIntersection(&l1, &l2, &theyIntersect, &p0);
+            if (theyIntersect) {
+                if (windtriangle(&tri1s[0], c1p1, c1p2, c1p4)) {
+                    tri1s[1] = maketriangle(c1p3, c1p4, c1p2);
+                    tri2s[0] = maketriangle(c2p1, c2p2, c2p4);
+                    tri2s[1] = maketriangle(c2p3, c2p4, c2p2);
+                } else {
+                    tri1s[1] = maketriangle(c1p3, c1p2, c1p4);
+                    tri2s[0] = maketriangle(c2p1, c2p4, c2p2);
+                    tri2s[1] = maketriangle(c2p3, c2p2, c2p4);
+                }
             }
         }
-        l1 = makeline(c1p1, c1p2);
-        l2 = makeline(c1p3, c1p4);
-        if (intersect(&l1, &l2, &p0)) {
-            if (windtriangle(&tri1s[0], c1p1, c1p3, c1p4)) {
-                tri1s[1] = maketriangle(c1p2, c1p4, c1p3);
-                tri2s[0] = maketriangle(c2p1, c2p3, c2p4);
-                tri2s[1] = maketriangle(c2p2, c2p4, c2p3);
-            } else {
-                tri1s[1] = maketriangle(c1p2, c1p3, c1p4);
-                tri2s[0] = maketriangle(c2p1, c2p4, c2p3);
-                tri2s[1] = maketriangle(c2p2, c2p3, c2p4);
+        {
+            line const l1 = makeline(c1p1, c1p2);
+            line const l2 = makeline(c1p3, c1p4);
+            bool theyIntersect;
+            findIntersection(&l1, &l2, &theyIntersect, &p0);
+            if (theyIntersect) {
+                if (windtriangle(&tri1s[0], c1p1, c1p3, c1p4)) {
+                    tri1s[1] = maketriangle(c1p2, c1p4, c1p3);
+                    tri2s[0] = maketriangle(c2p1, c2p3, c2p4);
+                    tri2s[1] = maketriangle(c2p2, c2p4, c2p3);
+                } else {
+                    tri1s[1] = maketriangle(c1p2, c1p3, c1p4);
+                    tri2s[0] = maketriangle(c2p1, c2p4, c2p3);
+                    tri2s[1] = maketriangle(c2p2, c2p3, c2p4);
+                }
             }
         }
-
         /* control points in correct orientation */
         c1p1 = tri1s[0].p1;
         c1p2 = tri1s[0].p2;
@@ -945,20 +966,20 @@ prepTrig(int const wd,
 
         /* triangle from triangle point to side of image */
         /* left side triangle */
-        sideTriangle(nCP, 
-                     &tri1s[2], c1p1, c1p2, c1p3, c1p4, rbl1, rtl1, 
+        sideTriangle(nCP,
+                     &tri1s[2], c1p1, c1p2, c1p3, c1p4, rbl1, rtl1,
                      &tri2s[2], c2p1, c2p2, c2p3, c2p4, rbl2, rtl2);
         /* top side triangle */
-        sideTriangle(nCP, 
-                     &tri1s[3], c1p1, c1p2, c1p3, c1p4, rtl1, rtr1, 
+        sideTriangle(nCP,
+                     &tri1s[3], c1p1, c1p2, c1p3, c1p4, rtl1, rtr1,
                      &tri2s[3], c2p1, c2p2, c2p3, c2p4, rtl2, rtr2);
         /* right side triangle */
-        sideTriangle(nCP, 
-                     &tri1s[4], c1p1, c1p2, c1p3, c1p4, rtr1, rbr1, 
+        sideTriangle(nCP,
+                     &tri1s[4], c1p1, c1p2, c1p3, c1p4, rtr1, rbr1,
                      &tri2s[4], c2p1, c2p2, c2p3, c2p4, rtr2, rbr2);
         /* bottom side triangle */
-        sideTriangle(nCP, 
-                     &tri1s[5], c1p1, c1p2, c1p3, c1p4, rbr1, rbl1, 
+        sideTriangle(nCP,
+                     &tri1s[5], c1p1, c1p2, c1p3, c1p4, rbr1, rbl1,
                      &tri2s[5], c2p1, c2p2, c2p3, c2p4, rbr2, rbl2);
 
         /*-------------------------------------------------------------------*/
@@ -979,6 +1000,8 @@ prepTrig(int const wd,
                      &tri2s[9], c2p3, c2p1, rtl2, rtr2, rbl2, rbr2);
         nTri = 10;
     }
+
+    pm_randterm(&randSt);
 }
 
 
@@ -988,11 +1011,6 @@ prepQuad(void) {
 
 /* order quad control points */
 
-    double d01, d12, d20;
-    line l1, l2;
-    point mid;
-    triangle tri;
-
     if (nCP == 1) {
         /* create a rectangle from top-left corner of image and control
            point
@@ -1014,7 +1032,7 @@ prepQuad(void) {
             /* bottom-right and top-left */
             quad1 = quadRect(oldCP[1].x, oldCP[0].x, oldCP[1].y, oldCP[0].y);
         }
-        
+
         if ((newCP[0].x < newCP[1].x) && (newCP[0].y < newCP[1].y)) {
             /* top-left and bottom-right */
             quad2 = quadRect(newCP[0].x, newCP[1].x, newCP[0].y, newCP[1].y);
@@ -1034,10 +1052,10 @@ prepQuad(void) {
             /* diagonal of the parallelogram is the two control points
                furthest apart
             */
-            
-            d01 = distance(newCP[0], newCP[1]);
-            d12 = distance(newCP[1], newCP[2]);
-            d20 = distance(newCP[2], newCP[0]);
+
+            double const d01 = distance(newCP[0], newCP[1]);
+            double const d12 = distance(newCP[1], newCP[2]);
+            double const d20 = distance(newCP[2], newCP[0]);
 
             if ((d01 > d12) && (d01 > d20)) {
                 oldCP[3].x = oldCP[0].x + oldCP[1].x - oldCP[2].x;
@@ -1067,51 +1085,72 @@ prepQuad(void) {
 
         /* nCP = 3 or 4 */
 
-        /* find the intersection of the diagonals */
-        l1 = makeline(oldCP[0], oldCP[1]);
-        l2 = makeline(oldCP[2], oldCP[3]);
-        if (intersect(&l1, &l2, &mid)) {
-            quadCorner(oldCP[0], oldCP[1], oldCP[2], oldCP[3],
-                       mid, &quad1, &tri);
-        } else {
-            l1 = makeline(oldCP[0], oldCP[2]);
-            l2 = makeline(oldCP[1], oldCP[3]);
-            if (intersect(&l1, &l2, &mid))
-                quadCorner(oldCP[0], oldCP[2], oldCP[1], oldCP[3],
-                           mid, &quad1, &tri);
+        {
+            /* find the intersection of the diagonals */
+            line const l1 = makeline(oldCP[0], oldCP[1]);
+            line const l2 = makeline(oldCP[2], oldCP[3]);
+            bool theyIntersect;
+            point mid;
+            findIntersection(&l1, &l2, &theyIntersect, &mid);
+            if (theyIntersect)
+                quadCorner(oldCP[0], oldCP[1], oldCP[2], oldCP[3],
+                           mid, &quad1, NULL);
             else {
-                l1 = makeline(oldCP[0], oldCP[3]);
-                l2 = makeline(oldCP[1], oldCP[2]);
-                if (intersect(&l1, &l2, &mid))
-                    quadCorner(oldCP[0], oldCP[3],
-                               oldCP[1], oldCP[2], mid, &quad1, &tri);
-                else
-                    pm_error("The four old control points don't seem "
-                             "to be corners.");
+                line const l1 = makeline(oldCP[0], oldCP[2]);
+                line const l2 = makeline(oldCP[1], oldCP[3]);
+                bool theyIntersect;
+                point mid;
+                findIntersection(&l1, &l2, &theyIntersect, &mid);
+                if (theyIntersect)
+                    quadCorner(oldCP[0], oldCP[2], oldCP[1], oldCP[3],
+                               mid, &quad1, NULL);
+                else {
+                    line const l1 = makeline(oldCP[0], oldCP[3]);
+                    line const l2 = makeline(oldCP[1], oldCP[2]);
+                    bool theyIntersect;
+                    point mid;
+                    findIntersection(&l1, &l2, &theyIntersect, &mid);
+                    if (theyIntersect)
+                        quadCorner(oldCP[0], oldCP[3],
+                                   oldCP[1], oldCP[2], mid, &quad1, NULL);
+                    else
+                        pm_error("The four old control points don't seem "
+                                 "to be corners.");
+                }
             }
         }
-
-        /* repeat for the "to-be" control points */
-        l1 = makeline(newCP[0], newCP[1]);
-        l2 = makeline(newCP[2], newCP[3]);
-        if (intersect(&l1, &l2, &mid))
-            quadCorner(newCP[0], newCP[1], newCP[2], newCP[3],
-                       mid, &quad2, &tri);
-        else {
-            l1 = makeline(newCP[0], newCP[2]);
-            l2 = makeline(newCP[1], newCP[3]);
-            if (intersect(&l1, &l2, &mid))
-                quadCorner(newCP[0], newCP[2], newCP[1], newCP[3],
-                           mid, &quad2, &tri);
+        {
+            /* repeat for the "to-be" control points */
+            line const l1 = makeline(newCP[0], newCP[1]);
+            line const l2 = makeline(newCP[2], newCP[3]);
+            bool theyIntersect;
+            point mid;
+            findIntersection(&l1, &l2, &theyIntersect, &mid);
+            if (theyIntersect)
+                quadCorner(newCP[0], newCP[1], newCP[2], newCP[3],
+                           mid, &quad2, NULL);
             else {
-                l1 = makeline(newCP[0], newCP[3]);
-                l2 = makeline(newCP[1], newCP[2]);
-                if (intersect(&l1, &l2, &mid))
-                    quadCorner(newCP[0], newCP[3],
-                               newCP[1], newCP[2], mid, &quad2, &tri);
-                else
-                    pm_error("The four new control points don't seem "
-                             "to be corners.");
+                line const l1 = makeline(newCP[0], newCP[2]);
+                line const l2 = makeline(newCP[1], newCP[3]);
+                bool theyIntersect;
+                point mid;
+                findIntersection(&l1, &l2, &theyIntersect, &mid);
+                if (theyIntersect)
+                    quadCorner(newCP[0], newCP[2], newCP[1], newCP[3],
+                               mid, &quad2, NULL);
+                else {
+                    line const l1 = makeline(newCP[0], newCP[3]);
+                    line const l2 = makeline(newCP[1], newCP[2]);
+                    bool theyIntersect;
+                    point mid;
+                    findIntersection(&l1, &l2, &theyIntersect, &mid);
+                    if (theyIntersect)
+                        quadCorner(newCP[0], newCP[3],
+                                   newCP[1], newCP[2], mid, &quad2, NULL);
+                    else
+                        pm_error("The four new control points don't seem "
+                                 "to be corners.");
+                }
             }
         }
     }
@@ -1127,14 +1166,11 @@ warpTrig(point   const p2,
 
     point e1p1, e1p2, e1p3;
     point e2p1, e2p2, e2p3;
-    line lp, le;
-    line l1, l2, l3;
-    double d1, d2, d3;
-    int i;
+    unsigned int i;
 
     /* find in which triangle p2 lies */
-    for (i = 0; i < nTri; i++) {
-        if (insidetri (&tri2s[i], p2))
+    for (i = 0; i < nTri; ++i) {
+        if (insidetri(&tri2s[i], p2))
             break;
     }
 
@@ -1142,28 +1178,36 @@ warpTrig(point   const p2,
         *p1P = makepoint(0.0, 0.0);
     else {
         /* where in triangle is point */
-        d1 = fabs (p2.x - tri2s[i].p1.x) + fabs (p2.y - tri2s[i].p1.y);
-        d2 = fabs (p2.x - tri2s[i].p2.x) + fabs (p2.y - tri2s[i].p2.y);
-        d3 = fabs (p2.x - tri2s[i].p3.x) + fabs (p2.y - tri2s[i].p3.y);
-
-        /* line through p1 and p intersecting with edge p2-p3 */
-        lp = makeline(tri2s[i].p1, p2);
-        le = makeline(tri2s[i].p2, tri2s[i].p3);
-        intersect (&lp, &le, &e2p1);
-
-        /* line through p2 and p intersecting with edge p3-p1 */
-        lp = makeline(tri2s[i].p2, p2);
-        le = makeline(tri2s[i].p3, tri2s[i].p1);
-        intersect (&lp, &le, &e2p2);
+        double const d1 =
+            fabs (p2.x - tri2s[i].p1.x) + fabs (p2.y - tri2s[i].p1.y);
+        double const d2 =
+            fabs (p2.x - tri2s[i].p2.x) + fabs (p2.y - tri2s[i].p2.y);
+        double const d3 =
+            fabs (p2.x - tri2s[i].p3.x) + fabs (p2.y - tri2s[i].p3.y);
+
+        {
+            /* line through p1 and p intersecting with edge p2-p3 */
+            line const lp = makeline(tri2s[i].p1, p2);
+            line const le = makeline(tri2s[i].p2, tri2s[i].p3);
+            findIntersection(&lp, &le, NULL, &e2p1);
+        }
 
-        /* line through p3 and p intersecting with edge p1-p2 */
-        lp = makeline(tri2s[i].p3, p2);
-        le = makeline(tri2s[i].p1, tri2s[i].p2);
-        intersect (&lp, &le, &e2p3);
+        {
+            /* line through p2 and p intersecting with edge p3-p1 */
+            line const lp = makeline(tri2s[i].p2, p2);
+            line const le = makeline(tri2s[i].p3, tri2s[i].p1);
+            findIntersection(&lp, &le, NULL, &e2p2);
+        }
 
+        {
+            /* line through p3 and p intersecting with edge p1-p2 */
+            line const lp = makeline(tri2s[i].p3, p2);
+            line const le = makeline(tri2s[i].p1, tri2s[i].p2);
+            findIntersection(&lp, &le, NULL, &e2p3);
+        }
         /* map target control points to source control points */
         e1p1.x = tri1s[i].p2.x
-            + (e2p1.x - tri2s[i].p2.x)/(tri2s[i].p3.x - tri2s[i].p2.x) 
+            + (e2p1.x - tri2s[i].p2.x)/(tri2s[i].p3.x - tri2s[i].p2.x)
             * (tri1s[i].p3.x - tri1s[i].p2.x);
         e1p1.y = tri1s[i].p2.y
             + (e2p1.y - tri2s[i].p2.y)/(tri2s[i].p3.y - tri2s[i].p2.y)
@@ -1181,17 +1225,19 @@ warpTrig(point   const p2,
             + (e2p3.y - tri2s[i].p1.y)/(tri2s[i].p2.y - tri2s[i].p1.y)
             * (tri1s[i].p2.y - tri1s[i].p1.y);
 
-        /* intersect grid lines in source */
-        l1 = makeline(tri1s[i].p1, e1p1);
-        l2 = makeline(tri1s[i].p2, e1p2);
-        l3 = makeline(tri1s[i].p3, e1p3);
-
-        if ((d1 < d2) && (d1 < d3))
-            intersect (&l2, &l3, p1P);
-        else if (d2 < d3)
-            intersect (&l1, &l3, p1P);
-        else
-            intersect (&l1, &l2, p1P);
+        {
+            /* intersect grid lines in source */
+            line const l1 = makeline(tri1s[i].p1, e1p1);
+            line const l2 = makeline(tri1s[i].p2, e1p2);
+            line const l3 = makeline(tri1s[i].p3, e1p3);
+
+            if ((d1 < d2) && (d1 < d3))
+                findIntersection(&l2, &l3, NULL, p1P);
+            else if (d2 < d3)
+                findIntersection(&l1, &l3, NULL, p1P);
+            else
+                findIntersection(&l1, &l2, NULL, p1P);
+        }
     }
 }
 
@@ -1208,37 +1254,38 @@ warpQuad(point   const p2,
     point c2tl, c2tr, c2bl, c2br;
     point e1t, e1b, e1l, e1r;
     point e2t, e2b, e2l, e2r;
-    line l2t, l2b, l2l, l2r;
-    line lh, lv;
 
     c1tl = quad1.tl;
     c1tr = quad1.tr;
     c1bl = quad1.bl;
     c1br = quad1.br;
-       
+
     c2tl = quad2.tl;
     c2tr = quad2.tr;
     c2bl = quad2.bl;
     c2br = quad2.br;
 
-    l2t = makeline(c2tl, c2tr);
-    l2b = makeline(c2bl, c2br);
-    l2l = makeline(c2tl, c2bl);
-    l2r = makeline(c2tr, c2br);
-
-    /* find intersections of lines through control points */
-    intersect (&l2t, &l2b, &h2);
-    intersect (&l2l, &l2r, &v2);
-
-    /* find intersections of axes through P with control point box */
-    lv = makeline(p2, v2);
-    intersect (&l2t, &lv, &e2t);
-    intersect (&l2b, &lv, &e2b);
-
-    lh = makeline(p2, h2);
-    intersect (&l2l, &lh, &e2l);
-    intersect (&l2r, &lh, &e2r);
-
+    {
+        line const l2t = makeline(c2tl, c2tr);
+        line const l2b = makeline(c2bl, c2br);
+        line const l2l = makeline(c2tl, c2bl);
+        line const l2r = makeline(c2tr, c2br);
+
+        /* find intersections of lines through control points */
+        findIntersection(&l2t, &l2b, NULL, &h2);
+        findIntersection(&l2l, &l2r, NULL, &v2);
+
+        {
+            /* find intersections of axes through P with control point box */
+            line const lv = makeline(p2, v2);
+            line const lh = makeline(p2, h2);
+
+            findIntersection(&l2t, &lv, NULL, &e2t);
+            findIntersection(&l2b, &lv, NULL, &e2b);
+            findIntersection(&l2l, &lh, NULL, &e2l);
+            findIntersection(&l2r, &lh, NULL, &e2r);
+        }
+    }
     /* map target control points to source control points */
     e1t.x = c1tl.x + (e2t.x - c2tl.x)/(c2tr.x - c2tl.x) * (c1tr.x - c1tl.x);
     if (c1tl.y == c1tr.y)
@@ -1268,16 +1315,18 @@ warpQuad(point   const p2,
             = c1tr.x + (e2r.y - c2tr.y)/(c2br.y - c2tr.y) * (c1br.x - c1tr.x);
     e1r.y = c1tr.y + (e2r.y - c2tr.y)/(c2br.y - c2tr.y) * (c1br.y - c1tr.y);
 
-    /* intersect grid lines in source */
-    lv = makeline(e1t, e1b);
-    lh = makeline(e1l, e1r);
-    intersect (&lh, &lv, p1P);
+    {
+        /* intersect grid lines in source */
+        line const lv = makeline(e1t, e1b);
+        line const lh = makeline(e1l, e1r);
+        findIntersection(&lh, &lv, NULL, p1P);
+    }
 }
 
 
 
 static void
-setGlobalCP(struct cmdlineInfo const cmdline) {
+setGlobalCP(struct CmdlineInfo const cmdline) {
 
     unsigned int i;
 
@@ -1364,22 +1413,22 @@ pix(tuple **     const tuples,
         pix = 0.0;
         if (((int) floor(p.x) >= 0) && ((int) floor(p.x) < width) &&
             ((int) floor(p.y) >= 0) && ((int) floor(p.y) < height)) {
-            pix += (1.0 - rx) * (1.0 - ry) 
+            pix += (1.0 - rx) * (1.0 - ry)
                 * tuples[(int) floor(p.y)][(int) floor(p.x)][plane];
         }
         if (((int) floor(p.x) + 1 >= 0) && ((int) floor(p.x) + 1 < width) &&
             ((int) floor(p.y) >= 0) && ((int) floor(p.y) < height)) {
-            pix += rx * (1.0 - ry) 
+            pix += rx * (1.0 - ry)
                 * tuples[(int) floor(p.y)][(int) floor(p.x) + 1][plane];
         }
         if (((int) floor(p.x) >= 0) && ((int) floor(p.x) < width) &&
             ((int) floor(p.y) + 1 >= 0) && ((int) floor(p.y) + 1 < height)) {
-            pix += (1.0 - rx) * ry 
+            pix += (1.0 - rx) * ry
                 * tuples[(int) floor(p.y) + 1][(int) floor(p.x)][plane];
         }
         if (((int) floor(p.x) + 1 >= 0) && ((int) floor(p.x) + 1 < width) &&
             ((int) floor(p.y) + 1 >= 0) && ((int) floor(p.y) + 1 < height)) {
-            pix += rx * ry 
+            pix += rx * ry
                 * tuples[(int) floor(p.y) + 1][(int) floor(p.x) + 1][plane];
         }
     }
@@ -1392,21 +1441,19 @@ pix(tuple **     const tuples,
 int
 main(int argc, const char ** const argv) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     FILE * ifP;
     struct pam inpam, outpam;
     tuple ** inTuples;
     tuple ** outTuples;
     unsigned int p2y;
-  
+
     pm_proginit(&argc, argv);
 
     parseCmdline(argc, argv, &cmdline);
 
     setGlobalCP(cmdline);
 
-    srand(cmdline.randseedSpec ? cmdline.randseed : pm_randseed());
-
     ifP = pm_openr(cmdline.fileName);
 
     inTuples = pnm_readpam(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
@@ -1421,7 +1468,8 @@ main(int argc, const char ** const argv) {
     makeAllWhite(&outpam, outTuples);
 
     if (cmdline.tri)
-        prepTrig(inpam.width, inpam.height);
+        prepTrig(inpam.width, inpam.height,
+                 cmdline.randomseedSpec, cmdline.randomseed);
     if (cmdline.quad)
         prepQuad();
 
diff --git a/editor/pamshuffle.c b/editor/pamshuffle.c
new file mode 100644
index 00000000..bffb79c5
--- /dev/null
+++ b/editor/pamshuffle.c
@@ -0,0 +1,155 @@
+/*=============================================================================
+                               pamshuffle
+===============================================================================
+  Part of the Netpbm package.
+
+  Relocate pixels in row, randomly, using Fisher-Yates shuffling.
+
+  By Akira F. Urushibata
+
+  Contributed to the public domain by its author.
+=============================================================================*/
+
+#include <assert.h>
+#include "pm_c_util.h"
+#include "pam.h"
+#include "rand.h"
+#include "shhopt.h"
+
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char * inputFileName;
+    unsigned int column;
+    unsigned int randomseedSpec;
+    unsigned int randomseed;
+};
+
+static void
+parseCommandLine(int argc, const char ** const argv,
+                 struct CmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   Note that the file spec array we return is stored in the storage that
+   was passed to us as the argv array.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;
+        /* Instructions to OptParseOptions3 on how to parse our options. */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+
+    MALLOCARRAY(option_def, 100);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = false;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = true;  /* We have no parms that are negative numbers */
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0,   "column",     OPT_FLAG,   NULL,
+                               &cmdlineP->column,                    0);
+    OPTENT3(0,   "randomseed", OPT_UINT,   &cmdlineP->randomseed,
+                               &cmdlineP->randomseedSpec,            0);
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    free(option_def);
+
+    if (argc-1 > 1)
+        pm_error("Too many arguments (%u). "
+                 "The only possible argument is the input file name.", argc-1);
+    else if (argc-1 < 1)
+        cmdlineP->inputFileName = "-";
+    else
+        cmdlineP->inputFileName = argv[1];
+
+}
+
+
+
+static void
+shuffleRow(tuple *            const tuplerow,
+           unsigned int       const cols,
+           struct pm_randSt * const randStP) {
+
+    unsigned int col;
+
+    for (col = 0; col + 1 < cols; ++col) {
+        tuple        const temp    = tuplerow[col];
+        unsigned int const randcol = col + pm_rand(randStP) % (cols - col);
+
+        assert(randcol >= col );
+        assert(randcol < cols);
+
+        /* swap */
+        tuplerow[col]     = tuplerow[randcol];
+        tuplerow[randcol] = temp;
+    }
+}
+
+
+
+int
+main(int argc, const char * argv[]) {
+
+    FILE * ifP;
+    int    eof;     /* no more images in input stream */
+
+    struct CmdlineInfo cmdline;
+    struct pam inpam;   /* Input PAM image */
+    struct pam outpam;  /* Output PAM image */
+    struct pm_randSt randSt;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    pm_randinit(&randSt);
+    pm_srand2(&randSt, cmdline.randomseedSpec, cmdline.randomseed);
+
+    for (eof = FALSE; !eof;) {
+        tuple * inrow;   /* Input row buffer */
+        tuple * outrow;  /* Pointers into the input row buffer to reorder it */
+        unsigned int row, col;
+
+        pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
+
+        outpam = inpam;
+        outpam.file = stdout;
+
+        pnm_writepaminit(&outpam);
+
+        inrow = pnm_allocpamrow(&inpam);
+
+        MALLOCARRAY(outrow, inpam.width);
+
+        if (!outrow)
+            pm_error("Unable to allocate memory for %u-column output buffer",
+                     inpam.width);
+
+        for (col = 0; col < inpam.width; ++col)
+            outrow[col] = inrow[col];
+
+        for (row = 0; row < inpam.height; ++row) {
+            pnm_readpamrow(&inpam, inrow);
+
+            if (cmdline.column && row > 0) {
+                /* Use the same shuffle ('outrow') as the previous row */
+            } else
+                shuffleRow(outrow, inpam.width, &randSt);
+
+            pnm_writepamrow(&outpam, outrow);
+        }
+
+        pnm_freepamrow(inrow);
+        free(outrow);
+        pnm_nextimage(ifP, &eof);
+    }
+
+    pm_randterm(&randSt);
+
+    return 0;
+}
diff --git a/editor/pamsistoaglyph.c b/editor/pamsistoaglyph.c
index f9e25518..cac1f99f 100644
--- a/editor/pamsistoaglyph.c
+++ b/editor/pamsistoaglyph.c
@@ -151,7 +151,7 @@ bestEyeSepWeEncountered(int const bestSeparation[3],
     for (i = 2; i >= 0; --i) {
         if (bestSeparation[i] != 0)
             return bestSeparation[i];
-    }    
+    }
     return altBestSeparation;
 }
 
@@ -429,3 +429,4 @@ main(int argc, const char *argv[]) {
     return 0;
 }
 
+
diff --git a/editor/pamstretch-gen b/editor/pamstretch-gen
index fec4469c..ee04821a 100755
--- a/editor/pamstretch-gen
+++ b/editor/pamstretch-gen
@@ -24,10 +24,6 @@ while true ; do
         shift
         ;;
         -q|-qu|-qui|-quie|-quiet|--q|--qu|--qui|--quie|--quiet )
-        quietopt="-plain"
-        shift
-        ;;
-        -q|-qu|-qui|-quie|-quiet|--q|--qu|--qui|--quie|--quiet )
         quietopt="-quiet"
         shift
         ;;
@@ -80,7 +76,7 @@ esac
 # in some exceptional cases adjustment is necessary because of
 # "-dropedge".
 
-report=$(pamscale -reportonly $1 $tempfile)
+report=$(pamscale $quietopt -reportonly $1 $tempfile)
 if [ $? -ne 0 ]; then
   echo "pamstretch-gen: pamscale -reportonly $1 (file) failed" 1>&2
   exit 1
diff --git a/editor/pamthreshold.c b/editor/pamthreshold.c
index 8d28bc4a..809d76d9 100644
--- a/editor/pamthreshold.c
+++ b/editor/pamthreshold.c
@@ -73,7 +73,7 @@ initRange(struct range * const rangeP) {
     rangeP->max = 0.0;
 }
 
-          
+
 
 static void
 addToRange(struct range * const rangeP,
@@ -89,7 +89,7 @@ static float
 spread(struct range const range) {
 
     assert(range.max >= range.min);
-    
+
     return range.max - range.min;
 }
 
@@ -120,12 +120,12 @@ parseGeometry(const char *   const wxl,
 
 
 static void
-parseCommandLine(int                 argc, 
+parseCommandLine(int                 argc,
                  char **             argv,
                  struct cmdlineInfo *cmdlineP ) {
 /*----------------------------------------------------------------------------
    Parse program command line described in Unix standard form by argc
-   and argv.  Return the information in the options as *cmdlineP.  
+   and argv.  Return the information in the options as *cmdlineP.
 
    If command line is internally inconsistent (invalid options, etc.),
    issue error message to stderr and abort program.
@@ -145,7 +145,7 @@ parseCommandLine(int                 argc,
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     /* define the options */
-    OPTENT3(0, "simple",    OPT_FLAG,   NULL,               
+    OPTENT3(0, "simple",    OPT_FLAG,   NULL,
             &cmdlineP->simple,      0);
     OPTENT3(0, "local",     OPT_STRING, &localOpt,
             &localSpec,             0);
@@ -155,7 +155,7 @@ parseCommandLine(int                 argc,
             &thresholdSpec,         0);
     OPTENT3(0, "contrast",  OPT_FLOAT,  &cmdlineP->contrast,
             &contrastSpec,          0);
-    OPTENT3(0, "verbose",    OPT_FLAG,   NULL,               
+    OPTENT3(0, "verbose",    OPT_FLAG,   NULL,
             &cmdlineP->verbose,     0);
 
     /* set the defaults */
@@ -216,8 +216,8 @@ parseCommandLine(int                 argc,
         cmdlineP->inputFileName = "-";
     else if (argc-1 == 1)
         cmdlineP->inputFileName = argv[1];
-    else 
-        pm_error("Progam takes at most 1 parameter: the file name.  "
+    else
+        pm_error("Program takes at most 1 parameter: the file name.  "
                  "You specified %d", argc-1);
 }
 
@@ -389,7 +389,7 @@ computeGlobalThreshold(struct pam *         const inpamP,
        of the "k-means clustering algorithm."
 
        The article claims it's proven to converge, by the way.
-       We have an interation limit just as a safety net.
+       We have an iteration limit just as a safety net.
 
        This code originally implemented a rather different algorithm,
        while nonetheless carrying the comment that it implemented the
@@ -524,7 +524,7 @@ thresholdLocalRow(struct pam *       const inpamP,
         getLocalThreshold(inrows, inpamP->width, col, localWidth, windowHeight,
                           cmdline.threshold, minSpread, globalThreshold,
                           &threshold);
-        
+
         thresholdPixel(outpamP, inrow[col], outrow[col], threshold);
     }
 }
@@ -569,12 +569,12 @@ thresholdLocal(struct pam *       const inpamP,
     unsigned int oddLocalWidth;
     unsigned int oddLocalHeight;
     unsigned int i;
-    
+
     /* use a subimage with odd width and height to have a middle pixel */
 
     if (cmdline.width % 2 == 0)
         oddLocalWidth = cmdline.width + 1;
-    else 
+    else
         oddLocalWidth = cmdline.width;
     if (cmdline.height % 2 == 0)
         oddLocalHeight = cmdline.height + 1;
@@ -616,7 +616,7 @@ thresholdLocal(struct pam *       const inpamP,
                           outpamP, outrow);
 
         pnm_writepamrow(outpamP, outrow);
-        
+
         /* read next image line if available and necessary */
         if (row + windowHeight / 2 >= nextRowToRead &&
             nextRowToRead < inpamP->height)
@@ -655,7 +655,7 @@ thresholdIterative(struct pam * const inpamP,
 int
 main(int argc, char **argv) {
 
-    FILE * ifP; 
+    FILE * ifP;
     struct cmdlineInfo cmdline;
     struct pam inpam, outpam;
     int eof;  /* No more images in input stream */
@@ -711,3 +711,6 @@ main(int argc, char **argv) {
 
     return 0;
 }
+
+
+
diff --git a/editor/pamundice.c b/editor/pamundice.c
index dbe0a8df..60360f17 100644
--- a/editor/pamundice.c
+++ b/editor/pamundice.c
@@ -18,30 +18,28 @@
 #include "nstring.h"
 #include "mallocvar.h"
 
-#define MAXFILENAMELEN 80
-    /* Maximum number of characters we accept in filenames */
-
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
     const char * inputFilePattern;
-        /* null-terminated string, max MAXFILENAMELEN-10 characters */
     unsigned int across;
     unsigned int down;
-    unsigned int hoverlap; 
-    unsigned int voverlap; 
+    unsigned int hoverlap;
+    unsigned int voverlap;
+    const char * listfile;
+    unsigned int listfileSpec;
     unsigned int verbose;
 };
 
 
 
 static void
-parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo * const cmdlineP ) {
+parseCommandLine(int argc, const char ** argv,
+                 struct CmdlineInfo * const cmdlineP ) {
 /*----------------------------------------------------------------------------
    parse program command line described in Unix standard form by argc
-   and argv.  Return the information in the options as *cmdlineP.  
+   and argv.  Return the information in the options as *cmdlineP.
 
    If command line is internally inconsistent (invalid options, etc.),
    issue error message to stderr and abort program.
@@ -53,7 +51,7 @@ parseCommandLine(int argc, char ** argv,
         /* Instructions to pm_optParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
-    
+
     unsigned int acrossSpec, downSpec;
     unsigned int hoverlapSpec, voverlapSpec;
     unsigned int option_def_index;
@@ -69,6 +67,8 @@ parseCommandLine(int argc, char ** argv,
             &hoverlapSpec,                    0);
     OPTENT3(0, "voverlap",    OPT_UINT,    &cmdlineP->voverlap,
             &voverlapSpec,                    0);
+    OPTENT3(0, "listfile",    OPT_STRING,  &cmdlineP->listfile,
+            &cmdlineP->listfileSpec,          0);
     OPTENT3(0, "verbose",     OPT_FLAG,    NULL,
             &cmdlineP->verbose,               0);
 
@@ -76,13 +76,19 @@ parseCommandLine(int argc, char ** argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
+    pm_optParseOptions3( &argc, (char **)argv, opt, sizeof(opt), 0 );
         /* Uses and sets argc, argv, and some of *cmdline_p and others. */
 
-    if (!acrossSpec)
+    if (acrossSpec) {
+        if (cmdlineP->across == 0)
+            pm_error ("-across value must be positive");
+    } else
         cmdlineP->across = 1;
-    
-    if (!downSpec)
+
+    if (downSpec) {
+        if (cmdlineP->down == 0)
+            pm_error ("-down value must be positive");
+    } else
         cmdlineP->down = 1;
 
     if (!hoverlapSpec)
@@ -91,16 +97,23 @@ parseCommandLine(int argc, char ** argv,
     if (!voverlapSpec)
         cmdlineP->voverlap = 0;
 
-    if (argc-1 < 1)
-        pm_error("You must specify one argument: the input file name "
-                 "pattern (e.g. 'myimage%%2a%%2d.pnm')");
-    else {
-        cmdlineP->inputFilePattern = argv[1];
-
-        if (argc-1 > 1)
-            pm_error("Progam takes at most one parameter: input file name.  "
-                     "You specified %u", argc-1);
+    if (cmdlineP->listfileSpec) {
+        if (argc-1 > 0)
+            pm_error("Program takes no parameters when -listfile is "
+                     "specified.  You specified %u", argc-1);
+        else
+            cmdlineP->inputFilePattern = NULL;
+    } else {
+        if (argc-1 < 1)
+            pm_error("You must specify one argument, the input file name "
+                     "pattern (e.g. 'myimage%%2a%%2d.pnm'), or -listfile");
+        else if (argc-1 > 1)
+            pm_error("Program takes at most one parameter: "
+                     "the input file name pattern.  You specified %u", argc-1);
+        else
+            cmdlineP->inputFilePattern = argv[1];
     }
+    free(option_def);
 }
 
 
@@ -128,7 +141,7 @@ buffer_init(struct buffer * const bufferP) {
 
 static void
 buffer_term(struct buffer * const bufferP) {
-    
+
     free(bufferP->string);
 }
 
@@ -184,7 +197,7 @@ getPrecision(const char *   const pattern,
     inCursor = startInCursor;  /* Start right after the '%' */
 
     precision = 0;
-                
+
     while (isdigit(pattern[inCursor])) {
         precision = 10 * precision + digitValue(pattern[inCursor]);
         ++inCursor;
@@ -202,13 +215,24 @@ getPrecision(const char *   const pattern,
 
 
 
+typedef struct {
+    /* Context of % substitutions as we progress through a file name pattern */
+    bool downSub;
+        /* There has been a %d (down) substitution */
+    bool acrossSub;
+        /* There has been a %a (across) substitution */
+} SubstContext;
+
+
+
 static void
 doSubstitution(const char *    const pattern,
                unsigned int    const startInCursor,
                unsigned int    const rank,
                unsigned int    const file,
                struct buffer * const bufferP,
-               unsigned int *  const newInCursorP) {
+               unsigned int *  const newInCursorP,
+               SubstContext *  const substContextP) {
 
     unsigned int inCursor;
 
@@ -219,7 +243,7 @@ doSubstitution(const char *    const pattern,
         ++inCursor;
     } else {
         unsigned int precision;
-        
+
         getPrecision(pattern, inCursor, &precision, &inCursor);
 
         if (pattern[inCursor] == '\0')
@@ -232,16 +256,28 @@ doSubstitution(const char *    const pattern,
 
             switch (pattern[inCursor]) {
             case 'a':
-                pm_asprintf(&substString, "%0*u", precision, file);
-                pm_asprintf(&desc, "file (across)");
+                if (substContextP->acrossSub)
+                    pm_error("Format specifier 'a' appears more than "
+                             "once in input file pattern '%s'", pattern);
+                else {
+                    pm_asprintf(&substString, "%0*u", precision, file);
+                    pm_asprintf(&desc, "file (across)");
+                    substContextP->acrossSub = true;
+                }
                 break;
             case 'd':
-                pm_asprintf(&substString, "%0*u", precision, rank);
-                pm_asprintf(&desc, "rank (down)");
+                if (substContextP->downSub)
+                    pm_error("Format specifier 'd' appears more than "
+                             "once in input file pattern '%s'", pattern);
+                else {
+                    pm_asprintf(&substString, "%0*u", precision, rank);
+                    pm_asprintf(&desc, "rank (down)");
+                    substContextP->downSub = true;
+                }
                 break;
             default:
                 pm_error("Unknown format specifier '%c' in input file "
-                         "pattern '%s'.  Recognized format specifier s are "
+                         "pattern '%s'.  Recognized format specifiers are "
                          "'%%a' (across) and '%%d (down)'",
                          pattern[inCursor], pattern);
             }
@@ -252,7 +288,7 @@ doSubstitution(const char *    const pattern,
                          desc, (unsigned)strlen(substString), precision);
             else
                 buffer_addString(bufferP, substString);
-            
+
             pm_strfree(desc);
             pm_strfree(substString);
 
@@ -268,25 +304,32 @@ static void
 computeInputFileName(const char *  const pattern,
                      unsigned int  const rank,
                      unsigned int  const file,
-                     const char ** const fileNameP) {
+                     const char ** const fileNameP,
+                     bool *        const rankFileIndependentP) {
 
     struct buffer buffer;
     unsigned int inCursor;
+    SubstContext substContext;
 
     buffer_init(&buffer);
 
     inCursor = 0;
+    substContext.downSub   = 0;
+    substContext.acrossSub = 0;
 
     while (pattern[inCursor] != '\0') {
         if (pattern[inCursor] == '%') {
             ++inCursor;
 
-            doSubstitution(pattern, inCursor, rank, file, &buffer, &inCursor);
+            doSubstitution(pattern, inCursor, rank, file, &buffer, &inCursor,
+                           &substContext);
 
         } else
             buffer_addChar(&buffer, pattern[inCursor++]);
     }
 
+    *rankFileIndependentP = !substContext.downSub && !substContext.acrossSub;
+
     pm_asprintf(fileNameP, "%s", buffer.string);
 
     buffer_term(&buffer);
@@ -295,8 +338,127 @@ computeInputFileName(const char *  const pattern,
 
 
 
+
+static void
+createInFileListFmFile(const char  *  const listFile,
+                       unsigned int   const nRank,
+                       unsigned int   const nFile,
+                       const char *** const inputFileListP) {
+
+    FILE * const lfP = pm_openr(listFile);
+    unsigned int const fileCt = nRank * nFile;
+
+    const char ** inputFileList;
+    unsigned int fileSeq;
+
+    MALLOCARRAY_NOFAIL(inputFileList, nRank * nFile);
+
+    for (fileSeq = 0; fileSeq < fileCt; ) {
+        int eof;
+        size_t lineLen;
+        char * buf = NULL;   /* initial value */
+        size_t bufferSz = 0; /* initial value */
+
+        pm_getline(lfP, &buf, &bufferSz, &eof, &lineLen);
+
+        if (eof)
+            pm_error("Premature EOF reading list file.  "
+                     "Read %u files.  Should be %u.", fileSeq, fileCt);
+        else if (lineLen > 0) {
+            inputFileList[fileSeq] = buf;
+            ++fileSeq;
+        }
+    }
+    pm_close(lfP);
+
+    *inputFileListP = inputFileList;
+
+}
+
+
+
+static void
+createInFileListFmPattern(const char  *  const pattern,
+                          unsigned int   const nRank,
+                          unsigned int   const nFile,
+                          const char *** const inputFileListP) {
+
+    const char ** inputFileList;
+    unsigned int rank, file;
+    bool warnedSingleFile;
+
+    MALLOCARRAY_NOFAIL(inputFileList, nRank * nFile);
+
+    for (rank = 0, warnedSingleFile = false; rank < nRank ; ++rank) {
+         for (file = 0; file < nFile ; ++file) {
+             const unsigned int idx = rank * nFile + file;
+
+             bool fileNmIsRankFileIndependent;
+
+             computeInputFileName(pattern, rank, file, &inputFileList[idx],
+                                  &fileNmIsRankFileIndependent);
+
+             if (fileNmIsRankFileIndependent && !warnedSingleFile) {
+                 pm_message("Warning: No grid location (%%a/%%d) specified "
+                            "in input file pattern '%s'.  "
+                            "Input is single file", pattern);
+                 warnedSingleFile = true;
+             }
+         }
+    }
+    *inputFileListP = inputFileList;
+}
+
+
+
+static void
+destroyInFileList(const char ** const inputFileList,
+                  unsigned int  const nRank,
+                  unsigned int  const nFile) {
+
+    unsigned int const fileCt = nRank * nFile;
+
+    unsigned int fileSeq;
+
+    for (fileSeq = 0; fileSeq < fileCt; ++fileSeq)
+        pm_strfree(inputFileList[fileSeq]);
+
+    free(inputFileList);
+}
+
+
+
+typedef struct {
+    unsigned int nRank;  /* Number of images in the vertical direction */
+    unsigned int nFile;  /* Number of images in the horizontal direction */
+    unsigned int hoverlap;    /* horizontal overlap */
+    unsigned int voverlap;    /* vertical overlap */
+    const char ** list;  /* List (1-dimensional array) of filenames */
+                         /* Row-major, top to bottom, left to right */
+} InputFiles;
+
+
+
+static const char *
+inputFileName(InputFiles     const inputFiles,
+              unsigned int   const rank,
+              unsigned int   const file) {
+/*----------------------------------------------------------------------------
+    A selected entry from "inputFiles.list" based on "rank" and "file".
+
+    Currently we assume that the list is a one-dimensional represetation
+    of an array, row-major, top to bottom and left to right in each row.
+----------------------------------------------------------------------------*/
+    assert(rank < inputFiles.nRank);
+    assert(file < inputFiles.nFile);
+
+    return inputFiles.list[rank * inputFiles.nFile + file];
+}
+
+
+
 static void
-getCommonInfo(const char *   const inputFilePattern,
+getCommonInfo(InputFiles     const inputFiles,
               int *          const formatP,
               unsigned int * const depthP,
               sample *       const maxvalP,
@@ -306,16 +468,12 @@ getCommonInfo(const char *   const inputFilePattern,
    among all input images and the output image.  I.e. everything except
    width and height.
 -----------------------------------------------------------------------------*/
-    const char * fileName;
-        /* Name of top left input image */
     FILE * ifP;
         /* Top left input image stream */
     struct pam inpam00;
         /* Description of top left input image */
 
-    computeInputFileName(inputFilePattern, 0, 0, &fileName);
-
-    ifP = pm_openr(fileName);
+    ifP = pm_openr(inputFileName(inputFiles, 0, 0));
 
     pnm_readpaminit(ifP, &inpam00, PAM_STRUCT_SIZE(tuple_type));
 
@@ -325,40 +483,19 @@ getCommonInfo(const char *   const inputFilePattern,
     strcpy(tupleType, inpam00.tuple_type);
 
     pm_close(ifP);
-
-    pm_strfree(fileName);
 }
 
 
 
-static FILE *
-openInputImage(const char * const inputFilePattern,
-               unsigned int const rank,
-               unsigned int const file) {
-
-    FILE * retval;
-    const char * fileName;
-        
-    computeInputFileName(inputFilePattern, rank, file, &fileName);
-
-    retval = pm_openr(fileName);
-    
-    pm_strfree(fileName);
-
-    return retval;
-}
-
-               
-
 static void
-getImageInfo(const char * const inputFilePattern,
+getImageInfo(InputFiles   const inputFiles,
              unsigned int const rank,
              unsigned int const file,
              struct pam * const pamP) {
 
     FILE * ifP;
 
-    ifP = openInputImage(inputFilePattern, rank, file);
+    ifP = pm_openr(inputFileName(inputFiles, rank, file));
 
     pnm_readpaminit(ifP, pamP, PAM_STRUCT_SIZE(tuple_type));
 
@@ -369,76 +506,70 @@ getImageInfo(const char * const inputFilePattern,
 
 
 static void
-getOutputWidth(const char * const inputFilePattern,
-               unsigned int const nFile,
-               unsigned int const hoverlap,
-               int *        const widthP) {
+getOutputWidth(InputFiles const inputFiles,
+               int *      const widthP) {
 /*----------------------------------------------------------------------------
-   Get the output width by adding up the widths of all 'nFile' images of
-   the top rank, and allowing for overlap of 'hoverlap' pixels.
+   Get the output width by adding up the widths of all 'inputFiles.nFile'
+   images of the top rank, and allowing for overlap of 'inputFiles.hoverlap'
+   pixels.
 -----------------------------------------------------------------------------*/
-    unsigned int totalWidth;
+    double       totalWidth;
     unsigned int file;
 
-    for (file = 0, totalWidth = 0; file < nFile; ++file) {
+    for (file = 0, totalWidth = 0; file < inputFiles.nFile; ++file) {
         struct pam inpam;
 
-        getImageInfo(inputFilePattern, 0, file, &inpam);
+        getImageInfo(inputFiles, 0, file, &inpam);
 
-        if (inpam.width < hoverlap)
+        if (inpam.width < inputFiles.hoverlap)
             pm_error("Rank 0, file %u image has width %u, "
                      "which is less than the horizontal overlap of %u pixels",
-                     file, inpam.width, hoverlap);
+                     file, inpam.width, inputFiles.hoverlap);
         else {
             totalWidth += inpam.width;
 
-            if (file < nFile-1)
-                totalWidth -= hoverlap;
+            if (file < inputFiles.nFile-1)
+                totalWidth -= inputFiles.hoverlap;
         }
     }
-    *widthP = totalWidth;
+    *widthP = (int) totalWidth;
 }
 
 
 
 static void
-getOutputHeight(const char *  const inputFilePattern,
-                unsigned int  const nRank,
-                unsigned int  const voverlap,
-                int *         const heightP) {
+getOutputHeight(InputFiles const inputFiles,
+                int *      const heightP) {
 /*----------------------------------------------------------------------------
-   Get the output height by adding up the widths of all 'nRank' images of
-   the left file, and allowing for overlap of 'voverlap' pixels.
+   Get the output height by adding up the widths of all 'inputFiles.nRank'
+   images of the left file, and allowing for overlap of 'inputFiles.voverlap'
+   pixels.
 -----------------------------------------------------------------------------*/
-    unsigned int totalHeight;
+    double       totalHeight;
     unsigned int rank;
 
-    for (rank = 0, totalHeight = 0; rank < nRank; ++rank) {
+    for (rank = 0, totalHeight = 0; rank < inputFiles.nRank; ++rank) {
         struct pam inpam;
 
-        getImageInfo(inputFilePattern, rank, 0, &inpam);
+        getImageInfo(inputFiles, rank, 0, &inpam);
 
-        if (inpam.height < voverlap)
+        if (inpam.height < inputFiles.voverlap)
             pm_error("Rank %u, file 0 image has height %u, "
                      "which is less than the vertical overlap of %u pixels",
-                     rank, inpam.height, voverlap);
-        
+                     rank, inpam.height, inputFiles.voverlap);
+
         totalHeight += inpam.height;
-        
-        if (rank < nRank-1)
-            totalHeight -= voverlap;
+
+        if (rank < inputFiles.nRank-1)
+            totalHeight -= inputFiles.voverlap;
     }
-    *heightP = totalHeight;
+    *heightP = (int) totalHeight;
 }
 
 
 
 static void
-initOutpam(const char * const inputFilePattern,
-           unsigned int const nFile,
-           unsigned int const nRank,
-           unsigned int const hoverlap,
-           unsigned int const voverlap,
+initOutpam(InputFiles   const inputFiles,
            FILE *       const ofP,
            bool         const verbose,
            struct pam * const outpamP) {
@@ -447,10 +578,10 @@ initOutpam(const char * const inputFilePattern,
    *outpamP.
 
    Do this by examining the top rank and left file of the input images,
-   which are in files named by 'inputFilePattern', 'nFile', and 'nRank'.
+   which are in 'inputFiles.list'.
 
-   In computing dimensions, assume 'hoverlap' pixels of horizontal
-   overlap and 'voverlap' pixels of vertical overlap.
+   In computing dimensions, assume 'inputFiles.hoverlap' pixels of horizontal
+   overlap and 'inputFiles.voverlap' pixels of vertical overlap.
 
    We overlook any inconsistencies among the images.  E.g. if two images
    have different depths, we just return one of them.  If two images in
@@ -459,23 +590,23 @@ initOutpam(const char * const inputFilePattern,
    Therefore, Caller must check all the input images to make sure they are
    consistent with the information we return.
 -----------------------------------------------------------------------------*/
-    assert(nFile >= 1);
-    assert(nRank >= 1);
+    assert(inputFiles.nFile >= 1);
+    assert(inputFiles.nRank >= 1);
 
     outpamP->size        = sizeof(*outpamP);
     outpamP->len         = PAM_STRUCT_SIZE(tuple_type);
     outpamP->file        = ofP;
     outpamP->plainformat = 0;
-    
-    getCommonInfo(inputFilePattern, &outpamP->format, &outpamP->depth,
+
+    getCommonInfo(inputFiles, &outpamP->format, &outpamP->depth,
                   &outpamP->maxval, outpamP->tuple_type);
 
-    getOutputWidth(inputFilePattern, nFile, hoverlap, &outpamP->width);
+    getOutputWidth(inputFiles,  &outpamP->width);
 
-    getOutputHeight(inputFilePattern, nRank, voverlap, &outpamP->height);
+    getOutputHeight(inputFiles, &outpamP->height);
 
     if (verbose) {
-        pm_message("Output width = %u pixels", outpamP->width);
+        pm_message("Output width = %u pixels",  outpamP->width);
         pm_message("Output height = %u pixels", outpamP->height);
     }
 }
@@ -485,53 +616,50 @@ initOutpam(const char * const inputFilePattern,
 static void
 openInStreams(struct pam         inpam[],
               unsigned int const rank,
-              unsigned int const fileCount,
-              char         const inputFilePattern[]) {
+              InputFiles   const inputFiles) {
 /*----------------------------------------------------------------------------
    Open the input files for a single horizontal slice (there's one file
    for each vertical slice) and read the Netpbm headers from them.  Return
    the pam structures to describe each as inpam[].
 
-   Open the files for horizontal slice number 'rank', assuming there are
-   'fileCount' vertical slices (so open 'fileCount' files).  Use
-   inputFilePattern[] with each rank and file number to compute the name of
-   each file.
+   Open the files for horizontal slice number 'rank', as described by
+   'inputFiles'.
 -----------------------------------------------------------------------------*/
     unsigned int file;
 
-    for (file = 0; file < fileCount; ++file) {
-        FILE * const ifP = openInputImage(inputFilePattern, rank, file);
+    for (file = 0; file < inputFiles.nFile; ++file) {
+        FILE * const ifP = pm_openr(inputFileName(inputFiles, rank, file));
 
         pnm_readpaminit(ifP, &inpam[file], PAM_STRUCT_SIZE(tuple_type));
-    }        
+    }
 }
 
 
 
 static void
 closeInFiles(struct pam         pam[],
-             unsigned int const fileCount) {
+             unsigned int const fileCt) {
 /*----------------------------------------------------------------------------
-   Close the 'fileCount' input file streams represented by pam[].
+   Close the 'fileCt' input file streams represented by pam[].
 -----------------------------------------------------------------------------*/
-    unsigned int file;
-    
-    for (file = 0; file < fileCount; ++file)
-        pm_close(pam[file].file);
+    unsigned int fileSeq;
+
+    for (fileSeq = 0; fileSeq < fileCt; ++fileSeq)
+        pm_close(pam[fileSeq].file);
 }
 
 
 
 static void
-assembleRow(tuple              outputRow[], 
-            struct pam         inpam[], 
-            unsigned int const fileCount,
+assembleRow(tuple              outputRow[],
+            struct pam         inpam[],
+            unsigned int const fileCt,
             unsigned int const hOverlap) {
 /*----------------------------------------------------------------------------
-   Assemble the row outputRow[] from the 'fileCount' input files
+   Assemble the row outputRow[] from the 'fileCt' input files
    described out inpam[].
 
-   'hOverlap', which is meaningful only when fileCount is greater than 1,
+   'hOverlap', which is meaningful only when 'fileCt' is greater than 1,
    is the amount by which files overlap each other.  We assume every
    input image is at least that wide.
 
@@ -539,19 +667,17 @@ assembleRow(tuple              outputRow[],
    entire assembly.
 -----------------------------------------------------------------------------*/
     tuple * inputRow;
-    unsigned int file;
+    unsigned int fileSeq;
 
-    for (file = 0, inputRow = &outputRow[0]; 
-         file < fileCount; 
-         ++file) {
+    for (fileSeq = 0, inputRow = &outputRow[0]; fileSeq < fileCt; ++fileSeq) {
 
-        unsigned int const overlap = file == fileCount - 1 ? 0 : hOverlap;
+        unsigned int const overlap = fileSeq == fileCt - 1 ? 0 : hOverlap;
 
-        assert(hOverlap <= inpam[file].width);
+        assert(hOverlap <= inpam[fileSeq].width);
 
-        pnm_readpamrow(&inpam[file], inputRow);
+        pnm_readpamrow(&inpam[fileSeq], inputRow);
 
-        inputRow += inpam[file].width - overlap;
+        inputRow += inpam[fileSeq].width - overlap;
     }
 }
 
@@ -574,6 +700,7 @@ allocInpam(unsigned int  const rankCount,
 
 
 
+
 static void
 verifyRankFileAttributes(struct pam *       const inpam,
                          unsigned int       const nFile,
@@ -622,7 +749,7 @@ verifyRankFileAttributes(struct pam *       const inpam,
                      rank, file, inpamP->height, inpam[0].height);
         else {
             totalWidth += inpamP->width;
-        
+
             if (file < nFile-1)
                 totalWidth -= hoverlap;
         }
@@ -637,11 +764,7 @@ verifyRankFileAttributes(struct pam *       const inpam,
 
 static void
 assembleTiles(struct pam * const outpamP,
-              const char * const inputFilePattern,
-              unsigned int const nFile,
-              unsigned int const nRank,
-              unsigned int const hoverlap,
-              unsigned int const voverlap,
+              InputFiles   const inputFiles,
               struct pam         inpam[],
               tuple *      const tuplerow) {
 
@@ -649,12 +772,17 @@ assembleTiles(struct pam * const outpamP,
         /* Number of the current rank (horizontal slice).  Ranks are numbered
            sequentially starting at 0.
         */
-    
+
+    unsigned int const nRank    = inputFiles.nRank;
+    unsigned int const nFile    = inputFiles.nFile;
+    unsigned int const hoverlap = inputFiles.hoverlap;
+    unsigned int const voverlap = inputFiles.voverlap;
+
     for (rank = 0; rank < nRank; ++rank) {
         unsigned int row;
         unsigned int rankHeight;
 
-        openInStreams(inpam, rank, nFile, inputFilePattern);
+        openInStreams(inpam, rank, inputFiles);
 
         verifyRankFileAttributes(inpam, nFile, outpamP, hoverlap, rank);
 
@@ -672,36 +800,47 @@ assembleTiles(struct pam * const outpamP,
 
 
 int
-main(int argc, char ** argv) {
+main(int argc, const char ** argv) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
+    InputFiles inputFiles;
     struct pam outpam;
     struct pam * inpam;
         /* malloc'ed.  inpam[x] is the pam structure that controls the
-           current rank of file x. 
+           current rank of file x.
         */
     tuple * tuplerow;
 
-    pnm_init(&argc, argv);
-    
+    pm_proginit(&argc, argv);
+
     parseCommandLine(argc, argv, &cmdline);
-        
+
     allocInpam(cmdline.across, &inpam);
 
-    initOutpam(cmdline.inputFilePattern, cmdline.across, cmdline.down,
-               cmdline.hoverlap, cmdline.voverlap, stdout, cmdline.verbose,
-               &outpam);
-    
+    if (cmdline.listfileSpec)
+        createInFileListFmFile(cmdline.listfile,
+                               cmdline.down, cmdline.across,
+                               &inputFiles.list);
+    else
+        createInFileListFmPattern(cmdline.inputFilePattern,
+                                  cmdline.down, cmdline.across,
+                                  &inputFiles.list);
+
+    inputFiles.nFile    = cmdline.across;
+    inputFiles.nRank    = cmdline.down;
+    inputFiles.hoverlap = cmdline.hoverlap;
+    inputFiles.voverlap = cmdline.voverlap;
+
+    initOutpam(inputFiles, stdout, cmdline.verbose, &outpam);
+
     tuplerow = pnm_allocpamrow(&outpam);
 
     pnm_writepaminit(&outpam);
 
-    assembleTiles(&outpam,
-                  cmdline.inputFilePattern, cmdline.across, cmdline.down,
-                  cmdline.hoverlap, cmdline.voverlap, inpam, tuplerow);
+    assembleTiles(&outpam, inputFiles, inpam, tuplerow);
 
     pnm_freepamrow(tuplerow);
-
+    destroyInFileList(inputFiles.list, inputFiles.nRank, inputFiles.nFile);
     free(inpam);
 
     return 0;
diff --git a/editor/pbmclean.c b/editor/pbmclean.c
index 08f410c0..47c775e5 100644
--- a/editor/pbmclean.c
+++ b/editor/pbmclean.c
@@ -381,7 +381,7 @@ cleanSimple(FILE *             const ifP,
    Do the traditional clean where you look only at the immediate neighboring
    pixels of a subject pixel to determine whether to erase that pixel.
 -----------------------------------------------------------------------------*/
-    bit ** buffer;
+    bit ** buffer;  /* one bit per pixel */
         /* The rows of the input relevant to our current processing:
            the current row and the one above and below it.
         */
@@ -399,7 +399,7 @@ cleanSimple(FILE *             const ifP,
     setupInputBuffers(ifP, cols, format, &buffer, &edgeRow,
                       &thisRow, &nextRow);
 
-    outRow = pbm_allocrow(cols);
+    outRow = pbm_allocrow_packed(cols);
 
     pbm_writepbminit(ofP, cols, rows, 0) ;
 
@@ -756,12 +756,12 @@ cleanExtended(FILE *             const ifP,
    We erase (flip) every pixel in every trivial blob.  A trivial blob is
    one with 'trivialSize' pixels or fewer.
 -----------------------------------------------------------------------------*/
-    bit ** pixels;
+    bit ** pixels;    /* one byte per pixel */
     int cols, rows;
 
     pixels = pbm_readpbm(ifP, &cols, &rows);
 
-	cleanPixels(pixels, cols, rows, foregroundColor, trivialSize, nFlippedP);
+        cleanPixels(pixels, cols, rows, foregroundColor, trivialSize, nFlippedP);
 
     pbm_writepbm(ofP, pixels, cols, rows, 0);
 
diff --git a/editor/pbmpscale.c b/editor/pbmpscale.c
index 3b6935b2..434c7965 100644
--- a/editor/pbmpscale.c
+++ b/editor/pbmpscale.c
@@ -12,7 +12,7 @@
 #define LEFTBITS pm_byteLeftBits
 #define RIGHTBITS pm_byteRightBits
 
-/* Table for translating bit pattern into "corners" flag element */ 
+/* Table for translating bit pattern into "corners" flag element */
 
 unsigned char const
 transTable[512] = {
@@ -191,8 +191,8 @@ setFlags(const bit *     const prevrow,
          unsigned char * const flags,
          unsigned int    const cols ) {
 /*----------------------------------------------------------------------------
-   Scan one row, examining the row above and row below, and determine 
-   whether there are "corners" for each pixel.  Feed a 9 bit sample into 
+   Scan one row, examining the row above and row below, and determine
+   whether there are "corners" for each pixel.  Feed a 9 bit sample into
    pre-calculated array transTable[512] to calculate all four corner statuses
    at once.
 
@@ -220,7 +220,7 @@ setFlags(const bit *     const prevrow,
        The high byte of the patterns is a mask, which determines which bits are
        not ignored.
     */
-    uint16_t const patterns[] 
+    uint16_t const patterns[]
         = { 0x0000,   0xd555,            /* no corner */
             0x0001,   0xffc1, 0xd514,    /* normal corner */
             0x0002,   0xd554, 0xd515, 0xbea2, 0xdfc0, 0xfd81, 0xfd80, 0xdf80,
@@ -230,7 +230,7 @@ setFlags(const bit *     const prevrow,
     /*
       For example, the NE corner is examined with the following 8 bit sample:
       Current : W : NW : N : NE : E : SE : S
-      (SW is the "square behind") 
+      (SW is the "square behind")
       */
 #endif
 
@@ -257,7 +257,7 @@ setFlags(const bit *     const prevrow,
         sample = ( ( prevrow24 >> ( 8 -offset) ) & 0x01c0 )
             | ( ( thisrow24 >> (11 -offset) ) & 0x0038 )
             | ( ( nextrow24 >> (14 -offset) ) & 0x0007 );
-        
+
         flags[col] =  transTable[sample];
     }
 }
@@ -275,14 +275,14 @@ expandRow(const bit *     const thisrow,
           int             const ucutoff) {
 /*----------------------------------------------------------------------------
   Process one row, using flags array as reference.  If pixel has no corners
-  output a NxN square of the given color, otherwise output with the 
+  output a NxN square of the given color, otherwise output with the
   specified corner area(s) clipped off.
 -----------------------------------------------------------------------------*/
     unsigned int const outcols = cols * scale;
 
     unsigned int i;
     unsigned int col;
-    
+
     for (i = 0; i < scale; ++i) {
         int const zone = (i > ucutoff) - (i < cutoff);
         int const cut1 =
@@ -297,7 +297,7 @@ expandRow(const bit *     const thisrow,
         cut[1] = cut1;
         cut[2] = cut1 ? cut1 - 1 : 0;
         cut[3] = (cut1 && cutoff > 1) ? cut1 - 1 : cut1;
-      
+
         for (col = 0; col < cols; ++col) {
             unsigned int const col8 = col / 8;
             unsigned int const offset = col % 8;
@@ -309,11 +309,11 @@ expandRow(const bit *     const thisrow,
             if (flag == 0x00) {
                 /* There are no corners, no color change */
                 outcol += scale;
-            } else { 
+            } else {
                 switch (zone) {
                 case -1:
                     if (i==0 && flag == 0xff) {
-                        /* No corners, color changed */ 
+                        /* No corners, color changed */
                         cutl = cutr = 0;
                         flags[col] = 0x00;
                             /* Use above skip procedure next cycle */
@@ -330,7 +330,7 @@ expandRow(const bit *     const thisrow,
                     cutr = cut[SE(flag)];
                     break;
                 }
-                
+
                 if (cutl > 0) {
                     writeBitSpan(outrow, cutl, outcol, !pix);
                     outcol += cutl;
@@ -384,10 +384,10 @@ main(int argc, const char ** argv) {
 
     pbm_readpbminit(ifP, &cols, &rows, &format) ;
 
-    validateComputableDimensions(cols, rows, cmdline.scale); 
+    validateComputableDimensions(cols, rows, cmdline.scale);
 
     outcols = cols * cmdline.scale;
-    outrows = rows * cmdline.scale; 
+    outrows = rows * cmdline.scale;
 
     /* Initialize input buffers.
        We add a margin of 8 bits on the right of the three rows.
@@ -402,7 +402,7 @@ main(int argc, const char ** argv) {
     for (i = 0; i < pbm_packed_bytes(cols + 8); ++i)
         edgerow[i] = 0x00;
 
-    /* Add blank bytes at right edges */ 
+    /* Add blank bytes at right edges */
     for (i = 0; i < 3; ++i)
         buffer[i][pbm_packed_bytes(cols + 8) - 1] = 0x00;
 
diff --git a/editor/pbmreduce.c b/editor/pbmreduce.c
index 3a0968fe..70caa581 100644
--- a/editor/pbmreduce.c
+++ b/editor/pbmreduce.c
@@ -11,9 +11,11 @@
 */
 
 #include "pm_c_util.h"
-#include "pbm.h"
 #include "mallocvar.h"
+#include "rand.h"
 #include "shhopt.h"
+#include "pbm.h"
+
 #include <assert.h>
 
 #define SCALE 1024
@@ -105,7 +107,7 @@ parseCommandLine(int argc, const char ** argv,
         unsigned int scale;
 
         scale = strtol(argv[1], &endptr, 10);
-        if (*argv[1] == '\0') 
+        if (*argv[1] == '\0')
             pm_error("Scale argument is a null string.  Must be a number.");
         else if (*endptr != '\0')
             pm_error("Scale argument contains non-numeric character '%c'.",
@@ -115,7 +117,7 @@ parseCommandLine(int argc, const char ** argv,
                      "You specified %d", scale);
         else if (scale > INT_MAX / scale)
             pm_error("Scale argument too large.  You specified %d", scale);
-        else 
+        else
             cmdlineP->scale = scale;
 
         if (argc-1 > 1) {
@@ -145,10 +147,11 @@ struct FS {
 static void
 initializeFloydSteinberg(struct FS  * const fsP,
                          int          const newcols,
-                         unsigned int const seed,
-                         bool         const seedSpec) {
+                         bool         const seedSpec,
+                         unsigned int const seed) {
 
     unsigned int col;
+    struct pm_randSt randSt;
 
     MALLOCARRAY(fsP->thiserr, newcols + 2);
     MALLOCARRAY(fsP->nexterr, newcols + 2);
@@ -156,33 +159,36 @@ initializeFloydSteinberg(struct FS  * const fsP,
     if (fsP->thiserr == NULL || fsP->nexterr == NULL)
         pm_error("out of memory");
 
-    srand(seedSpec ? seed : pm_randseed());
+    pm_randinit(&randSt);
+    pm_srand2(&randSt, seedSpec, seed);
 
     for (col = 0; col < newcols + 2; ++col)
-        fsP->thiserr[col] = (rand() % SCALE - HALFSCALE) / 4;
+        fsP->thiserr[col] = ((int) (pm_rand(&randSt) % SCALE) - HALFSCALE) / 4;
         /* (random errors in [-SCALE/8 .. SCALE/8]) */
+
+    pm_randterm(&randSt);
 }
 
 
 
 /*
     Scanning method
-    
+
     In Floyd-Steinberg dithering mode horizontal direction of scan alternates
     between rows; this is called "serpentine scanning".
-    
+
     Example input (14 x 7), N=3:
-    
+
     111222333444xx    Fractional pixels on the right edge and bottom edge (x)
-    111222333444xx    are ignored; their values do not influence output. 
+    111222333444xx    are ignored; their values do not influence output.
     111222333444xx
     888777666555xx
     888777666555xx
     888777666555xx
     xxxxxxxxxxxxxx
-    
+
     Output (4 x 2):
-    
+
     1234
     8765
 
@@ -196,11 +202,14 @@ enum Direction { RIGHT_TO_LEFT, LEFT_TO_RIGHT };
 static enum Direction
 oppositeDir(enum Direction const arg) {
 
+    enum Direction retval;
+
     switch (arg) {
-    case LEFT_TO_RIGHT: return RIGHT_TO_LEFT;
-    case RIGHT_TO_LEFT: return LEFT_TO_RIGHT;
+    case LEFT_TO_RIGHT: retval = RIGHT_TO_LEFT; break;
+    case RIGHT_TO_LEFT: retval = LEFT_TO_RIGHT; break;
     }
-    assert(false);  /* All cases handled above */
+
+    return retval;
 }
 
 
@@ -240,7 +249,7 @@ main(int argc, const char * argv[]) {
 
     if (cmdline.halftone == QT_FS)
         initializeFloydSteinberg(&fs, newcols,
-                                 cmdline.randomseed, cmdline.randomseedSpec);
+                                 cmdline.randomseedSpec, cmdline.randomseed);
     else {
         /* These variables are meaningless in this case, and the values
            should never be used.
@@ -258,10 +267,10 @@ main(int argc, const char * argv[]) {
         int limitCol;
         int startCol;
         int step;
-   
+
         for (colChar = 0; colChar < colChars; ++colChar)
             newbitrow[colChar] = 0x00;  /* Clear to white */
- 
+
         for (subrow = 0; subrow < cmdline.scale; ++subrow)
             pbm_readpbmrow(ifP, bitslice[subrow], cols, format);
 
@@ -274,7 +283,7 @@ main(int argc, const char * argv[]) {
         case LEFT_TO_RIGHT: {
             startCol = 0;
             limitCol = newcols;
-            step = +1;  
+            step = +1;
         } break;
         case RIGHT_TO_LEFT: {
             startCol = newcols - 1;
diff --git a/editor/pgmmedian.c b/editor/pgmmedian.c
index 4648af68..9cebeac8 100644
--- a/editor/pgmmedian.c
+++ b/editor/pgmmedian.c
@@ -1,4 +1,4 @@
-/* 
+/*
 ** Version 1.0  September 28, 1996
 **
 ** Copyright (C) 1996 by Mike Burns <burns@cac.psu.edu>
@@ -15,16 +15,17 @@
 
 /* References
 ** ----------
-** The select k'th value implementation is based on Algorithm 489 by 
+** The select k'th value implementation is based on Algorithm 489 by
 ** Robert W. Floyd from the "Collected Algorithms from ACM" Volume II.
 **
 ** The histogram sort is based is described in the paper "A Fast Two-
-** Dimensional Median Filtering Algorithm" in "IEEE Transactions on 
+** Dimensional Median Filtering Algorithm" in "IEEE Transactions on
 ** Acoustics, Speech, and Signal Processing" Vol. ASSP-27, No. 1, February
 ** 1979.  The algorithm I more closely followed is found in "Digital
 ** Image Processing Algorithms" by Ioannis Pitas.
 */
 
+#include <assert.h>
 
 #include "pm_c_util.h"
 #include "pgm.h"
@@ -32,10 +33,10 @@
 #include "mallocvar.h"
 #include "nstring.h"
 
-enum medianMethod {MEDIAN_UNSPECIFIED, SELECT_MEDIAN, HISTOGRAM_SORT_MEDIAN};
+enum MedianMethod {MEDIAN_UNSPECIFIED, SELECT_MEDIAN, HISTOGRAM_SORT_MEDIAN};
 #define MAX_MEDIAN_TYPES      2
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -43,24 +44,28 @@ struct cmdlineInfo {
     unsigned int width;
     unsigned int height;
     unsigned int cutoff;
-    enum medianMethod type;
+    enum MedianMethod type;
 };
 
 
-/* Global variables common to each median sort routine. */
 static int const forceplain = 0;
-static int format;
-static gray maxval;
-static gray **grays;
-static gray *grayrow;
-static int ccolso2, crowso2;
-static int row;
+
+
+
+/* Global variables common to each median sort routine. */
+static gray ** grays;
+    /* The convolution buffer.  This is a circular buffer that contains the
+       rows of the input image that are being convolved into the current 
+       output row.
+    */
+static gray * grayrow;
+    /* A buffer for building the current output row */
 
 
 
 static void
-parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo * const cmdlineP) {
+parseCommandLine(int argc, const 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.
@@ -91,13 +96,21 @@ parseCommandLine(int argc, char ** argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We may have parms that are negative numbers */
 
-    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
-    if (!widthSpec)
+    if (widthSpec) {
+        if (cmdlineP->width < 1)
+            pm_error("-width must be at least 1");
+    } else
         cmdlineP->width = 3;
-    if (!heightSpec)
+
+    if (heightSpec) {
+        if (cmdlineP->height < 1)
+            pm_error("-height must be at least 1");
+    } else
         cmdlineP->height = 3;
+
     if (!cutoffSpec)
         cmdlineP->cutoff = 250;
 
@@ -125,6 +138,32 @@ parseCommandLine(int argc, char ** argv,
 
 
 static void
+setWindow(gray **      const convBuffer,
+          unsigned int const crows,
+          gray **      const cgrayrow,
+          unsigned int const lastRow) {
+/*----------------------------------------------------------------------------
+   Set 'cgrayrow' so it points into the circular buffer 'convBuffer' such
+   that cgrayrow[0] is the topmost row in the buffer, given that the
+   bottommost row in the buffer is row number 'lastRow'.
+-----------------------------------------------------------------------------*/
+    unsigned int const windowTopRow = (lastRow + 1) % crows;
+
+    unsigned int bufferRow;
+    unsigned int wrow;
+
+    wrow = 0;
+
+    for (bufferRow = windowTopRow; bufferRow < crows; ++wrow, ++bufferRow)
+        cgrayrow[wrow] = grays[bufferRow];
+
+    for (bufferRow = 0; bufferRow < windowTopRow; ++wrow, ++bufferRow)
+        cgrayrow[wrow] = grays[bufferRow];
+}
+
+
+
+static void
 select489(gray * const a,
           int *  const parray,
           int    const n,
@@ -184,54 +223,53 @@ selectMedian(FILE *       const ifP,
              unsigned int const crows,
              unsigned int const cols,
              unsigned int const rows,
-             unsigned int const median) {
+             int          const format,
+             gray         const maxval,
+             unsigned int const median,
+             unsigned int const firstRow) {
+
+    unsigned int const ccolso2 = ccols / 2;
+    unsigned int const crowso2 = crows / 2;
 
     unsigned int const numValues = crows * ccols;
 
     unsigned int col;
-    gray * garray;
-        /* Array of the currenty gray values */
+    gray * garray;  /* Array of the currently gray values */
     int * parray;
     int * subcol;
-    gray ** rowptr;
-    
+    gray ** cgrayrow;
+    unsigned int row;
+
     garray = pgm_allocrow(numValues);
 
-    MALLOCARRAY(rowptr, crows);
+    MALLOCARRAY(cgrayrow, crows);
     MALLOCARRAY(parray, numValues);
     MALLOCARRAY(subcol, cols);
 
-    if (rowptr == NULL || parray == NULL || subcol == NULL)
+    if (cgrayrow == NULL || parray == NULL || subcol == NULL)
         pm_error("Unable to allocate memory");
 
     for (col = 0; col < cols; ++col)
         subcol[col] = (col - (ccolso2 + 1)) % ccols;
 
     /* Apply median to main part of image. */
-    for ( ; row < rows; ++row) {
-        int crow;
-        int rownum, irow, temprow;
+    for (row = firstRow; row < rows; ++row) {
+        unsigned int crow;
         unsigned int col;
-    
+
         pgm_readpgmrow(ifP, grays[row % crows], cols, maxval, format);
 
-        /* Rotate pointers to rows, so rows can be accessed in order. */
-        temprow = (row + 1) % crows;
-        rownum = 0;
-        for (irow = temprow; irow < crows; ++rownum, ++irow)
-            rowptr[rownum] = grays[irow];
-        for (irow = 0; irow < temprow; ++rownum, ++irow)
-            rowptr[rownum] = grays[irow];
+        setWindow(grays, crows, cgrayrow, row);
 
         for (col = 0; col < cols; ++col) {
             if (col < ccolso2 || col >= cols - ccolso2) {
-                grayrow[col] = rowptr[crowso2][col];
+                grayrow[col] = cgrayrow[crowso2][col];
             } else if (col == ccolso2) {
                 unsigned int const leftcol = col - ccolso2;
                 unsigned int i;
                 i = 0;
                 for (crow = 0; crow < crows; ++crow) {
-                    gray * const temprptr = rowptr[crow] + leftcol;
+                    gray * const temprptr = cgrayrow[crow] + leftcol;
                     unsigned int ccol;
                     for (ccol = 0; ccol < ccols; ++ccol) {
                         garray[i] = *(temprptr + ccol);
@@ -246,23 +284,16 @@ selectMedian(FILE *       const ifP,
                 unsigned int crow;
                 unsigned int tsum;
                 for (crow = 0, tsum = 0; crow < crows; ++crow, tsum += ccols)
-                    garray[tsum + subcol[col]] = *(rowptr[crow] + addcol );
+                    garray[tsum + subcol[col]] = *(cgrayrow[crow] + addcol );
                 select489( garray, parray, numValues, median );
                 grayrow[col] = garray[parray[median]];
             }
         }
         pgm_writepgmrow( stdout, grayrow, cols, maxval, forceplain );
     }
-
-    {
-        unsigned int irow;
-        /* Write out remaining unchanged rows. */
-        for (irow = crowso2 + 1; irow < crows; ++irow)
-            pgm_writepgmrow(stdout, rowptr[irow], cols, maxval, forceplain);
-    }
     free(subcol);
     free(parray);
-    free(rowptr);
+    free(cgrayrow);
     pgm_freerow(garray);
 }
 
@@ -274,31 +305,40 @@ histogramSortMedian(FILE *       const ifP,
                     unsigned int const crows,
                     unsigned int const cols,
                     unsigned int const rows,
-                    unsigned int const median) {
+                    int          const format,
+                    gray         const maxval,
+                    unsigned int const median,
+                    unsigned int const firstRow) {
 
+    unsigned int const ccolso2 = ccols / 2;
+    unsigned int const crowso2 = crows / 2;
     unsigned int const histmax = maxval + 1;
 
     unsigned int * hist;
     unsigned int mdn, ltmdn;
     gray * leftCol;
     gray * rghtCol;
-    gray ** rowptr;
-
-    MALLOCARRAY(rowptr, crows);
+    gray ** cgrayrow;
+        /* The window of the image currently being convolved, with
+           cgrayrow[0] being the top row of the window.  Pointers into grays[]
+        */
+    unsigned int row;
+        /* Row number in input -- bottommost row in the window we're currently
+           convolving
+        */
+
+    MALLOCARRAY(cgrayrow, crows);
     MALLOCARRAY(hist, histmax);
 
-    if (rowptr == NULL || hist == NULL)
+    if (cgrayrow == NULL || hist == NULL)
         pm_error("Unable to allocate memory");
 
     leftCol = pgm_allocrow(crows);
     rghtCol = pgm_allocrow(crows);
 
     /* Apply median to main part of image. */
-    for ( ; row < rows; ++row) {
+    for (row = firstRow; row < rows; ++row) {
         unsigned int col;
-        unsigned int temprow;
-        unsigned int rownum;
-        unsigned int irow;
         unsigned int i;
         /* initialize hist[] */
         for (i = 0; i < histmax; ++i)
@@ -306,24 +346,18 @@ histogramSortMedian(FILE *       const ifP,
 
         pgm_readpgmrow(ifP, grays[row % crows], cols, maxval, format);
 
-        /* Rotate pointers to rows, so rows can be accessed in order. */
-        temprow = (row + 1) % crows;
-        rownum = 0;
-        for (irow = temprow; irow < crows; ++rownum, ++irow)
-            rowptr[rownum] = grays[irow];
-        for (irow = 0; irow < temprow; ++rownum, ++irow)
-            rowptr[rownum] = grays[irow];
+        setWindow(grays, crows, cgrayrow, row);
 
         for (col = 0; col < cols; ++col) {
             if (col < ccolso2 || col >= cols - ccolso2)
-                grayrow[col] = rowptr[crowso2][col];
+                grayrow[col] = cgrayrow[crowso2][col];
             else if (col == ccolso2) {
-                unsigned int crow;
                 unsigned int const leftcol = col - ccolso2;
+                unsigned int crow;
                 i = 0;
                 for (crow = 0; crow < crows; ++crow) {
                     unsigned int ccol;
-                    gray * const temprptr = rowptr[crow] + leftcol;
+                    gray * const temprptr = cgrayrow[crow] + leftcol;
                     for (ccol = 0; ccol < ccols; ++ccol) {
                         gray const g = *(temprptr + ccol);
                         ++hist[g];
@@ -334,17 +368,17 @@ histogramSortMedian(FILE *       const ifP,
                 for (mdn = 0; ltmdn <= median; ++mdn)
                     ltmdn += hist[mdn];
                 --mdn;
-                if (ltmdn > median) 
+                if (ltmdn > median)
                     ltmdn -= hist[mdn];
 
                 grayrow[col] = mdn;
             } else {
-                unsigned int crow;
                 unsigned int const subcol = col - (ccolso2 + 1);
                 unsigned int const addcol = col + ccolso2;
+                unsigned int crow;
                 for (crow = 0; crow < crows; ++crow) {
-                    leftCol[crow] = *(rowptr[crow] + subcol);
-                    rghtCol[crow] = *(rowptr[crow] + addcol);
+                    leftCol[crow] = *(cgrayrow[crow] + subcol);
+                    rghtCol[crow] = *(cgrayrow[crow] + addcol);
                 }
                 for (crow = 0; crow < crows; ++crow) {
                     {
@@ -374,7 +408,7 @@ histogramSortMedian(FILE *       const ifP,
                         ++mdn;
                     }
                     --mdn;
-                    if (ltmdn > median) 
+                    if (ltmdn > median)
                         ltmdn -= hist[mdn];
                 }
                 grayrow[col] = mdn;
@@ -382,84 +416,127 @@ histogramSortMedian(FILE *       const ifP,
         }
         pgm_writepgmrow(stdout, grayrow, cols, maxval, forceplain);
     }
-
-    {
-        /* Write out remaining unchanged rows. */
-        unsigned int irow;
-        for (irow = crowso2 + 1; irow < crows; ++irow)
-            pgm_writepgmrow(stdout, rowptr[irow], cols, maxval, forceplain);
-    }
     pgm_freerow(leftCol);
     pgm_freerow(rghtCol);
     free(hist);
-    free(rowptr);
+    free(cgrayrow);
+}
+
+
+
+static void
+convolve(FILE *            const ifP,
+         unsigned int      const cols,
+         unsigned int      const rows,
+         gray              const maxval,
+         int               const format,
+         unsigned int      const ccols,
+         unsigned int      const crows,
+         enum MedianMethod const medianMethod,
+         unsigned int      const median) {
+
+    unsigned int const crowso2 = crows / 2;
+
+    unsigned int row;
+
+    /* An even-size convolution window is biased toward the top and left.  So
+       if it is 8 rows, the window covers 4 rows above the target row and 3
+       rows below it, plus the target row itself.  'crowso2' is the number of
+       the target row within the window.  There are always 'crowso2' rows
+       above it and either crowso2 or crowso2-1 rows below it.
+    */
+
+    /* Allocate space for number of rows in mask size. */
+    grays = pgm_allocarray(cols, crows);
+    grayrow = pgm_allocrow(cols);
+
+    /* Prime the convolution window -- fill it except the last row */
+    for (row = 0; row < crows - 1; ++row)
+        pgm_readpgmrow(ifP, grays[row], cols, maxval, format);
+
+    /* Copy the top half out verbatim, since convolution kernel for these rows
+       runs off the top of the image.
+    */
+    for (row = 0; row < crowso2; ++row)
+        pgm_writepgmrow(stdout, grays[row], cols, maxval, forceplain);
+
+    switch (medianMethod) {
+    case SELECT_MEDIAN:
+        selectMedian(ifP, ccols, crows, cols, rows, format, maxval,
+                     median, crows-1);
+        break;
+
+    case HISTOGRAM_SORT_MEDIAN:
+        histogramSortMedian(ifP, ccols, crows, cols, rows, format, maxval,
+                            median, crows-1);
+        break;
+    case MEDIAN_UNSPECIFIED:
+        pm_error("INTERNAL ERROR: median unspecified");
+    }
+
+    /* Copy the bottom half of the remaining convolution window verbatim,
+       since convolution kernel for these rows runs off the bottom of the
+       image.
+    */
+    assert(crows >= crowso2 + 1);
+
+    for (row = rows - (crows-crowso2-1); row < rows; ++row)
+        pgm_writepgmrow(stdout, grays[row % crows], cols, maxval,
+                        forceplain);
+
+    pgm_freearray(grays, crows);
+    pgm_freerow(grayrow);
 }
 
 
 
 int
-main(int    argc,
-     char * argv[]) {
+main(int          argc,
+     const char * argv[]) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     FILE * ifP;
     int cols, rows;
-    int median;
-    enum medianMethod medianMethod;
+    int format;
+    gray maxval;
+    unsigned int ccols, crows;
+    unsigned int median;
+    enum MedianMethod medianMethod;
 
-    pgm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
-    
+
     ifP = pm_openr(cmdline.inputFileName);
 
-    ccolso2 = cmdline.width / 2;
-    crowso2 = cmdline.height / 2;
+    assert(cmdline.height > 0 && cmdline.width > 0);
 
     pgm_readpgminit(ifP, &cols, &rows, &maxval, &format);
-    pgm_writepgminit(stdout, cols, rows, maxval, forceplain);
 
-    /* Allocate space for number of rows in mask size. */
-    grays = pgm_allocarray(cols, cmdline.height);
-    grayrow = pgm_allocrow(cols);
+    ccols = MIN(cmdline.width,  cols+1);
+    crows = MIN(cmdline.height, rows+1);
 
-    /* Read in and write out initial rows that won't get changed. */
-    for (row = 0; row < cmdline.height - 1; ++row) {
-        pgm_readpgmrow(ifP, grays[row], cols, maxval, format);
-        /* Write out the unchanged row. */
-        if (row < crowso2)
-            pgm_writepgmrow(stdout, grays[row], cols, maxval, forceplain);
-    }
+    pgm_writepgminit(stdout, cols, rows, maxval, forceplain);
 
-    median = (cmdline.height * cmdline.width) / 2;
+    median = (crows * ccols) / 2;
 
     /* Choose which sort to run. */
     if (cmdline.type == MEDIAN_UNSPECIFIED) {
-        if ((maxval / ((cmdline.width * cmdline.height) - 1)) < cmdline.cutoff)
+        if ((maxval / ((ccols * crows) - 1)) < cmdline.cutoff)
             medianMethod = HISTOGRAM_SORT_MEDIAN;
         else
             medianMethod = SELECT_MEDIAN;
     } else
         medianMethod = cmdline.type;
 
-    switch (medianMethod) {
-    case SELECT_MEDIAN:
-        selectMedian(ifP, cmdline.width, cmdline.height, cols, rows, median);
-        break;
-        
-    case HISTOGRAM_SORT_MEDIAN:
-        histogramSortMedian(ifP, cmdline.width, cmdline.height,
-                            cols, rows, median);
-        break;
-    case MEDIAN_UNSPECIFIED:
-        pm_error("INTERNAL ERROR: median unspecified");
-    }
-    
+
+    convolve(ifP, cols, rows, maxval, format, ccols, crows, medianMethod,
+             median);
+
     pm_close(ifP);
     pm_close(stdout);
 
-    pgm_freearray(grays, cmdline.height);
-    pgm_freerow(grayrow);
-
     return 0;
 }
+
+
diff --git a/editor/pnmcat.c b/editor/pnmcat.c
deleted file mode 100644
index 217f6b57..00000000
--- a/editor/pnmcat.c
+++ /dev/null
@@ -1,872 +0,0 @@
-/* pnmcat.c - concatenate PNM images
-**
-** Copyright (C) 1989, 1991 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 <assert.h>
-
-#include "pm_c_util.h"
-#include "mallocvar.h"
-#include "shhopt.h"
-#include "bitarith.h"
-#include "nstring.h"
-#include "pnm.h"
-
-#define LEFTBITS pm_byteLeftBits
-#define RIGHTBITS pm_byteRightBits
-
-enum backcolor {BACK_WHITE, BACK_BLACK, BACK_AUTO};
-
-enum orientation {TOPBOTTOM, LEFTRIGHT};
-
-enum justification {JUST_CENTER, JUST_MIN, JUST_MAX};
-
-struct imgInfo {
-    /* This obviously should be a struct pam.  We should convert this
-       to 'pamcat'.
-    */
-    FILE * ifP;
-    int    cols;
-    int    rows;
-    int    format;
-    xelval maxval;
-};
-
-
-
-struct cmdlineInfo {
-    /* All the information the user supplied in the command line,
-       in a form easy for the program to use.
-    */
-    const char ** inputFilespec;
-    unsigned int nfiles;
-    enum backcolor backcolor;
-    enum orientation orientation;
-    enum justification justification;
-};
-
-
-
-static void
-parseCommandLine(int argc, const char ** const argv,
-                 struct cmdlineInfo * const cmdlineP) {
-/*----------------------------------------------------------------------------
-   Note that the file spec array we return is stored in the storage that
-   was passed to us as the argv array.
------------------------------------------------------------------------------*/
-    optEntry * option_def;
-        /* Instructions to OptParseOptions3() on how to parse our options.
-         */
-    optStruct3 opt;
-
-    unsigned int option_def_index;
-
-    unsigned int leftright, topbottom, black, white, jtop, jbottom,
-        jleft, jright, jcenter;
-
-    MALLOCARRAY_NOFAIL(option_def, 100);
-
-    option_def_index = 0;   /* incremented by OPTENTRY */
-    OPTENT3(0, "leftright",  OPT_FLAG,   NULL, &leftright,   0);
-    OPTENT3(0, "lr",         OPT_FLAG,   NULL, &leftright,   0);
-    OPTENT3(0, "topbottom",  OPT_FLAG,   NULL, &topbottom,   0);
-    OPTENT3(0, "tb",         OPT_FLAG,   NULL, &topbottom,   0);
-    OPTENT3(0, "black",      OPT_FLAG,   NULL, &black,       0);
-    OPTENT3(0, "white",      OPT_FLAG,   NULL, &white,       0);
-    OPTENT3(0, "jtop",       OPT_FLAG,   NULL, &jtop,        0);
-    OPTENT3(0, "jbottom",    OPT_FLAG,   NULL, &jbottom,     0);
-    OPTENT3(0, "jleft",      OPT_FLAG,   NULL, &jleft,       0);
-    OPTENT3(0, "jright",     OPT_FLAG,   NULL, &jright,      0);
-    OPTENT3(0, "jcenter",    OPT_FLAG,   NULL, &jcenter,     0);
-
-    opt.opt_table = option_def;
-    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
-    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
-
-    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
-        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
-
-    free(option_def);
-
-    if (leftright + topbottom > 1)
-        pm_error("You may specify only one of -topbottom (-tb) and "
-                 "-leftright (-lr)");
-    else if (leftright)
-        cmdlineP->orientation = LEFTRIGHT;
-    else if (topbottom)
-        cmdlineP->orientation = TOPBOTTOM;
-    else
-        pm_error("You must specify either -leftright or -topbottom");
-
-    if (black + white > 1)
-        pm_error("You may specify only one of -black and -white");
-    else if (black)
-        cmdlineP->backcolor = BACK_BLACK;
-    else if (white)
-        cmdlineP->backcolor = BACK_WHITE;
-    else
-        cmdlineP->backcolor = BACK_AUTO;
-
-    if (jtop + jbottom + jleft + jright + jcenter > 1)
-        pm_error("You may specify onlyone of -jtop, -jbottom, "
-                 "-jleft, and -jright");
-    else {
-        switch (cmdlineP->orientation) {
-        case LEFTRIGHT:
-            if (jleft)
-                pm_error("-jleft is invalid with -leftright");
-            if (jright)
-                pm_error("-jright is invalid with -leftright");
-            if (jtop)
-                cmdlineP->justification = JUST_MIN;
-            else if (jbottom)
-                cmdlineP->justification = JUST_MAX;
-            else if (jcenter)
-                cmdlineP->justification = JUST_CENTER;
-            else
-                cmdlineP->justification = JUST_CENTER;
-            break;
-        case TOPBOTTOM:
-            if (jtop)
-                pm_error("-jtop is invalid with -topbottom");
-            if (jbottom)
-                pm_error("-jbottom is invalid with -topbottom");
-            if (jleft)
-                cmdlineP->justification = JUST_MIN;
-            else if (jright)
-                cmdlineP->justification = JUST_MAX;
-            else if (jcenter)
-                cmdlineP->justification = JUST_CENTER;
-            else
-                cmdlineP->justification = JUST_CENTER;
-            break;
-        }
-    }
-
-    if (argc-1 < 1) {
-        MALLOCARRAY_NOFAIL(cmdlineP->inputFilespec, 1);
-        cmdlineP->inputFilespec[0] = "-";
-        cmdlineP->nfiles = 1;
-    } else {
-        unsigned int i;
-        unsigned int stdinCt;
-            /* Number of input files user specified as Standard Input */
-
-        MALLOCARRAY_NOFAIL(cmdlineP->inputFilespec, argc-1);
-
-        for (i = 0, stdinCt = 0; i < argc-1; ++i) {
-            cmdlineP->inputFilespec[i] = argv[1+i];
-            if (streq(argv[1+i], "-"))
-                ++stdinCt;
-        }
-        cmdlineP->nfiles = argc-1;
-        if (stdinCt > 1)
-            pm_error("At most one input image can come from Standard Input.  "
-                     "You specified %u", stdinCt);
-    }
-}
-
-
-
-static void
-computeOutputParms(unsigned int     const nfiles,
-                   enum orientation const orientation,
-                   struct imgInfo   const img[],
-                   unsigned int *   const newcolsP,
-                   unsigned int *   const newrowsP,
-                   xelval *         const newmaxvalP,
-                   int *            const newformatP) {
-
-    double newcols, newrows;
-    int newformat;
-    xelval newmaxval;
-
-    unsigned int i;
-
-    newcols = 0;
-    newrows = 0;
-
-    for (i = 0; i < nfiles; ++i) {
-        const struct imgInfo * const imgP = &img[i];
-
-        if (i == 0) {
-            newmaxval = imgP->maxval;
-            newformat = imgP->format;
-        } else {
-            if (PNM_FORMAT_TYPE(imgP->format) > PNM_FORMAT_TYPE(newformat))
-                newformat = imgP->format;
-            if (imgP->maxval > newmaxval)
-                newmaxval = imgP->maxval;
-        }
-        switch (orientation) {
-        case LEFTRIGHT:
-            newcols += imgP->cols;
-            if (imgP->rows > newrows)
-                newrows = imgP->rows;
-            break;
-        case TOPBOTTOM:
-            newrows += imgP->rows;
-            if (imgP->cols > newcols)
-                newcols = imgP->cols;
-            break;
-        }
-    }
-
-    /* Note that while 'double' is not in general a precise numerical type,
-       in the case of a sum of integers which is less than INT_MAX, it
-       is exact, because double's precision is greater than int's.
-    */
-    if (newcols > INT_MAX)
-       pm_error("Output width too large: %.0f.", newcols);
-    if (newrows > INT_MAX)
-       pm_error("Output height too large: %.0f.", newrows);
-
-    *newrowsP   = (unsigned int)newrows;
-    *newcolsP   = (unsigned int)newcols;
-    *newmaxvalP = newmaxval;
-    *newformatP = newformat;
-}
-
-
-
-static void
-copyBitrow(const unsigned char * const source,
-           unsigned char *       const destBitrow,
-           unsigned int          const cols,
-           unsigned int          const offset) {
-/*----------------------------------------------------------------------------
-  Copy from source to destBitrow, without shifting.  Preserve
-  surrounding image data.
------------------------------------------------------------------------------*/
-    unsigned char * const dest = & destBitrow[ offset/8 ];
-        /* Copy destination, with leading full bytes ignored. */
-    unsigned int const rs = offset % 8;
-        /* The "little offset", as measured from start of dest.  Source
-           is already shifted by this value.
-        */
-    unsigned int const trs = (cols + rs) % 8;
-        /* The number of partial bits in the final char. */
-    unsigned int const colByteCnt = pbm_packed_bytes(cols + rs);
-        /* # bytes to process, including partial ones on both ends. */
-    unsigned int const last = colByteCnt - 1;
-
-    unsigned char const origHead = dest[0];
-    unsigned char const origEnd  = dest[last];
-
-    unsigned int i;
-
-    assert(colByteCnt >= 1);
-
-    for (i = 0; i < colByteCnt; ++i)
-        dest[i] = source[i];
-
-    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);
-}
-
-
-
-static void
-padFillBitrow(unsigned char * const destBitrow,
-              unsigned char   const padColor,
-              unsigned int    const cols,
-              unsigned int    const offset) {
-/*----------------------------------------------------------------------------
-   Fill destBitrow, starting at offset, with padColor.  padColor is a
-   byte -- 0x00 or 0xff -- not a single bit.
------------------------------------------------------------------------------*/
-    unsigned char * const dest = &destBitrow[offset/8];
-    unsigned int const rs = offset % 8;
-    unsigned int const trs = (cols + rs) % 8;
-    unsigned int const colByteCnt = pbm_packed_bytes(cols + rs);
-    unsigned int const last = colByteCnt - 1;
-
-    unsigned char const origHead = dest[0];
-    unsigned char const origEnd  = dest[last];
-
-    unsigned int i;
-
-    assert(colByteCnt > 0);
-
-    for (i = 0; i < colByteCnt; ++i)
-        dest[i] = padColor;
-
-    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);
-}
-
-
-
-/* concatenateLeftRightPBM() and concatenateLeftRightGen()
-   employ almost identical algorithms.
-   The difference is in the data types and functions.
-
-   Same for concatenateTopBottomPBM() and concatenateTopBottomGen().
-*/
-
-
-struct imgInfoPbm2 {
-    /* Information about one image */
-    unsigned char * proberow;
-        /* Top row of image, when background color is
-           auto-determined.
-        */
-    unsigned int offset;
-        /* start position of image, in bits, counting from left
-           edge
-        */
-    unsigned char background;
-        /* Background color.  0x00 means white; 0xff means black */
-    unsigned int padtop;
-        /* Top padding amount */
-};
-
-
-
-static void
-getPbmImageInfo(struct imgInfo        const img[],
-                unsigned int          const nfiles,
-                unsigned int          const newrows,
-                enum justification    const justification,
-                enum backcolor        const backcolor,
-                struct imgInfoPbm2 ** const img2P) {
-/*----------------------------------------------------------------------------
-   Read the first row of each image in img[] and return that and additional
-   information about images as *img2P.
------------------------------------------------------------------------------*/
-    struct imgInfoPbm2 * img2;
-    unsigned int i;
-
-    MALLOCARRAY_NOFAIL(img2, nfiles);
-
-    for (i = 0; i < nfiles; ++i) {
-        switch (justification) {
-        case JUST_MIN:    img2[i].padtop = 0;                           break;
-        case JUST_MAX:    img2[i].padtop = newrows - img[i].rows;       break;
-        case JUST_CENTER: img2[i].padtop = (newrows - img[i].rows) / 2; break;
-        }
-        
-        img2[i].offset = (i == 0) ? 0 : img2[i-1].offset + img[i-1].cols;
-        
-        if (img[i].rows == newrows)  /* no padding */
-            img2[i].proberow = NULL;
-        else {                   /* determine pad color for image i */
-            switch (backcolor) {
-            case BACK_AUTO: {
-                bit bgBit;
-                img2[i].proberow =
-                    pbm_allocrow_packed((unsigned int)img[i].cols + 7);
-                pbm_readpbmrow_bitoffset(
-                    img[i].ifP, img2[i].proberow,
-                    img[i].cols, img[i].format, img2[i].offset % 8);
-
-                bgBit = pbm_backgroundbitrow(
-                    img2[i].proberow, img[i].cols, img2[i].offset % 8);
-
-                img2[i].background = bgBit == PBM_BLACK ? 0xff : 0x00;
-            } break;
-            case BACK_BLACK:
-                img2[i].proberow   = NULL;
-                img2[i].background = 0xff;
-                break;
-            case BACK_WHITE:
-                img2[i].proberow   = NULL;
-                img2[i].background = 0x00;
-                break;
-            }
-        }
-    }
-    *img2P = img2;
-}
-
-
-
-static void
-destroyPbmImg2(struct imgInfoPbm2 * const img2,
-               unsigned int         const nfiles) {
-
-    unsigned int i;
-
-    for (i = 0; i < nfiles; ++i) {
-        if (img2[i].proberow)
-            free(img2[i].proberow);
-    }
-    free(img2);
-}
-
-
-
-static void
-concatenateLeftRightPbm(FILE *             const ofP,
-                        unsigned int       const nfiles,
-                        unsigned int       const newcols,
-                        unsigned int       const newrows,
-                        enum justification const justification,
-                        struct imgInfo     const img[],   
-                        enum backcolor     const backcolor) {
-
-    unsigned char * const outrow = pbm_allocrow_packed(newcols);
-        /* We use just one outrow.  All padding and image data (with the
-           exeption of following img2.proberow) goes directly into this
-           packed PBM row. 
-        */
-
-    struct imgInfoPbm2 * img2;
-        /* malloc'ed array, one element per image.  Shadows img[] */
-    unsigned int row;
-
-    getPbmImageInfo(img, nfiles, newrows, justification, backcolor, &img2);
-
-    outrow[pbm_packed_bytes(newcols)-1] = 0x00;
-
-    for (row = 0; row < newrows; ++row) {
-        unsigned int i;
-
-        for (i = 0; i < nfiles; ++i) {
-
-            if ((row == 0 && img2[i].padtop > 0) ||
-                row == img2[i].padtop + img[i].rows) {
-
-                /* This row begins a run of padding, either above or below
-                   file 'i', so set 'outrow' to padding.
-                */
-                padFillBitrow(outrow, img2[i].background, img[i].cols,
-                              img2[i].offset);
-            }
-
-            if (row == img2[i].padtop && img2[i].proberow != NULL) {
-                /* Top row has been read to proberow[] to determine
-                   background.  Copy it to outrow[].
-                */
-                copyBitrow(img2[i].proberow, outrow,
-                           img[i].cols, img2[i].offset);
-            } else if (row >= img2[i].padtop &&
-                       row < img2[i].padtop + img[i].rows) {
-                pbm_readpbmrow_bitoffset(
-                    img[i].ifP, outrow, img[i].cols, img[i].format,
-                    img2[i].offset);
-            } else {
-                /* It's a row of padding, so outrow[] is already set
-                   appropriately.
-                */
-            }
-        }
-        pbm_writepbmrow_packed(ofP, outrow, newcols, 0);
-    }
-
-    destroyPbmImg2(img2, nfiles);
-
-    pbm_freerow_packed(outrow);
-}
-
-
-
-static void
-concatenateTopBottomPbm(FILE *             const ofP,
-                        unsigned int       const nfiles,
-                        int                const newcols,
-                        int                const newrows,
-                        enum justification const justification,
-                        struct imgInfo     const img[],
-                        enum backcolor     const backcolor) {
-
-    unsigned char * const outrow = pbm_allocrow_packed(newcols);
-        /* Like the left-right PBM case, all padding and image data
-           goes directly into outrow.  There is no proberow.
-        */
-    unsigned char background, backgroundPrev;
-        /* 0x00 means white; 0xff means black */
-    unsigned int  padleft;
-    bool          backChange;
-        /* Background color is different from that of the previous
-           input image.
-        */
-
-    unsigned int i;
-    unsigned int row, startRow;
-    
-    outrow[pbm_packed_bytes(newcols)-1] = 0x00;
-
-    switch (backcolor){
-    case BACK_AUTO:   /* do nothing */    break;
-    case BACK_BLACK:  background = 0xff;  break;
-    case BACK_WHITE:  background = 0x00;  break;
-    }
-
-    for (i = 0; i < nfiles; ++i) {
-        if (img[i].cols == newcols) {
-            /* No padding */
-            startRow = 0;
-            backChange = FALSE;
-            padleft = 0;
-            outrow[pbm_packed_bytes(newcols)-1] = 0x00;
-        } else {
-            /* Determine amount of padding and color */
-            switch (justification) {
-            case JUST_MIN:     padleft = 0;                           break;
-            case JUST_MAX:     padleft = newcols - img[i].cols;       break;
-            case JUST_CENTER:  padleft = (newcols - img[i].cols) / 2; break;
-            }
-
-            switch (backcolor) {
-            case BACK_AUTO: {
-                bit bgBit;
-
-                startRow = 1;
-                
-                pbm_readpbmrow_bitoffset(img[i].ifP,
-                                         outrow, img[i].cols, img[i].format,
-                                         padleft);
-
-                bgBit = pbm_backgroundbitrow(outrow, img[i].cols, padleft);
-                background = bgBit == PBM_BLACK ? 0xff : 0x00;
-
-                backChange = (i == 0 || background != backgroundPrev);
-            } break;
-            case BACK_WHITE:
-            case BACK_BLACK:
-                startRow = 0;
-                backChange = (i==0);
-                break;
-            }
-
-            if (backChange || (i > 0 && img[i-1].cols > img[i].cols)) {
-                unsigned int const padright = newcols - padleft - img[i].cols;
-                
-                if (padleft > 0)
-                    padFillBitrow(outrow, background, padleft, 0);
-                
-                if (padright > 0)            
-                    padFillBitrow(outrow, background, padright,
-                                  padleft + img[i].cols);
-                
-            }
-        }
-            
-        if (startRow == 1)
-            /* Top row already read for auto background color
-               determination.  Write it out.
-            */
-            pbm_writepbmrow_packed(ofP, outrow, newcols, 0);
-        
-        for (row = startRow; row < img[i].rows; ++row) {
-            pbm_readpbmrow_bitoffset(img[i].ifP, outrow, img[i].cols,
-                                     img[i].format, padleft);
-            pbm_writepbmrow_packed(ofP, outrow, newcols, 0);
-        }
-
-        backgroundPrev = background;
-    }
-    pbm_freerow_packed(outrow);
-}
-
-
-
-struct imgGen2 {
-    xel * xelrow;
-    xel * inrow;
-    xel   background;
-    int   padtop;
-};
-
-
-
-static void
-getGenImgInfo(struct imgInfo     const img[],
-              unsigned int       const nfiles,
-              xel *              const newxelrow,
-              unsigned int       const newrows,
-              xelval             const newmaxval,
-              int                const newformat,
-              enum justification const justification,
-              enum backcolor     const backcolor,
-              struct imgGen2 **  const img2P) {
-
-    struct imgGen2 * img2;
-    unsigned int i;
-
-    MALLOCARRAY_NOFAIL(img2, nfiles);
-
-    for (i = 0; i < nfiles; ++i) {
-        switch (justification) {  /* Determine top padding */
-            case JUST_MIN:
-                img2[i].padtop = 0;
-                break;
-            case JUST_MAX:
-                img2[i].padtop = newrows - img[i].rows;
-                break;
-            case JUST_CENTER:
-                img2[i].padtop = (newrows - img[i].rows) / 2;
-                break;
-        }
-
-        img2[i].inrow =
-            (i == 0 ? &newxelrow[0] : img2[i-1].inrow + img[i-1].cols);
-
-        if (img[i].rows == newrows)  /* no padding */
-            img2[i].xelrow = NULL;
-        else {
-            /* Determine pad color */
-            switch (backcolor){
-            case BACK_AUTO:
-                img2[i].xelrow = pnm_allocrow(img[i].cols);
-                pnm_readpnmrow(img[i].ifP, img2[i].xelrow,
-                               img[i].cols, img[i].maxval, img[i].format);
-                pnm_promoteformatrow(img2[i].xelrow, img[i].cols,
-                                     img[i].maxval, img[i].format,
-                                     newmaxval, newformat);
-                img2[i].background = pnm_backgroundxelrow(
-                    img2[i].xelrow, img[i].cols, newmaxval, newformat);
-                break;
-            case BACK_BLACK:
-                img2[i].xelrow = NULL;
-                img2[i].background = pnm_blackxel(newmaxval, newformat);
-                break;
-            case BACK_WHITE:
-                img2[i].xelrow = NULL;
-                img2[i].background = pnm_whitexel(newmaxval, newformat);
-                break;
-            }
-        }
-    }
-    *img2P = img2;
-}
-
-
-
-static void
-concatenateLeftRightGen(FILE *             const ofP,
-                        unsigned int       const nfiles,
-                        unsigned int       const newcols,
-                        unsigned int       const newrows,
-                        xelval             const newmaxval,
-                        int                const newformat,
-                        enum justification const justification,
-                        struct imgInfo     const img[],
-                        enum backcolor     const backcolor) {
-
-    xel * const outrow = pnm_allocrow(newcols);
-    struct imgGen2 * img2;
-    unsigned int row;
-
-    getGenImgInfo(img, nfiles, outrow, newrows,
-                  newmaxval, newformat, justification, backcolor, &img2);
-
-    for (row = 0; row < newrows; ++row) {
-        unsigned int i;
-
-        for (i = 0; i < nfiles; ++i) {
-            if ((row == 0 && img2[i].padtop > 0) ||
-                row == img2[i].padtop + img[i].rows) {
-                /* This row begins a run of padding, either above or below
-                   file 'i', so set 'outrow' to padding.
-                */
-                unsigned int col;
-                for (col = 0; col < img[i].cols; ++col)
-                    img2[i].inrow[col] = img2[i].background;
-            }
-            if (row == img2[i].padtop && img2[i].xelrow) {
-                /* We're at the top row of file 'i', and that row
-                   has already been read to xelrow[] to determine
-                   background.  Copy it to 'outrow'.
-                */
-                unsigned int col;
-                for (col = 0; col < img[i].cols; ++col)
-                    img2[i].inrow[col] = img2[i].xelrow[col];
-                
-                free(img2[i].xelrow);
-            } else if (row >= img2[i].padtop &&
-                       row < img2[i].padtop + img[i].rows) {
-                pnm_readpnmrow(
-                    img[i].ifP, img2[i].inrow, img[i].cols, img[i].maxval,
-                    img[i].format);
-                pnm_promoteformatrow(
-                    img2[i].inrow, img[i].cols, img[i].maxval,
-                    img[i].format, newmaxval, newformat);
-            } else {
-                /* It's a row of padding, so outrow[] is already set
-                   appropriately.
-                */
-            }
-        }
-        pnm_writepnmrow(ofP, outrow, newcols, newmaxval, newformat, 0);
-    }
-    pnm_freerow(outrow);
-}
-
-
-
-static void
-concatenateTopBottomGen(FILE *             const ofP,
-                        unsigned int       const nfiles,
-                        int                const newcols,
-                        int                const newrows,
-                        xelval             const newmaxval,
-                        int                const newformat,
-                        enum justification const justification,
-                        struct imgInfo     const img[],
-                        enum backcolor     const backcolor) {
-
-    xel * const newxelrow = pnm_allocrow(newcols);
-    xel * inrow;
-    unsigned int padleft;
-    unsigned int i;
-    unsigned int row, startRow;
-    xel background, backgroundPrev;
-    bool backChange;
-        /* The background color is different from that of the previous
-           input image.
-        */
-
-    switch (backcolor) {
-    case BACK_AUTO: /* do nothing now, determine at start of each image */
-                     break;
-    case BACK_BLACK: background = pnm_blackxel(newmaxval, newformat);
-                     break;
-    case BACK_WHITE: background = pnm_whitexel(newmaxval, newformat);
-                     break;
-    }
-
-    for ( i = 0; i < nfiles; ++i, backgroundPrev = background) {
-        if (img[i].cols == newcols) {
-            /* no padding */
-            startRow = 0;
-            backChange = FALSE;
-            inrow = newxelrow;
-        } else { /* Calculate left padding amount */ 
-            switch (justification) {
-            case JUST_MIN:    padleft = 0;                            break;
-            case JUST_MAX:    padleft = newcols - img[i].cols;        break;
-            case JUST_CENTER: padleft = (newcols - img[i].cols) / 2;  break;
-            }
-
-            if (backcolor == BACK_AUTO) {
-                /* Determine background color */
-
-                startRow = 1;
-                inrow = &newxelrow[padleft];
-
-                pnm_readpnmrow(img[i].ifP, inrow,
-                               img[i].cols, img[i].maxval, img[i].format);
-                pnm_promoteformatrow(inrow, img[i].cols, img[i].maxval,
-                                     img[i].format,
-                                     newmaxval, newformat);
-                background = pnm_backgroundxelrow(
-                    inrow, img[i].cols, newmaxval, newformat);
-
-                backChange = i==0 || !PNM_EQUAL(background, backgroundPrev);
-            } else {
-                /* background color is constant: black or white */
-                startRow = 0;
-                inrow = &newxelrow[padleft];
-                backChange = (i==0);
-            }
-
-            if (backChange || (i > 0 && img[i-1].cols > img[i].cols)) {
-                unsigned int col;
-
-                for (col = 0; col < padleft; ++col)
-                    newxelrow[col] = background;
-                for (col = padleft + img[i].cols; col < newcols; ++col)
-                    newxelrow[col] = background;
-            }
-        }
-
-        if (startRow == 1)
-            /* Top row already read for auto background
-               color determination.  Write it out. */
-            pnm_writepnmrow(ofP, newxelrow, newcols, newmaxval, newformat, 0);
-
-        for (row = startRow; row < img[i].rows; ++row) {
-            pnm_readpnmrow(img[i].ifP,
-                           inrow, img[i].cols, img[i].maxval, img[i].format);
-            pnm_promoteformatrow(
-                inrow, img[i].cols, img[i].maxval, img[i].format,
-                newmaxval, newformat);
-
-            pnm_writepnmrow(ofP, newxelrow, newcols, newmaxval, newformat, 0);
-        }
-    }
-    pnm_freerow(newxelrow);
-}
-
-
-
-int
-main(int           argc,
-     const char ** argv) {
-
-    struct cmdlineInfo cmdline;
-    struct imgInfo * img;  /* malloc'ed array */
-    xelval newmaxval;
-    int newformat;
-    unsigned int i;
-    unsigned int newrows, newcols;
-
-    pm_proginit(&argc, argv);
-
-    parseCommandLine(argc, argv, &cmdline);
-
-    MALLOCARRAY_NOFAIL(img, cmdline.nfiles);
-
-    for (i = 0; i < cmdline.nfiles; ++i) {
-        img[i].ifP = pm_openr(cmdline.inputFilespec[i]);
-        pnm_readpnminit(img[i].ifP, &img[i].cols, &img[i].rows,
-                        &img[i].maxval, &img[i].format);
-    }
-
-    computeOutputParms(cmdline.nfiles, cmdline.orientation, img,
-                       &newcols, &newrows, &newmaxval, &newformat);
-
-    pnm_writepnminit(stdout, newcols, newrows, newmaxval, newformat, 0);
-
-    if (PNM_FORMAT_TYPE(newformat) == PBM_TYPE) {
-        switch (cmdline.orientation) {
-        case LEFTRIGHT:
-            concatenateLeftRightPbm(stdout, cmdline.nfiles,
-                                    newcols, newrows, cmdline.justification,
-                                    img, cmdline.backcolor);
-            break;
-        case TOPBOTTOM:
-            concatenateTopBottomPbm(stdout, cmdline.nfiles,
-                                    newcols, newrows, cmdline.justification,
-                                    img, cmdline.backcolor);
-            break;
-        }
-    } else {
-        switch (cmdline.orientation) {
-        case LEFTRIGHT:
-            concatenateLeftRightGen(stdout, cmdline.nfiles,
-                                    newcols, newrows, newmaxval, newformat,
-                                    cmdline.justification, img,
-                                    cmdline.backcolor);
-            break;
-        case TOPBOTTOM:
-            concatenateTopBottomGen(stdout, cmdline.nfiles,
-                                    newcols, newrows, newmaxval, newformat,
-                                    cmdline.justification, img,
-                                    cmdline.backcolor);
-            break;
-        }
-    }
-    for (i = 0; i < cmdline.nfiles; ++i)
-        pm_close(img[i].ifP);
-    free(cmdline.inputFilespec);
-    free(img);
-    pm_close(stdout);
-
-    return 0;
-}
diff --git a/editor/pnmconvol.c b/editor/pnmconvol.c
index b1d8e025..fcd52bea 100644
--- a/editor/pnmconvol.c
+++ b/editor/pnmconvol.c
@@ -1314,7 +1314,7 @@ computeInitialColumnSums(struct pam *              const pamP,
                          sample **                 const convColumnSum) {
 /*----------------------------------------------------------------------------
   Add up the sum of each column of window[][], whose rows are described
-  by *inpamP.  The window's height is that of tthe convolution kernel
+  by *inpamP.  The window's height is that of the convolution kernel
   *convKernelP.
 
   Return it as convColumnSum[][].
@@ -1854,7 +1854,7 @@ convolveHorizontalRowPlane(struct pam *              const pamP,
                            pamP->maxval);
         } else if (col == ccolso2) {
             unsigned int const leftcol = 0;
-                /* Window is up againt left edge of image */
+                /* Window is up against left edge of image */
 
             {
                 unsigned int ccol;
@@ -2019,7 +2019,7 @@ convolveVerticalRowPlane(struct pam *              const pamP,
 
             if (col == ccolso2) {
                 unsigned int const leftcol = 0;
-                    /* Convolution window is againt left edge of image */
+                    /* Convolution window is against left edge of image */
 
                 unsigned int ccol;
 
diff --git a/editor/pnmcrop.c b/editor/pnmcrop.c
index d6bae1d3..43027da0 100644
--- a/editor/pnmcrop.c
+++ b/editor/pnmcrop.c
@@ -454,7 +454,9 @@ backgroundColor(FILE *         const ifP,
    *ifP, which is described by 'cols', 'rows', 'maxval', and 'format'.
 
    'backgroundChoice' is the method we are to use in determining the
-   background color.
+   background color.  'colorName' is the color we are to assume is
+   background in the case that 'backgroundChoice' says to use a particular
+   color and meangingless otherwise.
 
    Expect the file to be positioned to the start of the raster, and leave
    it positioned arbitrarily.
@@ -484,9 +486,6 @@ backgroundColor(FILE *         const ifP,
         background =
             background1Corner(ifP, rows, cols, maxval, format, corner);
         break;
-
-    default:
-        pm_error("internal error");
     }
 
     return background;
@@ -1124,63 +1123,135 @@ noCrops(struct CmdlineInfo const cmdline) {
 
 
 
+static void
+divideAllBackgroundIntoBorders(unsigned int   const totalSz,
+                               bool           const wantCropSideA,
+                               bool           const wantCropSideB,
+                               unsigned int   const wantMargin,
+                               unsigned int * const sideASzP,
+                               unsigned int * const sideBSzP) {
+/*----------------------------------------------------------------------------
+   Divide up an all-background space into fictional borders (that can be
+   trimmed or padded).
+
+   If there is to be a margin, those borders touch - the entire image is
+   borders.  But if there is not to be a margin, there has to be one pixel,
+   row, or column between the borders so that there is something left after we
+   crop off those borders (because there's no such thing as a zero-pixel
+   image).
+
+   This function does the borders in one direction - top and bottom or left
+   and right.  Top or left is called "Side A"; bottom or right is called "Side
+   B".  'totalSz' is the width of the image in the top/bottom case and the
+   height of the image in the left/right case.
+-----------------------------------------------------------------------------*/
+    unsigned int sideASz, sideBSz;
+
+    if (wantCropSideA && wantCropSideB) {
+        sideASz = totalSz/2;
+        if (wantMargin)
+            sideBSz = totalSz - sideASz;
+        else
+            sideBSz = totalSz - sideASz - 1;
+    } else if (wantCropSideA) {
+        if (wantMargin)
+            sideASz = totalSz;
+        else
+            sideASz = totalSz - 1;
+        sideBSz = 0;
+    } else if (wantCropSideB) {
+        sideASz = 0;
+        if (wantMargin)
+            sideBSz = totalSz;
+        else
+            sideBSz = totalSz - 1;
+    } else {
+        sideASz = 0;
+        sideBSz = 0;
+    }
+    *sideASzP = sideASz;
+    *sideBSzP = sideBSz;
+}
+
+
+
+static CropOp
+oneSideCrop(bool         const wantCrop,
+            unsigned int const borderSz,
+            unsigned int const margin) {
+
+    CropOp retval;
+
+    if (wantCrop) {
+        if (borderSz >= margin) {
+            retval.removeSize = borderSz - margin;
+            retval.padSize    = 0;
+        } else {
+            retval.removeSize = 0;
+            retval.padSize    = margin - borderSz;
+        }
+    } else {
+        retval.removeSize = 0;
+        retval.padSize    = 0;
+    }
+
+    return retval;
+}
+
+
+
 static CropSet
 extremeCrops(struct CmdlineInfo const cmdline,
              unsigned int       const cols,
              unsigned int       const rows) {
 /*----------------------------------------------------------------------------
-   Crops that crop as much as possible, reducing output to a single pixel.
+   Crops that crop as much as possible, reducing output to a single
+   row, column, or pixel, plus margins.
 -----------------------------------------------------------------------------*/
     CropSet retval;
 
+    unsigned int leftBorderSz, rghtBorderSz;
+    unsigned int topBorderSz, botBorderSz;
+
     if (cmdline.verbose)
         pm_message("Input image has no distinction between "
                    "border and content");
 
-    /* We can't just pick a representive pixel, say top-left corner.
-       If -top and/or -bottom was specified but not -left and -right,
-       the output should be one row, not a single pixel.
+    /* Note that the "entirely background" image may have several colors: this
+       happens when -closeness was specified.  That means we can't just build
+       up an image from background color - we actually have to preserve some
+       of the original image.
 
-       The "entirely background" image may have several colors: this
-       happens when -closeness was specified.
+       We divide the background into individual borders, with a foreground of
+       either nothing at all or a single row, column, or pixel, then crop
+       those fictional borders the same as if they were real.  The "nothing
+       at all" case is feasible only when there is to be a margin, because
+       otherwise cropping the borders would leave nothing.
     */
 
-    if (cmdline.wantCrop[LEFT] && cmdline.wantCrop[RIGHT]) {
-        retval.op[LEFT ].removeSize = cols / 2;
-        retval.op[RIGHT].removeSize = cols - retval.op[LEFT].removeSize -1;
-    } else if (cmdline.wantCrop[LEFT]) {
-        retval.op[LEFT ].removeSize = cols - 1;
-        retval.op[RIGHT].removeSize = 0;
-    } else if (cmdline.wantCrop[RIGHT]) {
-        retval.op[LEFT ].removeSize = 0;
-        retval.op[RIGHT].removeSize = cols - 1;
-    } else {
-        retval.op[LEFT ].removeSize = 0;
-        retval.op[RIGHT].removeSize = 0;
-    }
+    divideAllBackgroundIntoBorders(cols,
+                                   cmdline.wantCrop[LEFT],
+                                   cmdline.wantCrop[RIGHT],
+                                   cmdline.margin > 0,
+                                   &leftBorderSz,
+                                   &rghtBorderSz);
+
+    divideAllBackgroundIntoBorders(rows,
+                                   cmdline.wantCrop[TOP],
+                                   cmdline.wantCrop[BOTTOM],
+                                   cmdline.margin > 0,
+                                   &topBorderSz,
+                                   &botBorderSz);
+
+    retval.op[LEFT  ] =
+        oneSideCrop(cmdline.wantCrop[LEFT  ], leftBorderSz, cmdline.margin);
+    retval.op[RIGHT ] =
+        oneSideCrop(cmdline.wantCrop[RIGHT ], rghtBorderSz, cmdline.margin);
+    retval.op[TOP   ] =
+        oneSideCrop(cmdline.wantCrop[TOP   ], topBorderSz,  cmdline.margin);
+    retval.op[BOTTOM] =
+        oneSideCrop(cmdline.wantCrop[BOTTOM], botBorderSz,  cmdline.margin);
 
-    if (cmdline.wantCrop[TOP] && cmdline.wantCrop[BOTTOM]) {
-        retval.op[ TOP  ].removeSize = rows / 2;
-        retval.op[BOTTOM].removeSize = rows - retval.op[TOP].removeSize -1;
-    } else if (cmdline.wantCrop[TOP]) {
-        retval.op[ TOP  ].removeSize = rows - 1;
-        retval.op[BOTTOM].removeSize = 0;
-    } else if (cmdline.wantCrop[BOTTOM]) {
-        retval.op[ TOP  ].removeSize = 0;
-        retval.op[BOTTOM].removeSize = rows - 1;
-    } else {
-        retval.op[ TOP  ].removeSize = 0;
-        retval.op[BOTTOM].removeSize = 0;
-    }
-
-    if (cmdline.margin > 0)
-        pm_message ("-margin value %u ignored", cmdline.margin);
-
-    {
-        EdgeLocation i;
-        for (i = 0; i < ARRAY_SIZE(retval.op); ++i)
-            retval.op[i].padSize = 0;
-    }
     return retval;
 }
 
@@ -1265,9 +1336,9 @@ cropOneImage(struct CmdlineInfo const cmdline,
              FILE *             const bdfP,
              FILE *             const ofP) {
 /*----------------------------------------------------------------------------
-   Crop the image to which the stream *ifP is presently positioned
+   Crop the image to which the stream *ifP is currently positioned
    and write the results to *ofP.  If bdfP is non-null, use the image
-   to which stream *bdfP is presently positioned as the borderfile
+   to which stream *bdfP is currently positioned as the borderfile
    (the file that tells us where the existing borders are in the input
    image).  Leave *ifP and *bdfP positioned after the image.
 
@@ -1330,12 +1401,9 @@ cropOneImage(struct CmdlineInfo const cmdline,
             pm_error("The image is entirely background; "
                      "there is nothing to crop.");
             break;
-        case BLANK_PASS:
-            crop = noCrops(cmdline);                   break;
-        case BLANK_MINIMIZE:
-            crop = extremeCrops(cmdline, cols, rows);  break;
-        case BLANK_MAXCROP:
-            crop = maxcropReport(cmdline, cols, rows); break;
+        case BLANK_PASS:     crop = noCrops(cmdline);                   break;
+        case BLANK_MINIMIZE: crop = extremeCrops(cmdline, cols, rows);  break;
+        case BLANK_MAXCROP:  crop = maxcropReport(cmdline, cols, rows); break;
         }
     } else {
         crop = crops(cmdline, oldBorder);
diff --git a/editor/pnmflip b/editor/pnmflip
index 07d4ddb9..962198a2 100755
--- a/editor/pnmflip
+++ b/editor/pnmflip
@@ -46,6 +46,13 @@ exec perl -w -x -S -- "$0" "$@"
 use strict;
 use File::Basename;
 use Cwd 'abs_path';
+use IO::Handle;
+
+sub pm_message($) {
+    STDERR->print("pnmflip: $_[0]\n");
+}
+
+
 
 my $xformOpt;
 my @miscOptions;
@@ -78,8 +85,7 @@ foreach (@ARGV) {
     } else {
         # It's a parameter
         if (defined($infile)) {
-            print(STDERR
-                  "You may specify at most one non-option parameter.\n");
+            pm_message("You may specify at most one non-option parameter.");
             exit(10);
         } else {
             $infile = $_;
diff --git a/editor/pnmgamma.c b/editor/pnmgamma.c
index 0ed217d1..e10e138b 100644
--- a/editor/pnmgamma.c
+++ b/editor/pnmgamma.c
@@ -602,7 +602,7 @@ createGammaTables(enum transferFunction const transferFunction,
     if (*rtableP == NULL || *gtableP == NULL || *btableP == NULL)
         pm_error("Can't get memory to make gamma transfer tables");
 
-    /* Build the gamma corection tables. */
+    /* Build the gamma correction tables. */
     switch (transferFunction) {
     case XF_BT709RAMP: {
         buildBt709Gamma(*rtableP, maxval, newMaxval, rgamma);
diff --git a/editor/pnmindex.csh b/editor/pnmindex.csh
deleted file mode 100755
index c6f1e844..00000000
--- a/editor/pnmindex.csh
+++ /dev/null
@@ -1,189 +0,0 @@
-#!/bin/csh -f
-#
-# pnmindex - build a visual index of a bunch of anymaps
-#
-# Copyright (C) 1991 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.
-
-# -title and -quant added by John Heidemann 13-Sep-00.
-
-set size=100		# make the images about this big
-set across=6		# show this many images per row
-set colors=256		# quantize results to this many colors
-set back="-white"	# default background color
-set doquant=true	# quantize or not
-set title=""		# default title (none)
-
-while ( 1 )
-    switch ( "$1" )
-
-	case -s*:
-	if ( $#argv < 2 ) goto usage
-	set size="$2"
-	shift
-	shift
-	breaksw
-
-	case -a*:
-	if ( $#argv < 2 ) goto usage
-	set across="$2"
-	shift
-	shift
-	breaksw
-
-	case -t*:
-	if ( $#argv < 2 ) goto usage
-	set title="$2"
-	shift
-	shift
-	breaksw
-
-	case -c*:
-	set colors="$2"
-	shift
-	shift
-	breaksw
-
-	case -noq*:
-	set doquant=false
-	shift
-	breaksw
-
-	case -q*:
-	set doquant=true
-	shift
-	breaksw
-
-	case -b*:
-	set back="-black"
-	shift
-	breaksw
-
-	case -w*:
-	set back="-white"
-	shift
-	breaksw
-
-	case -*:
-	goto usage
-	breaksw
-
-	default:
-	break
-	breaksw
-
-    endsw
-end
-
-if ( $#argv == 0 ) then
-    goto usage
-endif
-
-set tmpfile=/tmp/pi.tmp.$$
-rm -f $tmpfile
-set maxformat=PBM
-
-set rowfiles=()
-set imagefiles=()
-@ row = 1
-@ col = 1
-
-if ( "$title" != "" ) then
-    set rowfile=/tmp/pi.${row}.$$
-    rm -f $rowfile
-    pbmtext "$title" > $rowfile
-    set rowfiles=( $rowfiles $rowfile )
-    @ row += 1
-endif
-
-foreach i ( $argv )
-
-    set description=`pnmfile $i`
-    if ( $description[4] <= $size && $description[6] <= $size ) then
-	cat $i > $tmpfile
-    else
-	switch ( $description[2] )
-	    case PBM:
-	    pnmscale -quiet -xysize $size $size $i | pgmtopbm > $tmpfile
-	    breaksw
-
-	    case PGM:
-	    pnmscale -quiet -xysize $size $size $i > $tmpfile
-	    if ( $maxformat == PBM ) then
-		set maxformat=PGM
-	    endif
-	    breaksw
-
-	    default:
-	    if ( $doquant == false ) then
-	        pnmscale -quiet -xysize $size $size $i > $tmpfile
-	    else
-	        pnmscale -quiet -xysize $size $size $i | ppmquant -quiet $colors > $tmpfile
-	    endif
-	    set maxformat=PPM
-	    breaksw
-	endsw
-    endif
-    set imagefile=/tmp/pi.${row}.${col}.$$
-    rm -f $imagefile
-    if ( "$back" == "-white" ) then
-	pbmtext "$i" | pnmcat $back -tb $tmpfile - > $imagefile
-    else
-	pbmtext "$i" | pnminvert | pnmcat $back -tb $tmpfile - > $imagefile
-    endif
-    rm -f $tmpfile
-    set imagefiles=( $imagefiles $imagefile )
-
-    if ( $col >= $across ) then
-	set rowfile=/tmp/pi.${row}.$$
-	rm -f $rowfile
-	if ( $maxformat != PPM || $doquant == false ) then
-	    pnmcat $back -lr -jbottom $imagefiles > $rowfile
-	else
-	    pnmcat $back -lr -jbottom $imagefiles | ppmquant -quiet $colors > $rowfile
-	endif
-	rm -f $imagefiles
-	set imagefiles=()
-	set rowfiles=( $rowfiles $rowfile )
-	@ col = 1
-	@ row += 1
-    else
-	@ col += 1
-    endif
-
-end
-
-if ( $#imagefiles > 0 ) then
-    set rowfile=/tmp/pi.${row}.$$
-    rm -f $rowfile
-    if ( $maxformat != PPM || $doquant == false ) then
-	pnmcat $back -lr -jbottom $imagefiles > $rowfile
-    else
-	pnmcat $back -lr -jbottom $imagefiles | ppmquant -quiet $colors > $rowfile
-    endif
-    rm -f $imagefiles
-    set rowfiles=( $rowfiles $rowfile )
-endif
-
-if ( $#rowfiles == 1 ) then
-    cat $rowfiles
-else
-    if ( $maxformat != PPM || $doquant == false ) then
-	pnmcat $back -tb $rowfiles
-    else
-	pnmcat $back -tb $rowfiles | ppmquant -quiet $colors
-    endif
-endif
-rm -f $rowfiles
-
-exit 0
-
-usage:
-echo "usage: $0 [-size N] [-across N] [-colors N] [-black] pnmfile ..."
-exit 1
diff --git a/editor/pnmindex.sh b/editor/pnmindex.sh
deleted file mode 100755
index dfc5b82a..00000000
--- a/editor/pnmindex.sh
+++ /dev/null
@@ -1,214 +0,0 @@
-#!/bin/sh
-#
-# pnmindex - build a visual index of a bunch of PNM images
-#
-# Copyright (C) 1991 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.
-
-size=100        # make the images about this big
-across=6        # show this many images per row
-colors=256      # quantize results to this many colors
-back="-white"   # default background color
-doquant=true    # quantize or not
-title=""        # default title (none)
-
-usage ()
-{
-  echo "usage: $0 [-size N] [-across N] [-colors N] [-black] pnmfile ..."
-  exit 1
-}
-
-while :; do
-    case "$1" in
-
-    -s*)
-        if [ $# -lt 2 ]; then usage; fi
-        size="$2"
-        shift
-        shift
-    ;;
-
-    -a*)
-        if [ $# -lt 2 ]; then usage; fi
-        across="$2"
-        shift
-        shift
-    ;;
-
-    -t*)
-        if [ $# -lt 2 ]; then usage; fi
-        title="$2"
-        shift
-        shift
-    ;;
-
-    -c*)
-        if [ $# -lt 2 ]; then usage; fi
-        colors="$2"
-        shift
-        shift
-    ;;
-
-    -b*)
-        back="-black"
-        shift
-    ;;
-
-    -w*)
-        back="-white"
-        shift
-    ;;
-
-    -noq*)
-        doquant=false
-        shift
-    ;;
-
-    -q*)
-        doquant=true
-        shift
-    ;;
-
-    -*)
-        usage
-    ;;
-
-    *)
-        break
-    ;;
-    esac
-done
-
-if [ $# -eq 0 ]; then
-    usage
-fi
-
-tempdir="${TMPDIR-/tmp}/pnmindex.$$"
-mkdir -m 0700 $tempdir || \
-  { echo "Could not create temporary file. Exiting."; exit 1;}
-trap 'rm -rf $tempdir' 0 1 3 15
-
-tmpfile=$tempdir/pi.tmp
-maxformat=PBM
-
-rowfiles=()
-imagefiles=()
-row=1
-col=1
-
-if [ "$title"x != ""x ] ; then
-#    rowfile=`tempfile -p pirow -m 600`
-    rowfile=$tempdir/pi.${row}
-    pbmtext "$title" > $rowfile
-    rowfiles=(${rowfiles[*]} $rowfile )
-    row=$(($row + 1))
-fi
-
-for i in "$@"; do
-
-    description=(`pnmfile $i`)
-
-    format=${description[1]}
-    width=${description[3]}
-    height=${description[5]}
-
-    if [ $? -ne 0 ]; then
-        echo pnmfile returned an error
-        exit $?
-    fi
-
-    if [ $width -le $size ] && \
-       [ $height -le $size ]; then
-        cat $i > $tmpfile
-    else
-        case $format in
-
-        PBM) 
-            pamscale -quiet -xysize $size $size $i | pgmtopbm > $tmpfile
-        ;;
-
-        PGM)
-            pamscale -quiet -xysize $size $size $i > $tmpfile
-            if [ $maxformat = PBM ]; then
-                maxformat=PGM
-            fi
-        ;;
-
-        *) 
-            if [ "$doquant" = "true" ] ; then
-                pamscale -quiet -xysize $size $size $i | \
-                pnmquant -quiet $colors > $tmpfile
-            else
-                pamscale -quiet -xysize $size $size $i > $tmpfile
-            fi
-            maxformat=PPM
-        ;;
-        esac
-    fi
-
-    imagefile=$tempdir/pi.${row}.${col}
-    rm -f $imagefile
-    if [ "$back" = "-white" ]; then
-        pbmtext "$i" | pnmcat $back -tb $tmpfile - > $imagefile
-    else
-        pbmtext "$i" | pnminvert | pnmcat $back -tb $tmpfile - > $imagefile
-    fi
-    imagefiles=( ${imagefiles[*]} $imagefile )
-
-    if [ $col -ge $across ]; then
-        rowfile=$tempdir/pi.${row}
-        rm -f $rowfile
-
-        if [ $maxformat != PPM -o "$doquant" = "false" ]; then
-            pnmcat $back -lr -jbottom ${imagefiles[*]} > $rowfile
-        else
-            pnmcat $back -lr -jbottom ${imagefiles[*]} | \
-            pnmquant -quiet $colors > $rowfile
-        fi
-
-        rm -f ${imagefiles[*]}
-        unset imagefiles
-        imagefiles=()
-        rowfiles=( ${rowfiles[*]} $rowfile )
-        col=1
-        row=$(($row + 1))
-    else
-        col=$(($col + 1))
-    fi
-done
-
-# All the full rows have been put in row files.  
-# Now put the final partial row in its row file.
-
-if [ ${#imagefiles[*]} -gt 0 ]; then
-    rowfile=$tempdir/pi.${row}
-    rm -f $rowfile
-    if [ $maxformat != PPM -o "$doquant" = "false" ]; then
-        pnmcat $back -lr -jbottom ${imagefiles[*]} > $rowfile
-    else
-        pnmcat $back -lr -jbottom ${imagefiles[*]} | \
-        pnmquant -quiet $colors > $rowfile
-    fi
-    rm -f ${imagefiles[*]}
-    rowfiles=( ${rowfiles[*]} $rowfile )
-fi
-
-if [ ${#rowfiles[*]} -eq 1 ]; then
-    cat $rowfiles
-else
-    if [ $maxformat != PPM -o "$doquant" = "false" ]; then
-        pnmcat $back -tb ${rowfiles[*]}
-    else
-        pnmcat $back -tb ${rowfiles[*]} | pnmquant -quiet $colors
-    fi
-fi
-rm -f ${rowfiles[*]}
-
-exit 0
-
diff --git a/editor/pnmmargin b/editor/pnmmargin
index 6e70aba3..94321c7f 100755
--- a/editor/pnmmargin
+++ b/editor/pnmmargin
@@ -94,7 +94,7 @@ else
 
     case "$color" in
         -gofigure )
-        pnmcut 0 0 1 1 $tmp1 | pnmtile $size 1 > $tmp2
+        pamcut 0 0 1 1 $tmp1 | pnmtile $size 1 > $tmp2
         ;;
         -white | -black )
         pnmpad $plainopt $color \
@@ -108,8 +108,8 @@ else
     pamflip -rotate90 $tmp2 > $tmp3
 
     # Cat things together.
-    pnmcat -lr $tmp2 $tmp1 $tmp2 > $tmp4
-    pnmcat -tb $plainopt $tmp3 $tmp4 $tmp3
+    pamcat -leftright $tmp2 $tmp1 $tmp2 > $tmp4
+    pamcat -topbottom $plainopt $tmp3 $tmp4 $tmp3
 fi
 
 
diff --git a/editor/pnmnlfilt.c b/editor/pnmnlfilt.c
index f55a67bd..bcb3680d 100644
--- a/editor/pnmnlfilt.c
+++ b/editor/pnmnlfilt.c
@@ -59,9 +59,9 @@ struct cmdlineInfo {
 };
 
 
-static void 
-parseCommandLine(int argc, 
-                 char ** argv, 
+static void
+parseCommandLine(int argc,
+                 char ** argv,
                  struct cmdlineInfo  * const cmdlineP) {
 
     if (argc-1 < 2)
@@ -75,9 +75,9 @@ parseCommandLine(int argc,
 
     if (sscanf( argv[2], "%lf", &cmdlineP->radius ) != 1)
         pm_error("Invalid radius (2nd) argument '%s'.  "
-                 "Must be a decimal number", 
+                 "Must be a decimal number",
                  argv[2]);
-    
+
     if ((cmdlineP->alpha > -0.1 && cmdlineP->alpha < 0.0) ||
         (cmdlineP->alpha > 0.5 && cmdlineP->alpha < 1.0))
         pm_error( "Alpha must be in range 0.0 <= alpha <= 0.5 "
@@ -118,11 +118,11 @@ parseCommandLine(int argc,
    this value.
 */
 
-#define MXIVAL PPM_MAXMAXVAL   
+#define MXIVAL PPM_MAXMAXVAL
 
-xelval omaxval; 
+xelval omaxval;
     /* global so that pixel processing code can get at it quickly */
-int noisevariance;      
+int noisevariance;
     /* global so that pixel processing code can get at it quickly */
 
 /*
@@ -157,7 +157,7 @@ static  xelval maxval;
 /* round and scale floating point to scaled integer */
 #define ROUNDSCALE(x) ((int)(((x) * (double)SCALE) + 0.5))
 /* round and un-scale scaled integer value */
-#define RUNSCALE(x) (((x) + (1 << (SCALEB-1))) >> SCALEB) 
+#define RUNSCALE(x) (((x) + (1 << (SCALEB-1))) >> SCALEB)
 /* rounded un-scale */
 #define UNSCALE(x) ((x) >> SCALEB)
 
@@ -194,9 +194,9 @@ int AVEDIV[7 * NOCSVAL];                /* divide by 7 to give average value */
 int SQUARE[2 * NOCSVAL];                /* scaled square lookup table */
 
 /* ************************************************** *
-   Hexagon intersecting square area functions 
-   Compute the area of the intersection of a triangle 
-   and a rectangle 
+   Hexagon intersecting square area functions
+   Compute the area of the intersection of a triangle
+   and a rectangle
    ************************************************** */
 
 /* Triangle orientation is per geometric axes (not graphical axies) */
@@ -210,7 +210,7 @@ int SQUARE[2 * NOCSVAL];                /* scaled square lookup table */
 
 #define SWAPI(a,b) (t = a, a = -b, b = -t)
 
-static double 
+static double
 triang_area(double rx0, double ry0, double rx1, double ry1,
             double tx0, double ty0, double tx1, double ty1,
             int tt) {
@@ -250,7 +250,7 @@ triang_area(double rx0, double ry0, double rx1, double ry1,
     a = tx0 - b * ty0;
     d = (ty1 - ty0)/(tx1 - tx0);
     c = ty0 - d * tx0;
-    
+
     /* compute top or right intersection */
     tt = 0;
     ly1 = ry1;
@@ -278,7 +278,7 @@ triang_area(double rx0, double ry0, double rx1, double ry1,
             return (rx1 - rx0) * (ry1 - ry0);
         tt |= 2;        /* bottom intersection */
     }
-    
+
     if (tt == 0) {
         /* top and left intersection */
         /* rectangle minus triangle */
@@ -293,7 +293,7 @@ triang_area(double rx0, double ry0, double rx1, double ry1,
         return ((rx1 - lx1) * (ry1 - ry0))
             + (0.5 * (lx1 - lx0) * (ry1 - ry0));
     } else {
-        /* tt == 3 */ 
+        /* tt == 3 */
         /* right and bottom intersection */
         /* triangle */
         return (0.5 * (rx1 - lx0) * (ly1 - ry0));
@@ -303,7 +303,7 @@ triang_area(double rx0, double ry0, double rx1, double ry1,
 
 
 static double
-rectang_area(double rx0, double ry0, double rx1, double ry1, 
+rectang_area(double rx0, double ry0, double rx1, double ry1,
              double tx0, double ty0, double tx1, double ty1) {
 /* Compute rectangle area */
 /* rx0,ry0,rx1,ry1:  rectangle boundaries */
@@ -326,7 +326,7 @@ rectang_area(double rx0, double ry0, double rx1, double ry1,
 
 
 
-static double 
+static double
 hex_area(double sx, double sy, double hx, double hy, double d) {
 /* compute the area of overlap of a hexagon diameter d, */
 /* centered at hx,hy, with a unit square of center sx,sy. */
@@ -384,7 +384,7 @@ setupSquare(void) {
 
     for (i=0; i < (2 * NOCSVAL); ++i) {
         /* compute square and rescale by (val >> (2 * SCALEB + 2)) table */
-        int const val = CSCTOSC(i - NOCSVAL); 
+        int const val = CSCTOSC(i - NOCSVAL);
         /* NOCSVAL offset to cope with -ve input values */
         SQUARE[i] = (val * val) >> (2 * SCALEB + 2);
     }
@@ -414,7 +414,7 @@ setup1(double   const alpha,
 
         *mmeanscaleP = *meanscaleP = maxscale/noinmean;
         if (alpha == 0.0) {
-            /* mean filter */ 
+            /* mean filter */
             *alpharangeP = 0;
             *alphafractionP = 0.0;            /* not used */
         } else if (alpha < (1.0/6.0)) {
@@ -438,9 +438,9 @@ setup1(double   const alpha,
         double const noinmean = 7.0;
         *alpharangeP = 5;                 /* edge enhancement function */
         *mmeanscaleP = *meanscaleP = maxscale;  /* compute scaled hex values */
-        *alphafractionP = 1.0/noinmean;   
+        *alphafractionP = 1.0/noinmean;
             /* Set up 1:1 division lookup - not used */
-        *noisevarianceP = sqr(alphaNormalized * omaxval) / 8.0;    
+        *noisevarianceP = sqr(alphaNormalized * omaxval) / 8.0;
             /* estimate of noise variance */
     } else if (alpha >= -0.9 && alpha <= -0.1) {
         /* edge enhancement function */
@@ -449,7 +449,7 @@ setup1(double   const alpha,
         *alpharangeP = 4;                 /* edge enhancement function */
         *meanscaleP = maxscale * (-posAlpha/((1.0 - posAlpha) * 7.0));
             /* mean of 7 and scaled by -posAlpha/(1-posAlpha) */
-        *mmeanscaleP = maxscale * (1.0/(1.0 - posAlpha) + *meanscaleP);    
+        *mmeanscaleP = maxscale * (1.0/(1.0 - posAlpha) + *meanscaleP);
             /* middle pixel has 1/(1-posAlpha) as well */
         *alphafractionP = 0.0;    /* not used */
     } else {
@@ -481,18 +481,18 @@ setupPixelWeightingTables(double const radius,
                           double const mmeanscale) {
 
     /* Setup pixel weighting tables - note we pre-compute mean
-       division here too. 
+       division here too.
     */
-    double const hexhoff = radius/2;      
+    double const hexhoff = radius/2;
         /* horizontal offset of vertical hex centers */
-    double const hexvoff = 3.0 * radius/sqrt(12.0); 
+    double const hexvoff = 3.0 * radius/sqrt(12.0);
         /* vertical offset of vertical hex centers */
 
     double const tabscale  = meanscale  / (radius * hexvoff);
     double const mtabscale = mmeanscale / (radius * hexvoff);
 
     /* scale tables to normalize by hexagon area, and number of
-       hexes used in mean 
+       hexes used in mean
     */
     double const v0 =
         hex_area(0.0,  0.0, hexhoff, hexvoff, radius) * tabscale;
@@ -538,7 +538,7 @@ setupPixelWeightingTables(double const radius,
 
 
 /* Table initialization function - return alpha range */
-static int 
+static int
 atfilt_setup(double const alpha,
              double const radius,
              double const maxscale) {
@@ -546,7 +546,7 @@ atfilt_setup(double const alpha,
     int alpharange;                 /* alpha range value 0 - 5 */
     double meanscale;               /* scale for finding mean */
     double mmeanscale;              /* scale for finding mean - midle hex */
-    double alphafraction;   
+    double alphafraction;
         /* fraction of next largest/smallest to subtract from sum */
 
     setup1(alpha, radius, maxscale,
@@ -562,7 +562,7 @@ atfilt_setup(double const alpha,
 
 
 
-static int 
+static int
 atfilt0(int * p) {
 /* Core pixel processing function - hand it 3x3 pixels and return result. */
 /* Mean filter */
@@ -586,7 +586,7 @@ atfilt0(int * p) {
         else if (xx < small) \
             small = xx; }
 
-static int 
+static int
 atfilt1(int * p) {
 /* Mean of 5 - 7 middle values */
 /* 'p' is 9 pixel values from 3x3 neighbors */
@@ -635,7 +635,7 @@ atfilt1(int * p) {
     }
 
 
-static int 
+static int
 atfilt2(int *p) {
 /* Mean of 3 - 5 middle values */
 /* 'p' is 9 pixel values from 3x3 neighbors */
@@ -708,10 +708,10 @@ atfilt2(int *p) {
                         small2 = xx; \
                                          }}
 
-static int 
+static int
 atfilt3(int *p) {
 /* Mean of 1 - 3 middle values. If only 1 value, then this is a median
-   filter. 
+   filter.
 */
 /* 'p' is pixel values from 3x3 neighbors */
     int h0,h1,h2,h3,h4,h5,h6;       /* hexagon values    2 3   */
@@ -737,12 +737,12 @@ atfilt3(int *p) {
     CHECK(h5);
     CHECK(h6);
     /* Compute mean of middle 1-3 values */
-    return  UNSCALE(h0 -big0 -big1 -small0 -small1 
+    return  UNSCALE(h0 -big0 -big1 -small0 -small1
                     -ALFRAC[(big2 + small2)>>SCALEB]);
 }
 #undef CHECK
 
-static int 
+static int
 atfilt4(int *p) {
 /* Edge enhancement */
 /* notice we use the global omaxval */
@@ -765,7 +765,7 @@ atfilt4(int *p) {
     return hav;
 }
 
-static int 
+static int
 atfilt5(int *p) {
 /* Optimal estimation - do smoothing in inverse proportion */
 /* to the local variance. */
@@ -786,19 +786,19 @@ atfilt5(int *p) {
     h6 = V0[p[0]] + V1[p[7]] + V2[p[8]] + V3[p[1]];
     mean = h0 + h1 + h2 + h3 + h4 + h5 + h6;
     mean = AVEDIV[SCTOCSC(mean)];   /* compute scaled mean by dividing by 7 */
-    temp = (h1 - mean); variance = SQUARE[NOCSVAL + SCTOCSC(temp)];  
+    temp = (h1 - mean); variance = SQUARE[NOCSVAL + SCTOCSC(temp)];
         /* compute scaled variance */
-    temp = (h2 - mean); variance += SQUARE[NOCSVAL + SCTOCSC(temp)]; 
+    temp = (h2 - mean); variance += SQUARE[NOCSVAL + SCTOCSC(temp)];
         /* and rescale to keep */
-    temp = (h3 - mean); variance += SQUARE[NOCSVAL + SCTOCSC(temp)]; 
+    temp = (h3 - mean); variance += SQUARE[NOCSVAL + SCTOCSC(temp)];
         /* within 32 bit limits */
     temp = (h4 - mean); variance += SQUARE[NOCSVAL + SCTOCSC(temp)];
     temp = (h5 - mean); variance += SQUARE[NOCSVAL + SCTOCSC(temp)];
     temp = (h6 - mean); variance += SQUARE[NOCSVAL + SCTOCSC(temp)];
-    temp = (h0 - mean); variance += SQUARE[NOCSVAL + SCTOCSC(temp)];   
+    temp = (h0 - mean); variance += SQUARE[NOCSVAL + SCTOCSC(temp)];
     /* (temp = h0 - mean) */
     if (variance != 0)      /* avoid possible divide by 0 */
-        temp = mean + (variance * temp) / (variance + noisevariance);   
+        temp = mean + (variance * temp) / (variance + noisevariance);
             /* optimal estimate */
     else temp = h0;
     if (temp < 0)
@@ -811,17 +811,17 @@ atfilt5(int *p) {
 
 
 
-static void 
+static void
 do_one_frame(FILE * const ifP) {
 
     pnm_writepnminit( stdout, cols, rows, omaxval, oformat, 0 );
-    
+
     if ( PNM_FORMAT_TYPE(oformat) == PPM_TYPE ) {
         int pr[9],pg[9],pb[9];          /* 3x3 neighbor pixel values */
         int r,g,b;
 
         for ( row = 0; row < rows; row++ ) {
-            int po,no;           /* offsets for left and right colums in 3x3 */
+            int po,no;          /* offsets for left and right columns in 3x3 */
             xel *ip0, *ip1, *ip2, *op;
 
             if (row == 0) {
@@ -897,14 +897,14 @@ do_one_frame(FILE * const ifP) {
         promote = ( PNM_FORMAT_TYPE(format) != PNM_FORMAT_TYPE(oformat) );
 
         for ( row = 0; row < rows; row++ ) {
-            int po,no;          /* offsets for left and right colums in 3x3 */
+            int po,no;          /* offsets for left and right columns in 3x3 */
             xel *ip0, *ip1, *ip2, *op;
 
             if (row == 0) {
                 irow0 = irow1;
                 pnm_readpnmrow( ifP, irow1, cols, maxval, format );
                 if ( promote )
-                    pnm_promoteformatrow( irow1, cols, maxval, 
+                    pnm_promoteformatrow( irow1, cols, maxval,
                                           format, maxval, oformat );
             }
             if (row == (rows-1))
@@ -912,7 +912,7 @@ do_one_frame(FILE * const ifP) {
             else {
                 pnm_readpnmrow( ifP, irow2, cols, maxval, format );
                 if ( promote )
-                    pnm_promoteformatrow( irow2, cols, maxval, 
+                    pnm_promoteformatrow( irow2, cols, maxval,
                                           format, maxval, oformat );
             }
 
@@ -955,7 +955,7 @@ do_one_frame(FILE * const ifP) {
 
 
 static void
-verifySame(unsigned int const imageSeq, 
+verifySame(unsigned int const imageSeq,
            int const imageCols, int const imageRows,
            xelval const imageMaxval, int const imageFormat,
            int const cols, int const rows,
@@ -1000,16 +1000,16 @@ main(int argc, char *argv[]) {
     ifP = pm_openr(cmdline.inputFileName);
 
     pnm_readpnminit(ifP, &cols, &rows, &maxval, &format);
-        
-    if (maxval > MXIVAL) 
+
+    if (maxval > MXIVAL)
         pm_error("The maxval of the input image (%d) is too large.\n"
-                 "This program's limit is %d.", 
+                 "This program's limit is %d.",
                  maxval, MXIVAL);
-        
+
     oformat = PNM_FORMAT_TYPE(format);
     /* force output to max precision without forcing new 2-byte format */
     omaxval = MIN(maxval, PPM_MAXMAXVAL);
-        
+
     atfunc = atfuncs[atfilt_setup(cmdline.alpha, cmdline.radius,
                                   (double)omaxval/(double)maxval)];
 
@@ -1038,7 +1038,7 @@ main(int argc, char *argv[]) {
             int imageFormat;
 
             ++imageSeq;
-            pnm_readpnminit(ifP, &imageCols, &imageRows, 
+            pnm_readpnminit(ifP, &imageCols, &imageRows,
                             &imageMaxval, &imageFormat);
             verifySame(imageSeq,
                        imageCols, imageRows, imageMaxval, imageFormat,
@@ -1054,3 +1054,6 @@ main(int argc, char *argv[]) {
 
     return 0;
 }
+
+
+
diff --git a/editor/pnmnorm.c b/editor/pnmnorm.c
index 3a181bf3..8c25df80 100644
--- a/editor/pnmnorm.c
+++ b/editor/pnmnorm.c
@@ -38,7 +38,7 @@
 
 enum brightMethod {BRIGHT_LUMINOSITY, BRIGHT_COLORVALUE, BRIGHT_SATURATION};
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -70,7 +70,7 @@ struct cmdlineInfo {
 
 static void
 parseCommandLine(int argc, const char ** argv,
-                 struct cmdlineInfo * const cmdlineP) {
+                 struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    parse program command line described in Unix standard form by argc
    and argv.  Return the information in the options as *cmdlineP.
@@ -265,7 +265,12 @@ buildHistogram(FILE *   const ifp,
 static xelval
 minimumValue(const unsigned int * const hist,
              unsigned int         const highest) {
+/*----------------------------------------------------------------------------
+   The minimum brightness in the image, according to histogram 'hist',
+   which goes up to 'highest'.
 
+   Abort the program if there are no pixels of any brightness.
+-----------------------------------------------------------------------------*/
     xelval i;
     bool foundOne;
 
@@ -274,7 +279,8 @@ minimumValue(const unsigned int * const hist,
             foundOne = true;
         else {
             if (i == highest)
-                pm_error("INTERNAL ERROR in '%s'.  No pixels", __FUNCTION__);
+                pm_error("INTERNAL ERROR in function 'minimumValue'.  "
+                         "No pixels");
             else
                 ++i;
         }
@@ -287,7 +293,12 @@ minimumValue(const unsigned int * const hist,
 static xelval
 maximumValue(const unsigned int * const hist,
              unsigned int         const highest) {
+/*----------------------------------------------------------------------------
+   The maximum brightness in the image, according to histogram 'hist',
+   which goes up to 'highest'.
 
+   Abort the program if there are no pixels of any brightness.
+-----------------------------------------------------------------------------*/
     xelval i;
     bool foundOne;
 
@@ -296,7 +307,8 @@ maximumValue(const unsigned int * const hist,
             foundOne = true;
         else {
             if (i == 0)
-                pm_error("INTERNAL ERROR in '%s'.  No pixels", __FUNCTION__);
+                pm_error("INTERNAL ERROR in function 'maximumValue'.  "
+                         "No pixels");
             else
                 --i;
         }
@@ -306,12 +318,32 @@ maximumValue(const unsigned int * const hist,
 
 
 
+static unsigned int
+brightnessCount(const unsigned int * const hist,
+                unsigned int         const highest) {
+/*----------------------------------------------------------------------------
+   The number of distinct brightnesses in the image according to
+   histogram 'hist', which goes up to brightness 'highest'.
+-----------------------------------------------------------------------------*/
+    xelval i;
+    unsigned int nonzeroCount;
+
+    for (i = 0, nonzeroCount = 0; i <= highest; ++i) {
+        if (hist[i] > 0)
+            ++nonzeroCount;
+    }
+
+    return nonzeroCount;
+}
+
+
+
 static void
-computeBottomPercentile(unsigned int         hist[],
-                        unsigned int   const highest,
-                        unsigned int   const total,
-                        float          const percent,
-                        unsigned int * const percentileP) {
+computeBottomPercentile(const unsigned int * const hist,
+                        unsigned int         const highest,
+                        unsigned int         const total,
+                        float                const percent,
+                        unsigned int *       const percentileP) {
 /*----------------------------------------------------------------------------
    Compute the lowest index of hist[] such that the sum of the hist[]
    values with that index and lower represent at least 'percent' per cent of
@@ -339,11 +371,11 @@ computeBottomPercentile(unsigned int         hist[],
 
 
 static void
-computeTopPercentile(unsigned int         hist[],
-                     unsigned int   const highest,
-                     unsigned int   const total,
-                     float          const percent,
-                     unsigned int * const percentileP) {
+computeTopPercentile(const unsigned int * const hist,
+                     unsigned int         const highest,
+                     unsigned int         const total,
+                     float                const percent,
+                     unsigned int *       const percentileP) {
 /*----------------------------------------------------------------------------
    Compute the highest index of hist[] such that the sum of the hist[]
    values with that index and higher represent 'percent' per cent of
@@ -494,13 +526,68 @@ disOverlap(xelval   const reqBvalue,
 
 
 
+static xelval
+resolvedPctBvalue(const unsigned int * const hist,
+                  unsigned int         const totalPixelCt,
+                  xelval               const maxval,
+                  struct CmdlineInfo   const cmdline) {
+
+    xelval retval;
+
+    if (cmdline.bsingle)
+        retval = minimumValue(hist, maxval);
+    else if (cmdline.bvalueSpec && !cmdline.bpercentSpec) {
+        retval = cmdline.bvalue;
+    } else {
+        xelval percentBvalue;
+
+        computeBottomPercentile(hist, maxval, totalPixelCt, cmdline.bpercent,
+                                &percentBvalue);
+        if (cmdline.bvalueSpec)
+            retval = MIN(percentBvalue, cmdline.bvalue);
+        else
+            retval = percentBvalue;
+    }
+    return retval;
+}
+
+
+
+static xelval
+resolvedPctWvalue(const unsigned int * const hist,
+                  unsigned int         const totalPixelCt,
+                  xelval               const maxval,
+                  struct CmdlineInfo   const cmdline) {
+
+    xelval retval;
+
+    if (cmdline.wsingle)
+        retval = maximumValue(hist, maxval);
+    else if (cmdline.wvalueSpec && !cmdline.wpercentSpec) {
+        retval = cmdline.wvalue;
+    } else {
+        xelval percentWvalue;
+
+        computeTopPercentile(hist, maxval, totalPixelCt, cmdline.wpercent,
+                             &percentWvalue);
+        if (cmdline.wvalueSpec)
+            retval = MAX(percentWvalue, cmdline.wvalue);
+        else
+            retval = percentWvalue;
+    }
+
+    return retval;
+}
+
+
+
 static void
 resolvePercentParams(FILE *             const ifP,
                      unsigned int       const cols,
                      unsigned int       const rows,
                      xelval             const maxval,
                      int                const format,
-                     struct cmdlineInfo const cmdline,
+                     struct CmdlineInfo const cmdline,
                      xelval *           const bvalueP,
                      xelval *           const wvalueP) {
 /*----------------------------------------------------------------------------
@@ -521,32 +608,17 @@ resolvePercentParams(FILE *             const ifP,
         buildHistogram(ifP, cols, rows, maxval, format, hist,
                        cmdline.brightMethod);
 
-        if (cmdline.bsingle)
-            *bvalueP = minimumValue(hist, maxval);
-        else if (cmdline.bvalueSpec && !cmdline.bpercentSpec) {
-            *bvalueP = cmdline.bvalue;
+        if (!cmdline.bvalueSpec && !cmdline.wvalueSpec &&
+            brightnessCount(hist, maxval) < 2) {
+            /* Special case - you can't stretch a single brightness to both
+               ends.  So just don't stretch at all.
+            */
+            *bvalueP = 0;
+            *wvalueP = maxval;
         } else {
-            xelval percentBvalue;
-            computeBottomPercentile(hist, maxval, cols*rows, cmdline.bpercent,
-                                    &percentBvalue);
-            if (cmdline.bvalueSpec)
-                *bvalueP = MIN(percentBvalue, cmdline.bvalue);
-            else
-                *bvalueP = percentBvalue;
-        }
+            *bvalueP = resolvedPctBvalue(hist, cols * rows, maxval, cmdline);
 
-        if (cmdline.wsingle)
-            *wvalueP = maximumValue(hist, maxval);
-        else if (cmdline.wvalueSpec && !cmdline.wpercentSpec) {
-            *wvalueP = cmdline.wvalue;
-        } else {
-            xelval percentWvalue;
-            computeTopPercentile(hist, maxval, cols*rows, cmdline.wpercent,
-                                 &percentWvalue);
-            if (cmdline.wvalueSpec)
-                *wvalueP = MAX(percentWvalue, cmdline.wvalue);
-            else
-                *wvalueP = percentWvalue;
+            *wvalueP = resolvedPctWvalue(hist, cols * rows, maxval, cmdline);
         }
         free(hist);
     }
@@ -560,7 +632,7 @@ computeEndValues(FILE *             const ifP,
                  int                const rows,
                  xelval             const maxval,
                  int                const format,
-                 struct cmdlineInfo const cmdline,
+                 struct CmdlineInfo const cmdline,
                  xelval *           const bvalueP,
                  xelval *           const wvalueP,
                  bool *             const quadraticP,
@@ -627,7 +699,7 @@ computeLinearTransfer(xelval   const bvalue,
     unsigned int val;
     /* The following for structure is a hand optimization of this one:
        for (i = bvalue; i <= wvalue; ++i)
-       newBrightness[i] = (i-bvalue)*maxval/range);
+           newBrightness[i] = (i-bvalue)*maxval/range);
        (with proper rounding)
     */
     for (i = bvalue, val = range/2;
@@ -935,8 +1007,8 @@ reportTransferParm(bool   const quadratic,
 int
 main(int argc, const char *argv[]) {
 
-    struct cmdlineInfo cmdline;
-    FILE *ifP;
+    struct CmdlineInfo cmdline;
+    FILE * ifP;
     pm_filepos imagePos;
     xelval maxval;
     int rows, cols, format;
diff --git a/editor/pnmpad.c b/editor/pnmpad.c
index 7cc53b69..9fa9f9e6 100644
--- a/editor/pnmpad.c
+++ b/editor/pnmpad.c
@@ -38,6 +38,7 @@ struct cmdlineInfo {
     unsigned int mwidth;
     unsigned int mheight;
     unsigned int white;     /* >0: pad white; 0: pad black */
+    unsigned int reportonly;
     unsigned int verbose;
 };
 
@@ -86,14 +87,16 @@ parseCommandLine(int argc, const char ** argv,
             &yalignSpec,           0);
     OPTENT3(0,   "valign",    OPT_FLOAT,   &cmdlineP->yalign,
             &yalignSpec,           0);
-    OPTENT3(0,   "black",     OPT_FLAG,    NULL,
-            &blackOpt,           0);
     OPTENT3(0,   "mwidth",    OPT_UINT,    &cmdlineP->mwidth,
             &mwidthSpec,         0);
     OPTENT3(0,   "mheight",   OPT_UINT,    &cmdlineP->mheight,
             &mheightSpec,        0);
+    OPTENT3(0,   "black",     OPT_FLAG,    NULL,
+            &blackOpt,           0);
     OPTENT3(0,   "white",     OPT_FLAG,    NULL,
             &cmdlineP->white,    0);
+    OPTENT3(0,   "reportonly", OPT_FLAG,   NULL,
+            &cmdlineP->reportonly,   0);
     OPTENT3(0,   "verbose",   OPT_FLAG,    NULL,
             &cmdlineP->verbose,  0);
 
@@ -126,16 +129,16 @@ parseCommandLine(int argc, const char ** argv,
        pm_error("You can specify -height only once");
 
     if (xalignSpec && (cmdlineP->leftSpec || cmdlineP->rightSpec))
-        pm_error("You cannot specify both -xalign and -left or -right");
+        pm_error("You cannot specify both -halign and -left or -right");
 
     if (yalignSpec && (cmdlineP->topSpec || cmdlineP->bottomSpec))
-        pm_error("You cannot specify both -yalign and -top or -bottom");
+        pm_error("You cannot specify both -valign and -top or -bottom");
 
-    if (xalignSpec && !cmdlineP->xsizeSpec)
-        pm_error("-xalign is meaningless without -width");
+    if (xalignSpec && (!cmdlineP->xsizeSpec && !mwidthSpec) )
+        pm_error("-halign is meaningless without -width or -mwidth");
 
-    if (yalignSpec && !cmdlineP->ysizeSpec)
-        pm_error("-yalign is meaningless without -height");
+    if (yalignSpec && (!cmdlineP->ysizeSpec && !mheightSpec) )
+        pm_error("-valign is meaningless without -height or -mheight");
 
     if (xalignSpec) {
         if (cmdlineP->xalign < 0)
@@ -265,7 +268,7 @@ validateHorizontalSize(struct cmdlineInfo const cmdline,
         pm_error("The right padding value you specified is too large.");
 
     if ((double) cols +
-        (double) lpad + 
+        (double) lpad +
         (double) rpad +
         (double) mwidthMaxPad > MAX_WIDTHHEIGHT)
         pm_error("Given padding parameters make output width too large "
@@ -375,9 +378,9 @@ computePadSizesOneDim(unsigned int   const unpaddedSize,
         unsigned int const totalPadBeforeMult =
             begPadBeforeMult + endPadBeforeMult;
         double const begFrac =
-            totalPadBeforeMult > 0 ? 
+            totalPadBeforeMult > 0 ?
             (double)begPadBeforeMult / totalPadBeforeMult :
-            0.0;
+            align;
         unsigned int const addlMsizeBegPad = ROUNDU(morePadNeeded * begFrac);
             /* # of pixels we have to add to the beginning to satisfy
                user's desire for the final size to be a multiple of something
@@ -489,6 +492,23 @@ computePadSizes(struct cmdlineInfo const cmdline,
 
 
 static void
+reportPadSizes(int          const inCols,
+               int          const inRows,
+               unsigned int const lpad,
+               unsigned int const rpad,
+               unsigned int const tpad,
+               unsigned int const bpad) {
+
+    unsigned int const outCols = inCols + lpad + rpad;
+    unsigned int const outRows = inRows + tpad + bpad;
+
+    printf("%u %u %u %u %u %u\n", lpad, rpad, tpad, bpad, outCols, outRows);
+
+}
+
+
+
+static void
 padPbm(FILE *       const ifP,
        unsigned int const cols,
        unsigned int const rows,
@@ -527,7 +547,7 @@ padPbm(FILE *       const ifP,
     /* Write top margin */
     for (row = 0; row < tpad; ++row)
         pbm_writepbmrow_packed(stdout, bgrow, newcols, 0);
-    
+
     /* Read rows, shift and write with left and right margins added */
     for (row = 0; row < rows; ++row) {
         pbm_readpbmrow_bitoffset(ifP, newrow, cols, format, lpad);
@@ -636,12 +656,16 @@ main(int argc, const char ** argv) {
 
     newcols = cols + lpad + rpad;
 
-    if (PNM_FORMAT_TYPE(format) == PBM_TYPE)
-        padPbm(ifP, cols, rows, format, newcols, lpad, rpad, tpad, bpad,
-               !!cmdline.white);
-    else
-        padGeneral(ifP, cols, rows, maxval, format, 
-                   newcols, lpad, rpad, tpad, bpad, !!cmdline.white);
+    if (cmdline.reportonly)
+        reportPadSizes(cols, rows, lpad, rpad, tpad, bpad);
+    else {
+        if (PNM_FORMAT_TYPE(format) == PBM_TYPE)
+            padPbm(ifP, cols, rows, format, newcols, lpad, rpad, tpad, bpad,
+                   !!cmdline.white);
+        else
+            padGeneral(ifP, cols, rows, maxval, format,
+                       newcols, lpad, rpad, tpad, bpad, !!cmdline.white);
+    }
 
     pm_close(ifP);
 
diff --git a/editor/pnmquant b/editor/pnmquant
index 0bb328d2..4dd133f1 100755
--- a/editor/pnmquant
+++ b/editor/pnmquant
@@ -37,9 +37,16 @@ use Getopt::Long;
 use File::Spec;
 #use Fcntl ":seek";  # not available in Perl 5.00503
 use Fcntl;  # gets open flags
+use IO::Handle;
 
 my ($TRUE, $FALSE) = (1,0);
 
+sub pm_message($) {
+    STDERR->print("pnmquant: $_[0]\n");
+}
+
+
+
 my ($SEEK_SET, $SEEK_CUR, $SEEK_END) = (0, 1, 2);
 
 
@@ -59,16 +66,17 @@ sub doVersionHack($) {
 
 sub tempFile($) {
 
+    my ($suffix) = @_;
+
     # We trust Perl's File::Temp to do a better job of creating the temp
     # file, but it doesn't exist before Perl 5.6.1.
 
     if (eval { require File::Temp; 1 }) {
         return File::Temp::tempfile("pnmquant_XXXX", 
-                                    SUFFIX=>".pnm", 
+                                    SUFFIX=>$suffix, 
                                     DIR=>File::Spec->tmpdir(),
                                     UNLINK=>$TRUE);
     } else {
-        my ($suffix) = @_;
         my $fileName;
         local *file;  # For some inexplicable reason, must be local, not my
         my $i;
@@ -89,7 +97,7 @@ sub parseCommandLine(@) {
 
     my %cmdline;
 
-    my $validOptions = GetOptions(\%cmdline,
+    my $optsAreValid = GetOptions(\%cmdline,
                                   "center",
                                   "meancolor",
                                   "meanpixel",
@@ -101,18 +109,17 @@ sub parseCommandLine(@) {
                                   "quiet",
                                   "plain");
 
-    if (!$validOptions) {
-        print(STDERR "Invalid option syntax.\n");
+    if (!$optsAreValid) {
+        pm_message("Invalid option syntax");
         exit(1);
     }
     if (@ARGV > 2) {
-        print(STDERR "This program takes at most 2 arguments.  You specified ",
-              scalar(@ARGV), "\n");
+        pm_message("This program takes at most 2 arguments.  You specified " .
+                   scalar(@ARGV));
         exit(1);
     } 
     elsif (@ARGV < 1) {
-        print(STDERR 
-              "You must specify the number of colors as an argument.\n");
+        pm_message("You must specify the number of colors as an argument.");
         exit(1);
     }
     my $infile;
@@ -120,9 +127,8 @@ sub parseCommandLine(@) {
     
     if (!($cmdline{ncolors} =~ m{ ^[[:digit:]]+$ }x ) || 
         $cmdline{ncolors} == 0) {
-        print(STDERR 
-              "Number of colors argument '$cmdline{ncolors}' " .
-              "is not a positive integer.\n");
+        pm_message("Number of colors argument '$cmdline{ncolors}' " .
+                   "is not a positive integer.");
         exit(1);
     }
 
@@ -199,10 +205,10 @@ sub openSeekableAsStdin($) {
 
 
 
-sub makeColormap($$$$$) {
+sub makeColormap($$$$$$$) {
 
-    my ($ncolors, $opt_meanpixel, $opt_meancolor, $opt_spreadluminosity,
-        $opt_quiet) = @_;
+    my ($ncolors, $opt_center, $opt_meanpixel, $opt_meancolor,
+        $opt_spreadbrightness, $opt_spreadluminosity, $opt_quiet) = @_;
 
     # Make a colormap of $ncolors colors from the image on Standard Input.
     # Put it in a temporary file and return its name.
@@ -210,12 +216,23 @@ sub makeColormap($$$$$) {
     my ($mapfileFh, $mapfileSpec) = tempFile(".pnm");
 
     if (!defined($mapfileFh)) {
-        print(STDERR "Unable to create temporary file for colormap.  " .
-              "errno = $ERRNO\n");
+        pm_message("Unable to create temporary file for colormap.  " .
+                   "errno = $ERRNO");
         exit(1);
     }
-
+       
     my $averageOpt;
+
+    my $colorSummaryOptCt =
+        (defined($opt_meanpixel) ? 1 : 0) +
+        (defined($opt_meancolor) ? 1 : 0) +
+        (defined($opt_center)    ? 1 : 0);
+
+    if ($colorSummaryOptCt > 1) {
+        pm_message("You can specify only one of " .
+                   "-meanpixel, -meancolor, and -center");
+        exit(1);
+    }
     if (defined($opt_meanpixel)) {
         $averageOpt = "-meanpixel";
     } elsif (defined($opt_meancolor)) {
@@ -224,6 +241,16 @@ sub makeColormap($$$$$) {
         $averageOpt = "-center";
     }
 
+    my $spreadOptCt =
+        (defined($opt_spreadluminosity) ? 1 : 0) +
+        (defined($opt_spreadbrightness) ? 1 : 0);
+
+    if ($spreadOptCt > 1) {
+        pm_message("You can specify only one of " .
+                   "-spreadluminosity and -spreadbrightness");
+        exit(1);
+    }
+
     my $spreadOpt;
     if (defined($opt_spreadluminosity)) {
         $spreadOpt = "-spreadluminosity";
@@ -242,7 +269,7 @@ sub makeColormap($$$$$) {
     my $maprc = system("pnmcolormap", $ncolors, @options);
 
     if ($maprc != 0) {
-        print(STDERR "pnmcolormap failed, rc=$maprc\n");
+        pm_message("pnmcolormap failed, rc=$maprc");
         exit(1);
     } 
     return $mapfileSpec;
@@ -265,12 +292,16 @@ sub remap($$$$$$) {
         push(@options, "-floyd");
     }
     if ($opt_norandom) {
+        if (defined($opt_randomseed)) {
+             pm_message("You cannot specify -randomseed with -norandom");
+             exit(1);
+        }
         push(@options, "-norandom");
     }
     if (defined($opt_randomseed)) {
         if ($opt_randomseed < 0) {
-             print(STDERR "-randomseed value must not be negative.  " .
-                   "You specified $opt_randomseed\n");
+             pm_message("-randomseed value must not be negative.  " .
+                        "You specified $opt_randomseed");
              exit(10);
         }
         push(@options, "-randomseed=$opt_randomseed");
@@ -285,7 +316,7 @@ sub remap($$$$$$) {
     my $remaprc = system("pnmremap", "-mapfile=$mapfileSpec", @options);
     
     if ($remaprc != 0) {
-        print(STDERR "pnmremap failed, rc=$remaprc\n");
+        pm_message("pnmremap failed, rc=$remaprc");
         exit(1);
     }
 }
@@ -308,8 +339,10 @@ select(OLDOUT);  # avoids Perl bug where it says we never use OLDOUT
 
 
 my $mapfileSpec = makeColormap($cmdlineR->{ncolors}, 
+                               $cmdlineR->{center}, 
                                $cmdlineR->{meanpixel}, 
                                $cmdlineR->{meancolor}, 
+                               $cmdlineR->{spreadbrightness},
                                $cmdlineR->{spreadluminosity},
                                $cmdlineR->{quiet});
 
diff --git a/editor/pnmquantall b/editor/pnmquantall
index aea6cc84..594e8f7b 100755
--- a/editor/pnmquantall
+++ b/editor/pnmquantall
@@ -57,11 +57,18 @@ use warnings;
 use English;
 use Fcntl;  # gets open flags
 use File::Copy;
+use IO::Handle;
 
 my $TRUE=1; my $FALSE = 0;
 
 
 
+sub pm_message($) {
+    STDERR->print("pnmquantall: $_[0]\n");
+}
+
+
+
 sub doVersionHack($) {
     my ($argvR) = @_;
 
@@ -84,7 +91,7 @@ sub parseArgs($$$$) {
 
     if (@argv > 0 && $argv[0] eq "-ext") {
         if (@argv < 2) {
-            print STDERR ("-ext requires a value\n");
+            pm_message("-ext requires a value");
         exit(100);
         } else {
             $$extR = $argv[1];
@@ -96,8 +103,8 @@ sub parseArgs($$$$) {
     }
 
     if (@argv < $firstArgPos + 2) {
-        print STDERR ("Not enough arguments.  You need at least the number " .
-                      "of colors and one file name\n");
+        pm_message("Not enough arguments.  You need at least the number " .
+                      "of colors and one file name");
         exit(100);
     }
     
@@ -110,16 +117,17 @@ sub parseArgs($$$$) {
 
 sub tempFile($) {
 
+    my ($suffix) = @_;
+
     # We trust Perl's File::Temp to do a better job of creating the temp
     # file, but it doesn't exist before Perl 5.6.1.
 
     if (eval { require File::Temp; 1 }) {
         return File::Temp::tempfile("pnmquant_XXXX", 
-                                    SUFFIX=>".pnm", 
+                                    SUFFIX=>$suffix, 
                                     DIR=>File::Spec->tmpdir(),
                                     UNLINK=>$TRUE);
     } else {
-        my ($suffix) = @_;
         my $fileName;
         local *file;  # For some inexplicable reason, must be local, not my
         my $i;
@@ -137,11 +145,11 @@ sub tempFile($) {
 sub makeColorMap($$$$) {
     my ($fileNamesR, $newColorCt, $colorMapFileName, $errorR) = @_;
 
-    my $pnmcatCmd = "pnmcat -topbottom -white -jleft @{$fileNamesR}";
+    my $pamcatCmd = "pamcat -topbottom -white -jleft @{$fileNamesR}";
 
     my $pnmcolormapCmd = "pnmcolormap $newColorCt";
 
-    my $makeMapCmd = "$pnmcatCmd | $pnmcolormapCmd >$colorMapFileName";
+    my $makeMapCmd = "$pamcatCmd | $pnmcolormapCmd >$colorMapFileName";
 
     my $termStatus = system($makeMapCmd);
 
@@ -212,7 +220,7 @@ if (!$progError) {
 my $exitStatus;
 
 if ($progError) {
-    print STDERR ("Failed.  $progError\n");
+    pm_message("Failed.  $progError");
     $exitStatus = 1;
 } else {
     $exitStatus = 0;
diff --git a/editor/pnmremap.c b/editor/pnmremap.c
index 0038f4d7..e5b59d04 100644
--- a/editor/pnmremap.c
+++ b/editor/pnmremap.c
@@ -28,6 +28,7 @@
 #include "pm_c_util.h"
 #include "mallocvar.h"
 #include "nstring.h"
+#include "rand.h"
 #include "shhopt.h"
 #include "pam.h"
 #include "ppm.h"
@@ -399,20 +400,21 @@ randomizeError(long **       const err,
    Set a random error in the range [-1 .. 1] (normalized via FS_SCALE)
    in the error array err[][].
 -----------------------------------------------------------------------------*/
-    unsigned int const seed = (random.init == RANDOM_WITHSEED) ?
-        random.seed : pm_randseed();
-
     unsigned int col;
+    struct pm_randSt randSt;
 
     assert(random.init != RANDOM_NONE);
 
-    srand(seed);
+    pm_randinit(&randSt);
+    pm_srand2(&randSt, random.init == RANDOM_WITHSEED, random.seed);
 
     for (col = 0; col < width; ++col) {
         unsigned int plane;
         for (plane = 0; plane < depth; ++plane)
-            err[plane][col] = rand() % (FS_SCALE * 2) - FS_SCALE;
+            err[plane][col] = pm_rand(&randSt) % (FS_SCALE * 2) - FS_SCALE;
     }
+
+    pm_randterm(&randSt);
 }
 
 
@@ -1043,13 +1045,6 @@ copyRaster(struct pam *   const inpamP,
     inrow  = pnm_allocpamrow(inpamP);
     outrow = pnm_allocpamrow(&workpam);
 
-    if (outpamP->maxval != inpamP->maxval && defaultColor)
-        pm_error("The maxval of the colormap (%u) is not equal to the "
-                 "maxval of the input image (%u).  This is allowable only "
-                 "if you are doing an approximate mapping (i.e. you don't "
-                 "specify -firstisdefault or -missingcolor)",
-                 (unsigned int)outpamP->maxval, (unsigned int)inpamP->maxval);
-
     selectDepthAdjustment(inpamP, outpamP->depth, &depthAdjustment);
 
     usehash = TRUE;
@@ -1120,6 +1115,13 @@ remap(FILE *             const ifP,
         outpam.width  = inpam.width;
         outpam.height = inpam.height;
 
+        if (outpam.maxval != inpam.maxval && defaultColor)
+            pm_error("The maxval of the colormap (%u) is not equal to the "
+                     "maxval of the input image (%u).  This is allowable only "
+                     "if you are doing an approximate mapping (i.e. you don't "
+                     "specify -firstisdefault or -missingcolor)",
+                     (unsigned int)outpam.maxval, (unsigned int)inpam.maxval);
+
         pnm_writepaminit(&outpam);
 
         /* Set up so input buffers have extra space as needed to
diff --git a/editor/pnmshear.c b/editor/pnmshear.c
index c705c261..45d74c6f 100644
--- a/editor/pnmshear.c
+++ b/editor/pnmshear.c
@@ -54,7 +54,7 @@ parseCommandLine(int argc, const char ** argv,
     OPTENT3(0, "noantialias",      OPT_FLAG,  NULL, &cmdlineP->noantialias, 0);
     OPTENT3(0, "background",       OPT_STRING, &cmdlineP->background,
             &backgroundSpec, 0);
-    
+
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;
     opt.allowNegNum = TRUE;
@@ -106,21 +106,21 @@ makeNewXel(xel *  const outputXelP,
     switch (PNM_FORMAT_TYPE(format)) {
     case PPM_TYPE:
         PPM_ASSIGN(*outputXelP,
-                   (fracnew0 * PPM_GETR(prevXel) 
-                    + omfracnew0 * PPM_GETR(curXel) 
+                   (fracnew0 * PPM_GETR(prevXel)
+                    + omfracnew0 * PPM_GETR(curXel)
                     + HALFSCALE) / SCALE,
-                   (fracnew0 * PPM_GETG(prevXel) 
-                    + omfracnew0 * PPM_GETG(curXel) 
+                   (fracnew0 * PPM_GETG(prevXel)
+                    + omfracnew0 * PPM_GETG(curXel)
                     + HALFSCALE) / SCALE,
-                   (fracnew0 * PPM_GETB(prevXel) 
-                    + omfracnew0 * PPM_GETB(curXel) 
+                   (fracnew0 * PPM_GETB(prevXel)
+                    + omfracnew0 * PPM_GETB(curXel)
                     + HALFSCALE) / SCALE );
         break;
-        
+
     default:
         PNM_ASSIGN1(*outputXelP,
-                    (fracnew0 * PNM_GET1(prevXel) 
-                     + omfracnew0 * PNM_GET1(curXel) 
+                    (fracnew0 * PNM_GET1(prevXel)
+                     + omfracnew0 * PNM_GET1(curXel)
                      + HALFSCALE) / SCALE );
         break;
     }
@@ -130,9 +130,9 @@ makeNewXel(xel *  const outputXelP,
 
 static void
 shearRow(xel *        const xelrow,
-         unsigned int const cols, 
+         unsigned int const cols,
          xel *        const newxelrow,
-         unsigned int const newcols, 
+         unsigned int const newcols,
          double       const shearCols,
          int          const format,
          xel          const bgxel,
@@ -140,7 +140,7 @@ shearRow(xel *        const xelrow,
 /*----------------------------------------------------------------------------
    Shear the row 'xelrow' by 'shearCols' columns, and return the result as
    'newxelrow'.  They are 'cols' and 'newcols' columns wide, respectively.
-   
+
    Fill in the part of the output row that doesn't contain image data with
    'bgxel'.
 
@@ -152,14 +152,14 @@ shearRow(xel *        const xelrow,
     unsigned int const intShearCols = (unsigned int) shearCols;
 
     assert(shearCols >= 0.0);
-        
+
     if (antialias) {
         const long fracnew0 = (shearCols - intShearCols) * SCALE;
         const long omfracnew0 = SCALE - fracnew0;
 
         unsigned int col;
         xel prevXel;
-            
+
         for (col = 0; col < newcols; ++col)
             newxelrow[col] = bgxel;
 
@@ -170,7 +170,7 @@ shearRow(xel *        const xelrow,
                        format);
             prevXel = xelrow[col];
         }
-        if (fracnew0 > 0) 
+        if (fracnew0 > 0)
             /* Need to add a column for what's left over */
             makeNewXel(&newxelrow[intShearCols + cols],
                        bgxel, prevXel, fracnew0, omfracnew0, format);
@@ -197,7 +197,7 @@ backgroundColor(const char * const backgroundColorName,
 
     if (backgroundColorName) {
         retval = pnm_parsecolorxel(backgroundColorName, maxval, format);
-    } else 
+    } else
         retval = pnm_backgroundxelrow(topRow, cols, maxval, format);
 
     return retval;
@@ -212,10 +212,13 @@ main(int argc, const char * argv[]) {
     xel * xelrow;
     xel * newxelrow;
     xel bgxel;
-    int rows, cols, format; 
-    int newformat, newcols; 
-    int row;
-    xelval maxval, newmaxval;
+    int rows, cols;
+    int format;
+    unsigned int newcols;
+    int newformat;
+    unsigned int row;
+    xelval maxval;
+    xelval newmaxval;
     double shearfac;
     double newcolsD;
 
@@ -230,6 +233,16 @@ main(int argc, const char * argv[]) {
     pnm_readpnminit(ifP, &cols, &rows, &maxval, &format);
     xelrow = pnm_allocrow(cols);
 
+    shearfac = tan(cmdline.angle);
+
+    newcolsD = (double) rows * fabs(shearfac) + cols + 0.999999;
+    if (newcolsD > INT_MAX-2)
+        pm_error("angle is too close to +/-90 degrees; "
+                 "output image too wide for computation");
+    else
+        newcols = (unsigned int) newcolsD;
+
+
     /* Promote PBM files to PGM. */
     if (!cmdline.noantialias && PNM_FORMAT_TYPE(format) == PBM_TYPE) {
         newformat = PGM_TYPE;
@@ -241,18 +254,9 @@ main(int argc, const char * argv[]) {
         newmaxval = maxval;
     }
 
-    shearfac = fabs(tan(cmdline.angle));
-
-    newcolsD = (double) rows * shearfac + cols + 0.999999;
-    if (newcolsD > INT_MAX-2)
-        pm_error("angle is too close to +/-90 degrees; "
-                 "output image too wide for computation");
-    else
-        newcols = (int) newcolsD;
-
     pnm_writepnminit(stdout, newcols, rows, newmaxval, newformat, 0);
     newxelrow = pnm_allocrow(newcols);
-    
+
     for (row = 0; row < rows; ++row) {
         double shearCols;
 
@@ -262,17 +266,17 @@ main(int argc, const char * argv[]) {
             bgxel = backgroundColor(cmdline.background,
                                     xelrow, cols, newmaxval, format);
 
-        if (cmdline.angle > 0.0)
+        if (shearfac > 0.0)
             shearCols = row * shearfac;
         else
-            shearCols = (rows - row) * shearfac;
+            shearCols = (rows - row) * -shearfac;
 
-        shearRow(xelrow, cols, newxelrow, newcols, 
+        shearRow(xelrow, cols, newxelrow, newcols,
                  shearCols, format, bgxel, !cmdline.noantialias);
 
         pnm_writepnmrow(stdout, newxelrow, newcols, newmaxval, newformat, 0);
     }
-    
+
     pm_close(ifP);
     pm_close(stdout);
 
diff --git a/editor/pnmstitch.c b/editor/pnmstitch.c
index eae5e1b9..b27445b0 100644
--- a/editor/pnmstitch.c
+++ b/editor/pnmstitch.c
@@ -20,7 +20,7 @@
  * otherwise) arising in any way out of the use of this software, even if
  * advised of the possibility of such damage.
  *
- * Any restrictions or encumberances added to this source code or derivitives,
+ * Any restrictions or encumberances added to this source code or derivatives,
  * is prohibited.
  *
  *  Name: pnmstitch.c
@@ -1116,7 +1116,7 @@ OutputAlloc(Output     * const me,
 static void
 StraightThroughDeAlloc(Output * me)
 {
-    /* Trick the proper freeing of resouces on the Output Image */
+    /* Trick the proper freeing of resources on the Output Image */
     me->image->pam.height = 1;
     OutputDeAlloc(me);
 } /* StraightThroughDeAlloc() - end */
@@ -1131,7 +1131,7 @@ StraightThroughAlloc(Output     * const me,
     if (OutputAlloc(me, file, width, height, prototype) == FALSE) {
         StraightThroughDeAlloc(me);
     }
-    /* Trick the proper allocation of resouces on the Output Image */
+    /* Trick the proper allocation of resources on the Output Image */
     me->image->pam.height = 1;
     me->image->tuple = pnm_allocpamarray(&me->image->pam);
     if (me->image->tuple == (tuple **)NULL) {
@@ -1322,10 +1322,10 @@ Output OutputMethods[] = {
 /* Stitcher Methods */
 
 /* These names are for the 8 parameters of a stitch, in any of the 3
-   methods this program presently implements.  Each is a subscript in
+   methods this program currently implements.  Each is a subscript in
    the parms[] array for the Stitcher object that represents a linear
-   stitching method.  
-   
+   stitching method.
+
    There are also other sets of names for the 8 parameters, such as
    Rotate_a.  I don't know why.  Maybe historical.
 */
diff --git a/editor/ppmbrighten b/editor/ppmbrighten
new file mode 100755
index 00000000..f5de436f
--- /dev/null
+++ b/editor/ppmbrighten
@@ -0,0 +1,60 @@
+#! /bin/sh
+
+# This is just for backward compatibility.  New applications should use
+# 'pambrighten'.
+
+# We don't try very hard to respond well to invalid syntax, because backward
+# compatibility is mostly like existing, working applications.
+
+pambrightenOpts=''
+normalize='no'
+expectValue='no'
+
+for word in "$@"; do
+
+    if test "$expectValue" = 'yes'; then
+        # This is the value of an option, like "40" in "-saturation 40"
+        pambrightenOpts="$pambrightenOpts $word"
+        expectValue='no'
+    else
+        # 'word_one_hyphen' is 'word' except if 'word' is a double-hyphen
+        # option, 'word_one_hyphen' is the single-hyphen version of it.
+        # E.g. word=--saturation word_one_hyphen=-saturation .
+        word_one_hyphen=$(echo "$word" | sed s/^--/-/ )
+    
+        case $word_one_hyphen in
+            -version )
+                pambrighten -version; exit $?
+                ;;
+            -normalize|-normaliz|-normali|-normal|-norma|-norm|-nor|-no|-n)
+                normalize='yes'
+                ;;
+            -*=*)
+                pambrightenOpts="$pambrightenOpts $word"
+                # This is an option with value such as "-saturation=40"
+                ;;
+            -*)
+                pambrightenOpts="$pambrightenOpts $word"
+                # Starts with hyphen, no equals sign, so the next word is the
+                # option's value (note that the only valid ppmbrighten flag
+                # option is -normalized, handled above).
+                #
+                # E.g. "-saturation 40"
+                expectValue='yes'
+                ;;
+            *)
+                # Not an option or option value - only non-option argument
+                # ppmbrighten has is optional input file name
+                infile="$word"
+                ;;
+                
+        esac
+    fi
+done
+
+if test "$normalize" = 'yes'; then
+    pnmnorm -bsingle -wsingle -colorvalue -keephues $infile | \
+        pambrighten $pambrightenOpts | ppmtoppm
+else
+    pambrighten $pambrightenOpts $infile | ppmtoppm
+fi
diff --git a/editor/ppmbrighten.c b/editor/ppmbrighten.c
deleted file mode 100644
index 0446bb75..00000000
--- a/editor/ppmbrighten.c
+++ /dev/null
@@ -1,218 +0,0 @@
-/*=============================================================================
-                              ppmbrighten
-===============================================================================
-  Change Value and Saturation of PPM image.
-=============================================================================*/
-
-#include "pm_c_util.h"
-#include "ppm.h"
-#include "shhopt.h"
-#include "mallocvar.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;  /* '-' if stdin */
-    float saturation;
-    float value;
-    unsigned int normalize;
-};
-
-
-
-static void
-parseCommandLine(int argc, const 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 pm_optParseOptions3 on how to parse our options.
-         */
-    optStruct3 opt;
-
-    unsigned int option_def_index;
-
-    unsigned int saturationSpec, valueSpec;
-    int saturationOpt, valueOpt;
-
-    MALLOCARRAY_NOFAIL(option_def, 100);
-
-    option_def_index = 0;   /* incremented by OPTENT3 */
-    OPTENT3(0, "saturation",  OPT_INT,    &saturationOpt,
-            &saturationSpec,      0 );
-    OPTENT3(0, "value",       OPT_INT,    &valueOpt,
-            &valueSpec,           0 );
-    OPTENT3(0, "normalize",   OPT_FLAG,   NULL,
-            &cmdlineP->normalize, 0 );
-
-    opt.opt_table = option_def;
-    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
-    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
-
-    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
-        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
-
-    if (saturationSpec) {
-        if (saturationOpt < -100)
-            pm_error("Saturation reduction cannot be more than 100%%.  "
-                     "You specified %d", saturationOpt);
-        else
-            cmdlineP->saturation = 1.0 + (float)saturationOpt / 100;
-    } else
-        cmdlineP->saturation = 1.0;
-
-    if (valueSpec) {
-        if (valueOpt < -100)
-            pm_error("Value reduction cannot be more than 100%%.  "
-                     "You specified %d", valueOpt);
-        else
-            cmdlineP->value = 1.0 + (float)valueOpt / 100;
-    } else
-        cmdlineP->value = 1.0;
-
-    if (argc-1 < 1)
-        cmdlineP->inputFileName = "-";
-    else if (argc-1 == 1)
-        cmdlineP->inputFileName = argv[1];
-    else
-        pm_error("Program takes at most one argument:  file specification");
-}
-
-
-
-static void
-getMinMax(FILE *       const ifP,
-          unsigned int const cols,
-          unsigned int const rows,
-          pixval       const maxval,
-          int          const format,
-          double *     const minValueP,
-          double *     const maxValueP) {
-
-    pixel * pixelrow;
-    double minValue, maxValue;
-    unsigned int row;
-
-    pixelrow = ppm_allocrow(cols);
-
-    for (row = 0, minValue = 65536.0, maxValue = 0.0; row < rows; ++row) {
-        unsigned int col;
-
-        ppm_readppmrow(ifP, pixelrow, cols, maxval, format);
-
-        for (col = 0; col < cols; ++col) {
-            struct hsv const pixhsv =
-                ppm_hsv_from_color(pixelrow[col], maxval);
-
-            maxValue = MAX(maxValue, pixhsv.v);
-            minValue = MIN(minValue, pixhsv.v);
-        }
-    }
-    ppm_freerow(pixelrow);
-
-    *minValueP = minValue;
-    *maxValueP = maxValue;
-}
-
-
-
-int
-main(int argc, const char ** argv) {
-
-    double const EPSILON = 1.0e-5;
-    struct CmdlineInfo cmdline;
-    FILE * ifP;
-    pixel * pixelrow;
-    pixval maxval;
-    int rows, cols, format, row;
-    double minValue, maxValue;
-
-    pm_proginit(&argc, argv);
-
-    parseCommandLine(argc, argv, &cmdline);
-
-    if (cmdline.normalize)
-        ifP = pm_openr_seekable(cmdline.inputFileName);
-    else
-        ifP = pm_openr(cmdline.inputFileName);
-
-    ppm_readppminit(ifP, &cols, &rows, &maxval, &format);
-
-    if (cmdline.normalize) {
-        pm_filepos rasterPos;
-        pm_tell2(ifP, &rasterPos, sizeof(rasterPos));
-        getMinMax(ifP, cols, rows, maxval, format, &minValue, &maxValue);
-        pm_seek2(ifP, &rasterPos, sizeof(rasterPos));
-        if (maxValue - minValue > EPSILON) {
-            pm_message("Minimum value %.0f%% of full intensity "
-                       "being remapped to zero.",
-                       (minValue * 100.0));
-            pm_message("Maximum value %.0f%% of full intensity "
-                       "being remapped to full.",
-                       (maxValue * 100.0));
-        } else
-            pm_message("Sole value of %.0f%% of full intensity "
-                       "not being remapped",
-                       (maxValue * 100.0));
-    }
-
-    pixelrow = ppm_allocrow(cols);
-
-    ppm_writeppminit(stdout, cols, rows, maxval, 0);
-
-    for (row = 0; row < rows; ++row) {
-        unsigned int col;
-
-        ppm_readppmrow(ifP, pixelrow, cols, maxval, format);
-
-        for (col = 0; col < cols; ++col) {
-            struct hsv pixhsv;
-
-            pixhsv = ppm_hsv_from_color(pixelrow[col], maxval);
-                /* initial value */
-
-            if (cmdline.normalize) {
-                if (maxValue - minValue > EPSILON)
-                    pixhsv.v = (pixhsv.v - minValue) / (maxValue - minValue);
-            }
-            pixhsv.s = pixhsv.s * cmdline.saturation;
-            pixhsv.s = MAX(0.0, MIN(1.0, pixhsv.s));
-            pixhsv.v = pixhsv.v * cmdline.value;
-            pixhsv.v = MAX(0.0, MIN(1.0, pixhsv.v));
-            pixelrow[col] = ppm_color_from_hsv(pixhsv, maxval);
-        }
-        ppm_writeppmrow(stdout, pixelrow, cols, maxval, 0);
-    }
-    ppm_freerow(pixelrow);
-
-    pm_close(ifP);
-
-    /* If the program failed, it previously aborted with nonzero exit status
-       via various function calls.
-    */
-    return 0;
-}
-
-
-
-/**
-** Copyright (C) 1989 by Jef Poskanzer.
-** Copyright (C) 1990 by Brian Moffet.
-**
-** 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/editor/ppmfade b/editor/ppmfade
index dcd7bf26..7dc533a1 100755
--- a/editor/ppmfade
+++ b/editor/ppmfade
@@ -41,6 +41,8 @@ exec perl -w -x -S -- "$0" "$@"
 ##############################################################################
 use strict;
 
+use File::Temp;
+
 sub doVersionHack($) {
     my ($argvR) = @_;
 
@@ -52,7 +54,9 @@ sub doVersionHack($) {
     }
 }
 
+my $tmpdir;
 
+$tmpdir = File::Temp::tempdir("ppmfade.XXXXXX", CLEANUP => 1);
 
 my $SPREAD =  1;
 my $SHIFT =   2;
@@ -151,18 +155,18 @@ print("Frames are " . $width . "W x " . $height . "H\n");
 
 if ($first_file eq "undefined") {
     print "Fading from black to ";
-    system("ppmmake \\#000 $width $height >junk1$$.ppm");
+    system("ppmmake \\#000 $width $height >$tmpdir/junk1.ppm");
 } else {
     print "Fading from $first_file to ";
-    system("cp", $first_file, "junk1$$.ppm");
+    system("cp", $first_file, "$tmpdir/junk1.ppm");
 }
 
 if ($last_file eq "undefined") {
     print "black.\n";
-    system("ppmmake \\#000 $width $height >junk2$$.ppm");
+    system("ppmmake \\#000 $width $height >$tmpdir/junk2.ppm");
 } else {
     print "$last_file\n";
-    system("cp", $last_file, "junk2$$.ppm");
+    system("cp", $last_file, "$tmpdir/junk2.ppm");
 }
 
 #
@@ -170,14 +174,14 @@ if ($last_file eq "undefined") {
 #
 
 # Here's what our temporary files are:
-#   junk1$$.ppm: The original (fade-from) image
-#   junk2$$.ppm: The target (fade-from) image
-#   junk3$$.ppm: The frame of the fade for the current iteration of the 
-#                the for loop.
-#   junk1a$$.ppm: If the fade involves a ppmmix sequence from one intermediate
-#                 image to another, this is the first frame of that 
-#                 sequence.
-#   junk2a$$.ppm: This is the last frame of the above-mentioned ppmmix sequence
+#   junk1.ppm: The original (fade-from) image
+#   junk2.ppm: The target (fade-from) image
+#   junk3.ppm: The frame of the fade for the current iteration of the 
+#              the for loop.
+#   junk1a.ppm: If the fade involves a ppmmix sequence from one intermediate
+#               image to another, this is the first frame of that 
+#               sequence.
+#   junk2a.ppm: This is the last frame of the above-mentioned ppmmix sequence
 
 my $i;    # Frame number
 for ($i = 1; $i <= $nframes; $i++) {
@@ -185,147 +189,151 @@ for ($i = 1; $i <= $nframes; $i++) {
     if ($mode eq $SPREAD) {
         if ($i <= 10) {
             my $n = $spline20[$i] * 100;
-            system("ppmspread $n junk1$$.ppm >junk3$$.ppm");
+            system("ppmspread $n $tmpdir/junk1.ppm >$tmpdir/junk3.ppm");
         } elsif ($i <= 20) {
             my $n;
             $n = $spline20[$i] * 100;
-            system("ppmspread $n junk1$$.ppm >junk1a$$.ppm");
+            system("ppmspread $n $tmpdir/junk1.ppm >$tmpdir/junk1a.ppm");
             $n = (1-$spline20[$i-10]) * 100;
-            system("ppmspread $n junk2$$.ppm >junk2a$$.ppm");
+            system("ppmspread $n $tmpdir/junk2.ppm >$tmpdir/junk2a.ppm");
             $n = $spline10[$i-10];
-            system("ppmmix $n junk1a$$.ppm junk2a$$.ppm >junk3$$.ppm");
+            system("ppmmix $n $tmpdir/junk1a.ppm $tmpdir/junk2a.ppm " .
+                   ">$tmpdir/junk3.ppm");
         } else {
             my $n = (1-$spline20[$i-10])*100;
-            system("ppmspread $n junk2$$.ppm >junk3$$.ppm");
+            system("ppmspread $n $tmpdir/junk2.ppm >$tmpdir/junk3.ppm");
         }
     } elsif ($mode eq $SHIFT) {
         if ($i <= 10) {
             my $n = $spline20[$i] * 100;
-            system("ppmshift $n junk1$$.ppm >junk3$$.ppm");
+            system("ppmshift $n $tmpdir/junk1.ppm >$tmpdir/junk3.ppm");
         } elsif ($i <= 20) {
             my $n;
             $n = $spline20[$i] * 100;
-            system("ppmshift $n junk1$$.ppm >junk1a$$.ppm");
+            system("ppmshift $n $tmpdir/junk1.ppm >$tmpdir/junk1a.ppm");
             $n = (1-$spline20[$i-10])*100;
-            system("ppmshift $n junk2$$.ppm >junk2a$$.ppm");
+            system("ppmshift $n junk2.ppm >junk2a.ppm");
             $n = $spline10[$i-10];
-            system("ppmmix $n junk1a$$.ppm junk2a$$.ppm >junk3$$.ppm");
+            system("ppmmix $n junk1a.ppm junk2a.ppm >junk3.ppm");
         } else {
             my $n = (1-$spline20[$i-10]) * 100;
-            system("ppmshift $n junk2$$.ppm >junk3$$.ppm");
+            system("ppmshift $n junk2.ppm >junk3.ppm");
         }
     } elsif ($mode eq $RELIEF) {
         if ($i == 1) {
-            system("ppmrelief junk1$$.ppm >junk1r$$.ppm");
+            system("ppmrelief junk1.ppm >junk1r.ppm");
         }
         if ($i <= 10) {
             my $n = $spline10[$i];
-            system("ppmmix $n junk1$$.ppm junk1r$$.ppm >junk3$$.ppm");
+            system("ppmmix $n junk1.ppm junk1r.ppm >junk3.ppm");
         } elsif ($i <= 20) {
             my $n = $spline10[$i-10];
-            system("ppmmix $n junk1r$$.ppm junk2r$$.ppm >junk3$$.ppm");
+            system("ppmmix $n junk1r.ppm junk2r.ppm >junk3.ppm");
         } else {
             my $n = $spline10[$i-20];
-            system("ppmmix $n junk2r$$.ppm junk2$$.ppm >junk3$$.ppm");
+            system("ppmmix $n junk2r.ppm junk2.ppm >junk3.ppm");
         }
         if ($i == 10) {
-            system("ppmrelief junk2$$.ppm >junk2r$$.ppm");
+            system("ppmrelief junk2.ppm >junk2r.ppm");
         }
     } elsif ($mode eq $OIL) {
         if ($i == 1) {
-            system("ppmtopgm junk1$$.ppm | pgmoil >junko$$.ppm");
-            system("rgb3toppm junko$$.ppm junko$$.ppm junko$$.ppm " .
-                   ">junk1o$$.ppm");
+            system("ppmtopgm junk1.ppm | pgmoil >junko.ppm");
+            system("rgb3toppm junko.ppm junko.ppm junko.ppm " .
+                   ">junk1o.ppm");
         }
         if ($i <= 10) {
             my $n = $spline10[$i];
-            system("ppmmix $n junk1$$.ppm junk1o$$.ppm >junk3$$.ppm");
+            system("ppmmix $n junk1.ppm junk1o.ppm >junk3.ppm");
         } elsif ($i <= 20) {
             my $n = $spline10[$i-10];
-            system("ppmmix $n junk1o$$.ppm junk2o$$.ppm >junk3$$.ppm");
+            system("ppmmix $n junk1o.ppm junk2o.ppm >junk3.ppm");
         } else {
             my $n = $spline10[$i-20];
-            system("ppmmix $n junk2o$$.ppm junk2$$.ppm >junk3$$.ppm");
+            system("ppmmix $n junk2o.ppm junk2.ppm >junk3.ppm");
         }
         if ($i == 10) {
-            system("ppmtopgm junk2$$.ppm | pgmoil >junko$$.ppm");
-            system("rgb3toppm junko$$.ppm junko$$.ppm junko$$.ppm " .
-                   ">junk2o$$.ppm");
+            system("ppmtopgm junk2.ppm | pgmoil >junko.ppm");
+            system("rgb3toppm junko.ppm junko.ppm junko.ppm " .
+                   ">junk2o.ppm");
         }
     } elsif ($mode eq $EDGE) {
         if ($i == 1) {
-            system("ppmtopgm junk1$$.ppm | pgmedge >junko$$.ppm");
-            system("rgb3toppm junko$$.ppm junko$$.ppm junko$$.ppm " .
-                   ">junk1o$$.ppm");
+            system("ppmtopgm junk1.ppm | pgmedge >junko.ppm");
+            system("rgb3toppm junko.ppm junko.ppm junko.ppm " .
+                   ">junk1o.ppm");
         }
         if ($i <= 10) {
             my $n = $spline10[$i];
-            system("ppmmix $n junk1$$.ppm junk1o$$.ppm >junk3$$.ppm");
+            system("ppmmix $n junk1.ppm junk1o.ppm >junk3.ppm");
         } elsif ($i <= 20) {
             my $n = $spline10[$i-10];
-            system("ppmmix $n junk1o$$.ppm junk2o$$.ppm >junk3$$.ppm");
+            system("ppmmix $n junk1o.ppm junk2o.ppm >junk3.ppm");
         } else {
             my $n = $spline10[$i-20];
-            system("ppmmix $n junk2o$$.ppm junk2$$.ppm >junk3$$.ppm");
+            system("ppmmix $n junk2o.ppm junk2.ppm >junk3.ppm");
         }
         if ($i == 10) {
-            system("ppmtopgm junk2$$.ppm | pgmedge >junko$$.ppm");
-            system("rgb3toppm junko$$.ppm junko$$.ppm junko$$.ppm " .
-                   ">junk2o$$.ppm");
+            system("ppmtopgm junk2.ppm | pgmedge >junko.ppm");
+            system("rgb3toppm junko.ppm junko.ppm junko.ppm " .
+                   ">junk2o.ppm");
         } 
     } elsif ($mode eq $BENTLEY) {
         if ($i == 1) {
-            system("ppmtopgm junk1$$.ppm | pgmbentley >junko$$.ppm");
-            system("rgb3toppm junko$$.ppm junko$$.ppm junko$$.ppm " .
-                   ">junk1o$$.ppm");
+            system("ppmtopgm junk1.ppm | pgmbentley >junko.ppm");
+            system("rgb3toppm junko.ppm junko.ppm junko.ppm " .
+                   ">junk1o.ppm");
         }
         if ($i <= 10) {
             my $n = $spline10[$i];
-            system("ppmmix $n junk1$$.ppm junk1o$$.ppm >junk3$$.ppm");
+            system("ppmmix $n junk1.ppm junk1o.ppm >junk3.ppm");
         } elsif ($i <= 20) {
             my $n = $spline10[$i-10];
-            system("ppmmix $n junk1o$$.ppm junk2o$$.ppm >junk3$$.ppm");
+            system("ppmmix $n junk1o.ppm junk2o.ppm >junk3.ppm");
         } else {
             my $n = $spline10[$i-20];
-            system("ppmmix $n junk2o$$.ppm junk2$$.ppm >junk3$$.ppm");
+            system("ppmmix $n $tmpdir/junk2o.ppm $tmpdir/junk2.ppm " .
+                   ">$tmpdir/junk3.ppm");
         }
         if ($i == 10) {
-            system("ppmtopgm junk2$$.ppm | pgmbentley >junko$$.ppm");
-            system("rgb3toppm junko$$.ppm junko$$.ppm junko$$.ppm " .
-                   ">junk2o$$.ppm");
+               system("ppmtopgm $tmpdir/junk2.ppm | pgmbentley " .
+                      ">$tmpdir/junko.ppm");
+            system("rgb3toppm $tmpdir/junko.ppm $tmpdir/junko.ppm " .
+                   "$tmpdir/junko.ppm " .
+                   ">$tmpdir/junk2o.ppm");
         }
     } elsif ($mode eq $BLOCK) {
         if ($i <= 10) {
             my $n = 1 - 1.9*$spline20[$i];
-            system("pamscale $n junk1$$.ppm | " .
-                   "pamscale -width $width -height $height >junk3$$.ppm");
+            system("pamscale $n $tmpdir/junk1.ppm | " .
+                   "pamscale -width $width -height $height " .
+                   ">$tmpdir/junk3.ppm");
         } elsif ($i <= 20) {
             my $n = $spline10[$i-10];
-            system("ppmmix $n junk1a$$.ppm junk2a$$.ppm >junk3$$.ppm");
+            system("ppmmix $n $tmpdir/junk1a.ppm $tmpdir/junk2a.ppm " .
+                   ">$tmpdir/junk3.ppm");
         } else {
             my $n = 1 - 1.9*$spline20[31-$i];
-            system("pamscale $n junk2$$.ppm | " .
-                   "pamscale -width $width -height $height >junk3$$.ppm");
+            system("pamscale $n $tmpdir/junk2.ppm | " .
+                   "pamscale -width $width -height $height " .
+                   ">$tmpdir/junk3.ppm");
         }
         if ($i == 10) {
-            system("cp", "junk3$$.ppm", "junk1a$$.ppm");
-            system("pamscale $n junk2$$.ppm | " .
-                   "pamscale -width $width -height $height >junk2a$$.ppm");
+            system("cp", "$tmpdir/junk3.ppm", "$tmpdir/junk1a.ppm");
+            system("pamscale $n $tmpdir/junk2.ppm | " .
+                   "pamscale -width $width -height $height " .
+                   ">$tmpdir/junk2a.ppm");
         }    
     } elsif ($mode eq $MIX) {
         my $fade_factor = sqrt(1/($nframes-$i+1));
-        system("ppmmix $fade_factor junk1$$.ppm junk2$$.ppm >junk3$$.ppm");
+        system("ppmmix $fade_factor $tmpdir/junk1.ppm $tmpdir/junk2.ppm " .
+               ">$tmpdir/junk3.ppm");
     } else {
         print("Internal error: impossible mode value '$mode'\n");
     }
 
     my $outfile = sprintf("%s.%04d.ppm", $base_name, $i);
-    system("cp", "junk3$$.ppm", $outfile);
+    system("cp", "$tmpdir/junk3.ppm", $outfile);
 }
 
-#
-#  Clean up shop.
-#
-system("rm junk*$$.ppm");
-
 exit(0);
diff --git a/editor/ppmshadow b/editor/ppmshadow
index ae6b1b0f..438d4fa9 100755
--- a/editor/ppmshadow
+++ b/editor/ppmshadow
@@ -89,7 +89,7 @@ sub imageDimensions($) {
 sub backgroundColor($) {
     my ($fileName) = @_;
 #-----------------------------------------------------------------------------
-#  Return the color of the backround of the image in the file named $fileName.
+#  Return the color of the background of the image in the file named $fileName.
 #-----------------------------------------------------------------------------
     # We call the color of the top left pixel the background color.
 
@@ -198,7 +198,7 @@ if ($keeptemp) {
     mkdir($ourtmp, 0777) or
         die("Unable to create directory for temporary files '$ourtmp");
 } else {
-    $ourtmp = File::Temp::tempdir("$tmpdir/ppmshadowXXXX", UNLINK=>1);
+    $ourtmp = File::Temp::tempdir("$tmpdir/ppmshadowXXXX", CLEANUP=>1);
 }
 
 #   Apply defaults for arguments not specified
diff --git a/editor/specialty/pampaintspill.c b/editor/specialty/pampaintspill.c
index eb1888f7..7490fcef 100644
--- a/editor/specialty/pampaintspill.c
+++ b/editor/specialty/pampaintspill.c
@@ -6,7 +6,7 @@
  *
  * ----------------------------------------------------------------------
  *
- * Copyright (C) 2010 Scott Pakin <scott+pbm@pakin.org>
+ * Copyright (C) 2010-2021 Scott Pakin <scott+pbm@pakin.org>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -45,11 +45,11 @@
 
 #include "mallocvar.h"
 #include "nstring.h"
+#include "rand.h"
 #include "shhopt.h"
 #include "pam.h"
 #include "pammap.h"
 
-
 static time_t const timeUpdateDelta = 30;
     /* Seconds between progress updates */
 static int const    minUpdates = 4;
@@ -67,6 +67,10 @@ struct cmdlineInfo {
     unsigned int all;
     float        power;
     unsigned int downsample;
+    unsigned int randomseedSpec;
+    unsigned int randomseed;
+    unsigned int nearSpec;
+    unsigned int near;
 };
 
 struct coords {
@@ -98,16 +102,20 @@ parseCommandLine(int argc, const char ** const argv,
     MALLOCARRAY_NOFAIL(option_def, 100);
     option_def_index = 0;          /* Incremented by OPTENTRY */
 
-    OPTENT3(0, "bgcolor",    OPT_STRING, &cmdlineP->bgcolor,    
+    OPTENT3(0, "bgcolor",    OPT_STRING, &cmdlineP->bgcolor,
             &bgcolorSpec, 0);
     OPTENT3(0, "wrap",       OPT_FLAG,   NULL,
             &cmdlineP->wrap,       0);
     OPTENT3(0, "all",        OPT_FLAG,   NULL,
             &cmdlineP->all,        0);
-    OPTENT3(0, "power",      OPT_FLOAT,  &cmdlineP->power,      
+    OPTENT3(0, "power",      OPT_FLOAT,  &cmdlineP->power,
             &powerSpec, 0);
-    OPTENT3(0, "downsample", OPT_UINT,   &cmdlineP->downsample, 
+    OPTENT3(0, "downsample", OPT_UINT,   &cmdlineP->downsample,
             &downsampleSpec, 0);
+    OPTENT3(0, "randomseed", OPT_UINT,   &cmdlineP->randomseed,
+            &cmdlineP->randomseedSpec, 0);
+    OPTENT3(0, "near",       OPT_UINT,   &cmdlineP->near,
+            &cmdlineP->nearSpec, 0);
 
     opt.opt_table = option_def;
     opt.short_allowed = 0;
@@ -124,6 +132,11 @@ parseCommandLine(int argc, const char ** const argv,
     if (!downsampleSpec)
         cmdlineP->downsample = 0;
 
+    if (cmdlineP->nearSpec) {
+        if (cmdlineP->near == 0)
+            pm_error("The -near option requires a positive argument");
+    }
+
     if (argc-1 < 1)
         cmdlineP->inputFilename = "-";
     else {
@@ -223,7 +236,9 @@ locatePaintSources(struct pam *            const pamP,
                    tuple **                const tuples,
                    tuple                   const bgColor,
                    unsigned int            const downsample,
-                   struct paintSourceSet * const paintSourcesP) {
+                   struct paintSourceSet * const paintSourcesP,
+                   bool                    const randomseedSpec,
+                   unsigned int            const randomseed) {
 /*--------------------------------------------------------------------
   Construct a list of all pixel coordinates in the input image that
   represent a non-background color.
@@ -248,21 +263,24 @@ locatePaintSources(struct pam *            const pamP,
     pm_message("Image contains %u background + %u non-background pixels",
                pamP->width * pamP->height - paintSources.size,
                paintSources.size);
-    
+
     /* Reduce the number of paint sources to reduce execution time. */
     if (downsample > 0 && downsample < paintSources.size) {
+        struct pm_randSt randSt;
         unsigned int i;
 
-        srand(pm_randseed());
+        pm_randinit(&randSt);
+        pm_srand2(&randSt, randomseedSpec, randomseed);
 
         for (i = 0; i < downsample; ++i) {
             unsigned int const swapIdx =
-                i + rand() % (paintSources.size - i);
+                i + pm_rand(&randSt) % (paintSources.size - i);
             struct coords const swapVal = paintSources.list[i];
 
             paintSources.list[i] = paintSources.list[swapIdx];
             paintSources.list[swapIdx] = swapVal;
         }
+        pm_randterm(&randSt);
         paintSources.size = downsample;
     }
 
@@ -281,7 +299,7 @@ euclideanDistanceSqr(const struct coords * const p0,
                      unsigned int          const width,
                      unsigned int          const height) {
 /*----------------------------------------------------------------------------
-   Return the square of the Euclidian distance between p0 and p1.
+   Return the square of the Euclidean distance between p0 and p1.
 -----------------------------------------------------------------------------*/
     double const deltax = (double) (int) (p1->x - p0->x);
     double const deltay = (double) (int) (p1->y - p0->y);
@@ -299,7 +317,7 @@ euclideanDistanceTorusSqr(const struct coords * const p0,
                           unsigned int          const width,
                           unsigned int          const height) {
 /*----------------------------------------------------------------------------
-   Return the square of the Euclidian distance between p0 and p1, assuming
+   Return the square of the Euclidean distance between p0 and p1, assuming
    it's a toroidal surface on which the top row curves around to meet the
    bottom and the left column to the right.
 -----------------------------------------------------------------------------*/
@@ -356,6 +374,70 @@ reportProgress(unsigned int const rowsComplete,
 
 
 
+struct distanceList {
+    struct coords * sources;  /* malloc'ed */
+        /* The list of places in the image from which paint comes */
+    double * distSqrs;        /* malloc'ed */
+        /* The list of squared distances from the current point */
+    unsigned int size;
+        /* Number of entries in sources[] */
+};
+
+
+
+static void
+computeDistances(struct pam *           const pamP,
+                 struct coords          const target,
+                 struct paintSourceSet  const paintSources,
+                 distFunc_t *           const distFunc,
+                 bool                   const nearOnly,
+                 unsigned int           const numNear,
+                 struct distanceList *  const distancesP) {
+
+    unsigned int ps;
+
+    /* Acquire a list of all distances. */
+    distancesP->size = 0;
+    for (ps = 0; ps < paintSources.size; ++ps) {
+        struct coords const source = paintSources.list[ps];
+        double const distSqr =
+            (*distFunc)(&target, &source,
+                        pamP->width, pamP->height);
+        distancesP->sources[distancesP->size]  = source;
+        distancesP->distSqrs[distancesP->size] = distSqr;
+        ++distancesP->size;
+    }
+
+    /* If requested, truncate the list to the smallest numNear distances. */
+    if (nearOnly && numNear < distancesP->size) {
+        unsigned int i;
+
+        /* Perform a partial sort -- just enough to identify the numNear
+           smallest distances.  For performance reasons we assume that
+           numNear is much less than paintSources.size (say, less than
+           log2(paintSources.size)).
+        */
+        for (i = 0; i < numNear; ++i) {
+            unsigned int j;
+            for (j = i + 1; j < distancesP->size; ++j) {
+                if (distancesP->distSqrs[i] > distancesP->distSqrs[j]) {
+                    /* Swap elements i and j. */
+                    struct coords const src   = distancesP->sources[i];;
+                    double        const dist2 = distancesP->distSqrs[i];
+
+                    distancesP->sources[i]  = distancesP->sources[j];
+                    distancesP->distSqrs[i] = distancesP->distSqrs[j];
+                    distancesP->sources[j]  = src;
+                    distancesP->distSqrs[j] = dist2;
+                }
+            }
+        }
+        distancesP->size = numNear;
+    }
+}
+
+
+
 static void
 spillOnePixel(struct pam *          const pamP,
               struct coords         const target,
@@ -363,37 +445,38 @@ spillOnePixel(struct pam *          const pamP,
               distFunc_t *          const distFunc,
               double                const distPower,
               tuple                 const outTuple,
-              double *              const newColor) {
+              double *              const newColor,
+              bool                  const nearOnly,
+              unsigned int          const numNear,
+              struct distanceList * const distancesP) {
 
     unsigned int plane;
-    unsigned int ps;
+    unsigned int d;
     double       totalWeight;
 
     for (plane = 0; plane < pamP->depth; ++plane)
         newColor[plane] = 0.0;
+    computeDistances(pamP, target, paintSources, distFunc,
+                     nearOnly, numNear, distancesP);
     totalWeight = 0.0;
-    for (ps = 0; ps < paintSources.size; ++ps) {
-        struct coords const source = paintSources.list[ps];
-        double const distSqr =
-            (*distFunc)(&target, &source,
-                        pamP->width, pamP->height);
+    for (d = 0; d < distancesP->size; ++d) {
+        double        const distSqr = distancesP->distSqrs[d];
+        struct coords const source  = distancesP->sources[d];
 
-        if (distSqr > 0.0) {
-            /* We do special cases for some common cases with code
-               that is much faster than pow().
-            */
-            double const weight =
-                distPower == -2.0 ? 1.0 / distSqr :
-                distPower == -1.0 ? 1.0 / sqrt(distSqr):
-                pow(distSqr, distPower/2);
+        /* We do special cases for some common cases with code
+           that is much faster than pow().
+        */
+        double const weight =
+            distPower == -2.0 ? 1.0 / distSqr :
+            distPower == -1.0 ? 1.0 / sqrt(distSqr):
+            pow(distSqr, distPower/2);
 
-            unsigned int plane;
+        unsigned int plane;
 
-            for (plane = 0; plane < pamP->depth; ++plane)
-                newColor[plane] += weight * source.color[plane];
+        for (plane = 0; plane < pamP->depth; ++plane)
+            newColor[plane] += weight * source.color[plane];
 
-            totalWeight += weight;
-        }
+        totalWeight += weight;
     }
     for (plane = 0; plane < pamP->depth; ++plane)
         outTuple[plane] = (sample) (newColor[plane] / totalWeight);
@@ -409,6 +492,8 @@ produceOutputImage(struct pam *          const pamP,
                    distFunc_t *          const distFunc,
                    double                const distPower,
                    bool                  const all,
+                   bool                  const nearOnly,
+                   unsigned int          const numNear,
                    tuple ***             const outtuplesP) {
 /*--------------------------------------------------------------------
   Color each background pixel (or, if allPixels is 1, all pixels)
@@ -424,10 +509,14 @@ produceOutputImage(struct pam *          const pamP,
     rowsComplete = 0;
     #pragma omp parallel for
     for (row = 0; row < pamP->height; ++row) {
-        struct coords   target;
-        double        * newColor;
-        
+        struct coords         target;
+        double *              newColor;   /* malloc'ed */
+        struct distanceList * distancesP; /* malloc'ed */
+
         MALLOCARRAY(newColor, pamP->depth);
+        MALLOCVAR_NOFAIL(distancesP);
+        MALLOCARRAY_NOFAIL(distancesP->sources,  paintSources.size);
+        MALLOCARRAY_NOFAIL(distancesP->distSqrs, paintSources.size);
 
         target.y = row;
         for (target.x = 0; target.x < pamP->width; ++target.x) {
@@ -436,13 +525,17 @@ produceOutputImage(struct pam *          const pamP,
 
             if (all || tupleEqualColor(pamP, targetTuple, bgColor))
                 spillOnePixel(pamP, target, paintSources, distFunc, distPower,
-                              outputTuple, newColor);
+                              outputTuple, newColor, nearOnly, numNear,
+                              distancesP);
             else
                 pnm_assigntuple(pamP,  outputTuple, targetTuple);
         }
         #pragma omp critical (rowTally)
         reportProgress(++rowsComplete, pamP->height);
 
+        free(distancesP->distSqrs);
+        free(distancesP->sources);
+        free(distancesP);
         free(newColor);
     }
     *outtuplesP = outtuples;
@@ -484,10 +577,12 @@ main(int argc, const char *argv[]) {
                pnm_colorname(&inPam, bgColor, PAM_COLORNAME_HEXOK));
 
     locatePaintSources(&inPam, inTuples, bgColor, cmdline.downsample,
-                       &paintSources);
+                       &paintSources,
+                       cmdline.randomseedSpec, cmdline.randomseed);
 
     produceOutputImage(&inPam, inTuples, bgColor, paintSources, distFunc,
-                       cmdline.power, cmdline.all, &outTuples);
+                       cmdline.power, cmdline.all,
+                       cmdline.nearSpec, cmdline.near, &outTuples);
 
     outPam = inPam;
     outPam.file = stdout;
@@ -498,3 +593,6 @@ main(int argc, const char *argv[]) {
 
     return 0;
 }
+
+
+
diff --git a/editor/specialty/pampop9.c b/editor/specialty/pampop9.c
index d6c61e4f..b92c7d6b 100644
--- a/editor/specialty/pampop9.c
+++ b/editor/specialty/pampop9.c
@@ -25,9 +25,6 @@
 
 #include "pam.h"
 
-static const char * const copyright = 
-  "(c) Robert Tinsley 2003 (http://www.thepoacher.net/contact)";
-
 static const char *usagestr = "pnmfile|- xtiles ytiles xdelta ydelta";
 
 int main(int argc, char *argv[])
diff --git a/editor/specialty/pgmabel.c b/editor/specialty/pgmabel.c
index 0f4233ac..5badfd19 100644
--- a/editor/specialty/pgmabel.c
+++ b/editor/specialty/pgmabel.c
@@ -44,7 +44,7 @@ static const char* const version="$VER: pgmabel 1.009 (24 Jan 2002)";
 #include "pgm.h"
 
 #ifndef PID2          /*  PI/2 (on AMIGA always defined) */
-#define PID2    1.57079632679489661923  
+#define PID2    1.57079632679489661923
 #endif
 
 
@@ -59,7 +59,7 @@ static double *aldl, *ardl;                /* pointer for weighting factors */
 **      xr    <-  array of the calculated elements of the row
 **      adl   <-  pre-calculated surface coefficient for each segment
 */
-static double 
+static double
 Sum ( int n, double *xr, int N, double *adl)
 {
     int k;
@@ -79,7 +79,7 @@ Sum ( int n, double *xr, int N, double *adl)
 **      R, N  <-  indizes of the coefficient
 **      r     <-  radial position of the center of the surface
 */
-static double 
+static double
 dr ( int R, double r,  int N)
 {
     double a;
@@ -95,7 +95,7 @@ dr ( int R, double r,  int N)
 **        N    <-  width of the array
 **        adl  <-  array with pre-calculated weighting factors
 */
-static void 
+static void
 abel ( float *y, int N, double *adl)
 {
     register int n;
@@ -126,7 +126,7 @@ abel ( float *y, int N, double *adl)
 /* ----------------------------------------------------------------------------
 ** printing a help message if Option -h(elp) is chosen
 */
-static void 
+static void
 help()
 {
     pm_message("-----------------------------------------------------------------");
@@ -142,7 +142,7 @@ help()
     pm_message("|   verbose : output of useful data                             |");
     pm_message("|   pgmfile : Name of a pgmfile (optional)                      |");
     pm_message("|                                                               |");
-    pm_message("| for further information please contact the manpage            |"); 
+    pm_message("| for further information please contact the manpage            |");
     pm_message("-----------------------------------------------------------------");
     pm_message("%s",version);     /* telling the version      */
     exit(-1);                     /* retur-code for no result */
@@ -267,11 +267,11 @@ int main( argc, argv )
     }
     for (col = 0; col < (cols-midcol); ++col)      /* factors for right side */
     {
-        for (tc = 0; tc < (cols-midcol); ++tc) 
+        for (tc = 0; tc < (cols-midcol); ++tc)
             ardl[col*(cols-midcol)+tc] = dr(col,tc+0.5,cols-midcol);
     }
 
-    /* abel-transformation for each row splitted in right and left side      */
+    /* abel-transformation for each row split into right and left side      */
     for ( row = 0; row < rows ; ++row )
     {
         pgm_readpgmrow( ifp, grayorig, cols, maxval, format );
@@ -308,3 +308,5 @@ int main( argc, argv )
     exit( 0 );                       /* end of procedure                     */
 }
 
+
+
diff --git a/editor/specialty/pnmindex.c b/editor/specialty/pnmindex.c
index 438fe058..2b39e4ec 100644
--- a/editor/specialty/pnmindex.c
+++ b/editor/specialty/pnmindex.c
@@ -1,5 +1,5 @@
 /*============================================================================
-                              pnmindex   
+                                pnmindex
 ==============================================================================
 
   build a visual index of a bunch of PNM images
@@ -32,7 +32,7 @@
 #include "nstring.h"
 #include "pnm.h"
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -56,11 +56,11 @@ systemf(const char * const fmt,
         ...) {
 
     va_list varargs;
-    
+
     size_t dryRunLen;
-    
+
     va_start(varargs, fmt);
-    
+
     pm_vsnprintf(NULL, 0, fmt, varargs, &dryRunLen);
 
     va_end(varargs);
@@ -83,7 +83,7 @@ systemf(const char * const fmt,
             va_start(varargs, fmt);
 
             pm_vsnprintf(shellCommand, allocSize, fmt, varargs, &realLen);
-                
+
             assert(realLen == dryRunLen);
             va_end(varargs);
 
@@ -94,12 +94,12 @@ systemf(const char * const fmt,
             if (rc != 0)
                 pm_error("shell command '%s' failed.  rc %d",
                          shellCommand, rc);
-            
+
             pm_strfree(shellCommand);
         }
     }
 }
-        
+
 
 
 static const char *
@@ -168,8 +168,8 @@ shellQuote(const char * const arg) {
 
 
 static void
-parseCommandLine(int argc, char ** argv, 
-                 struct cmdlineInfo * const cmdlineP) {
+parseCommandLine(int argc, char ** argv,
+                 struct CmdlineInfo * const cmdlineP) {
 
     unsigned int option_def_index;
     optEntry *option_def;
@@ -183,13 +183,13 @@ parseCommandLine(int argc, char ** argv,
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENT3 */
-    OPTENT3(0, "black",       OPT_FLAG,   NULL,                  
+    OPTENT3(0, "black",       OPT_FLAG,   NULL,
             &cmdlineP->black,         0);
-    OPTENT3(0, "noquant",     OPT_FLAG,   NULL,                  
+    OPTENT3(0, "noquant",     OPT_FLAG,   NULL,
             &cmdlineP->noquant,       0);
-    OPTENT3(0, "quant",       OPT_FLAG,   NULL,                  
+    OPTENT3(0, "quant",       OPT_FLAG,   NULL,
             &quant,                   0);
-    OPTENT3(0, "verbose",     OPT_FLAG,   NULL,                  
+    OPTENT3(0, "verbose",     OPT_FLAG,   NULL,
             &cmdlineP->verbose,       0);
     OPTENT3(0, "size",        OPT_UINT,   &cmdlineP->size,
             &sizeSpec,                0);
@@ -202,7 +202,7 @@ parseCommandLine(int argc, char ** argv,
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
-    opt.allowNegNum = FALSE; 
+    opt.allowNegNum = FALSE;
 
     pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdline_p and others. */
@@ -212,7 +212,7 @@ parseCommandLine(int argc, char ** argv,
 
     if (!colorsSpec)
         cmdlineP->colors = 256;
-    
+
     if (!sizeSpec)
         cmdlineP->size = 100;
 
@@ -246,7 +246,7 @@ parseCommandLine(int argc, char ** argv,
 
 
 static void
-freeCmdline(struct cmdlineInfo const cmdline) {
+freeCmdline(struct CmdlineInfo const cmdline) {
 
     unsigned int i;
 
@@ -326,9 +326,9 @@ rowFileName(const char * const dirName,
             unsigned int const row) {
 
     const char * fileName;
-    
+
     pm_asprintf(&fileName, "%s/pi.%u", dirName, row);
-    
+
     return fileName;
 }
 
@@ -368,7 +368,7 @@ copyImage(const char * const inputFileName,
     systemf("cat %s > %s", inputFileNmToken, outputFileName);
 
     pm_strfree(inputFileNmToken);
-} 
+}
 
 
 
@@ -386,26 +386,26 @@ copyScaleQuantImage(const char * const inputFileName,
 
     switch (PNM_FORMAT_TYPE(format)) {
     case PBM_TYPE:
-        pm_asprintf(&scaleCommand, 
+        pm_asprintf(&scaleCommand,
                     "pamscale -quiet -xysize %u %u %s "
                     "| pgmtopbm > %s",
                     size, size, inputFileNmToken, outputFileName);
         break;
-        
+
     case PGM_TYPE:
-        pm_asprintf(&scaleCommand, 
+        pm_asprintf(&scaleCommand,
                     "pamscale -quiet -xysize %u %u %s >%s",
                     size, size, inputFileNmToken, outputFileName);
         break;
-        
+
     case PPM_TYPE:
         if (quant)
-            pm_asprintf(&scaleCommand, 
+            pm_asprintf(&scaleCommand,
                         "pamscale -quiet -xysize %u %u %s "
                         "| pnmquant -quiet %u > %s",
                         size, size, inputFileNmToken, colors, outputFileName);
         else
-            pm_asprintf(&scaleCommand, 
+            pm_asprintf(&scaleCommand,
                         "pamscale -quiet -xysize %u %u %s >%s",
                         size, size, inputFileNmToken, outputFileName);
         break;
@@ -426,7 +426,7 @@ formatTypeMax(int const typeA,
               int const typeB) {
 
     if (typeA == PPM_TYPE || typeB == PPM_TYPE)
-        return PPM_TYPE; 
+        return PPM_TYPE;
     else if (typeA == PGM_TYPE || typeB == PGM_TYPE)
         return PGM_TYPE;
     else
@@ -441,9 +441,9 @@ thumbnailFileName(const char * const dirName,
                   unsigned int const col) {
 
     const char * fileName;
-    
+
     pm_asprintf(&fileName, "%s/pi.%u.%u", dirName, row, col);
-    
+
     return fileName;
 }
 
@@ -464,7 +464,7 @@ thumbnailFileList(const char * const dirName,
         pm_error("Unable to allocate %u bytes for file list", maxListSize);
 
     list[0] = '\0';
-    
+
     for (col = 0; col < cols; ++col) {
         const char * const fileName = thumbnailFileName(dirName, row, col);
 
@@ -487,19 +487,28 @@ makeImageFile(const char * const thumbnailFileName,
               const char * const inputFileName,
               bool         const blackBackground,
               const char * const outputFileName) {
+/*----------------------------------------------------------------------------
+   Create one thumbnail image.  It consists of the image in the file named
+   'thumbnailFileName' with text of that name appended to the bottom.
 
+   Write the result to the file named 'outputFileName'.
+
+   'blackBackground' means give the image a black background where padding
+   is necessary and make the text white on black.  If false, give the image
+   a white background instead.
+-----------------------------------------------------------------------------*/
     const char * const blackWhiteOpt = blackBackground ? "-black" : "-white";
     const char * const invertStage   = blackBackground ? "| pnminvert " : "";
     const char * inputFileNmToken    = shellQuote(inputFileName);
 
     systemf("pbmtext %s %s"
-            "| pnmcat %s -topbottom %s - "
+            "| pamcat %s -topbottom %s - "
             "> %s",
             inputFileNmToken, invertStage, blackWhiteOpt,
             thumbnailFileName, outputFileName);
 
     pm_strfree(inputFileNmToken);
-}    
+}
 
 
 
@@ -519,21 +528,21 @@ makeThumbnail(const char *  const inputFileName,
     xelval maxval;
     const char * tmpfile;
     const char * fileName;
-        
+
     ifP = pm_openr(inputFileName);
     pnm_readpnminit(ifP, &imageCols, &imageRows, &maxval, &format);
     pm_close(ifP);
-    
+
     pm_asprintf(&tmpfile, "%s/pi.tmp", tempDir);
 
     if (imageCols < size && imageRows < size)
         copyImage(inputFileName, tmpfile);
     else
-        copyScaleQuantImage(inputFileName, tmpfile, format, 
+        copyScaleQuantImage(inputFileName, tmpfile, format,
                             size, quant, colors);
 
     fileName = thumbnailFileName(tempDir, row, col);
-        
+
     makeImageFile(tmpfile, inputFileName, black, fileName);
 
     unlink(tmpfile);
@@ -543,7 +552,7 @@ makeThumbnail(const char *  const inputFileName,
 
     *formatP = format;
 }
-        
+
 
 
 static void
@@ -552,7 +561,7 @@ unlinkThumbnailFiles(const char * const dirName,
                      unsigned int const cols) {
 
     unsigned int col;
-    
+
     for (col = 0; col < cols; ++col) {
         const char * const fileName = thumbnailFileName(dirName, row, col);
 
@@ -569,7 +578,7 @@ unlinkRowFiles(const char * const dirName,
                unsigned int const rows) {
 
     unsigned int row;
-    
+
     for (row = 0; row < rows; ++row) {
         const char * const fileName = rowFileName(dirName, row);
 
@@ -595,7 +604,7 @@ combineIntoRowAndDelete(unsigned int const row,
     const char * fileName;
     const char * quantStage;
     const char * fileList;
-    
+
     fileName = rowFileName(tempDir, row);
 
     unlink(fileName);
@@ -607,7 +616,7 @@ combineIntoRowAndDelete(unsigned int const row,
 
     fileList = thumbnailFileList(tempDir, row, cols);
 
-    systemf("pnmcat %s -leftright -jbottom %s "
+    systemf("pamcat %s -leftright -jbottom %s "
             "%s"
             ">%s",
             blackWhiteOpt, fileList, quantStage, fileName);
@@ -641,7 +650,7 @@ rowFileList(const char * const dirName,
 
         if (strlen(list) + strlen(fileName) + 1 > maxListSize - 1)
             pm_error("File name list too long for this program to handle.");
-        
+
         else {
             strcat(list, " ");
             strcat(list, fileName);
@@ -666,7 +675,7 @@ writeRowsAndDelete(unsigned int const rows,
 
     const char * quantStage;
     const char * fileList;
-    
+
     if (maxFormatType == PPM_TYPE && quant)
         pm_asprintf(&quantStage, "| pnmquant -quiet %u ", colors);
     else
@@ -674,7 +683,7 @@ writeRowsAndDelete(unsigned int const rows,
 
     fileList = rowFileList(tempDir, rows);
 
-    systemf("pnmcat %s -topbottom %s %s",
+    systemf("pamcat %s -topbottom %s %s",
             blackWhiteOpt, fileList, quantStage);
 
     pm_strfree(fileList);
@@ -687,7 +696,7 @@ writeRowsAndDelete(unsigned int const rows,
 
 int
 main(int argc, char *argv[]) {
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     const char * tempDir;
     int maxFormatType;
     unsigned int colsInRow;
@@ -699,7 +708,7 @@ main(int argc, char *argv[]) {
     parseCommandLine(argc, argv, &cmdline);
 
     verbose = cmdline.verbose;
-    
+
     makeTempDir(&tempDir);
 
     maxFormatType = PBM_TYPE;
@@ -714,7 +723,7 @@ main(int argc, char *argv[]) {
 
         int format;
 
-        makeThumbnail(inputFileName, cmdline.size, cmdline.black, 
+        makeThumbnail(inputFileName, cmdline.size, cmdline.black,
                       !cmdline.noquant, cmdline.colors, tempDir,
                       rowsDone, colsInRow, &format);
 
@@ -742,3 +751,6 @@ main(int argc, char *argv[]) {
 
     return 0;
 }
+
+
+
diff --git a/editor/specialty/ppmshift.c b/editor/specialty/ppmshift.c
index a765daa5..27cbb78c3 100644
--- a/editor/specialty/ppmshift.c
+++ b/editor/specialty/ppmshift.c
@@ -9,124 +9,183 @@
 /* V1.1    16.11.1993  Rewritten to be NetPBM.programming conforming */
 /*********************************************************************/
 
+#include <stdbool.h>
+
+#include "mallocvar.h"
+#include "rand.h"
+#include "shhopt.h"
 #include "ppm.h"
 
-/**************************/
-/* start of main function */
-/**************************/
+
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char * inputFileName;
+
+    unsigned int shift;
+    unsigned int seedSpec;
+    unsigned int seed;
+};
+
+
+
+static void
+parseCommandLine(int argc, const char ** const argv,
+                 struct CmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   Note that the file spec array we return is stored in the storage that
+   was passed to us as the argv array.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;
+        /* Instructions to OptParseOptions3 on how to parse our options. */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+
+    MALLOCARRAY(option_def, 100);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = false;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = true;  /* We have no parms that are negative numbers */
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0,   "seed",            OPT_UINT,     &cmdlineP->seed,
+            &cmdlineP->seedSpec,         0);
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (argc-1 < 1)
+        pm_error("You must specify the shift factor as an argument");
+    else {
+        int const arg1 = atoi(argv[1]);
+        if (arg1 < 0)
+            pm_error("shift factor must be 0 or more");
+        cmdlineP->shift = arg1;
+
+        if (argc-1 < 2)
+            cmdlineP->inputFileName = "-";
+        else {
+            cmdlineP->inputFileName = argv[2];
+
+            if (argc-1 > 2)
+                pm_error("Too many arguments (%u).  "
+                         "Shift factor and input file name are the only "
+                         "possible arguments", argc-1);
+        }
+    }
+    free(option_def);
+}
+
+
+
+static void
+shiftRow(pixel *            const srcrow,
+         unsigned int       const cols,
+         unsigned int       const shift,
+         pixel *            const destrow,
+         struct pm_randSt * const randStP) {
+
+    /* the range by which a line is shifted lays in the range from */
+    /* -shift/2 .. +shift/2 pixels; however, within this range it is */
+    /* randomly chosen */
+
+    pixel * pP;
+    pixel * pP2;
+    int nowshift;
+
+    if (shift != 0)
+        nowshift = (pm_rand(randStP) % (shift+1)) - ((shift+1) / 2);
+    else
+        nowshift = 0;
+
+    pP  = &srcrow[0];
+    pP2 = &destrow[0];
+
+    /* if the shift value is less than zero, we take the original
+       pixel line and copy it into the destination line translated
+       to the left by x pixels. The empty pixels on the right end
+       of the destination line are filled up with the pixel that
+       is the right-most in the original pixel line.
+    */
+    if (nowshift < 0) {
+        unsigned int col;
+        pP += abs(nowshift);
+        for (col = 0; col < cols; ++col) {
+            PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP));
+            ++pP2;
+            if (col < (cols + nowshift) - 1)
+                ++pP;
+        }
+    } else {
+        unsigned int col;
+        /* The shift value is 0 or positive, so fill the first
+           <nowshift> pixels of the destination line with the
+           first pixel from the source line, and copy the rest of
+           the source line to the dest line
+        */
+        for (col = 0; col < cols; ++col) {
+            PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP));
+            ++pP2;
+            if (col >= nowshift)
+                ++pP;
+        }
+    }
+}
+
+
+
 int
-main(int    argc,
-     char * argv[]) {
+main(int argc, const char ** argv) {
 
     FILE * ifP;
-    unsigned int row;
-    int argn, rows, cols, format;
+    struct CmdlineInfo cmdline;
+    int rows, cols, format;
+    pixval maxval;
     pixel * srcrow;
     pixel * destrow;
-    pixval maxval;
-    int shift, nowshift;
-    int shiftArg;
-
-    const char * const usage = "shift [ppmfile]\n        shift: maximum number of pixels to shift a line by\n";
+    unsigned int row;
+    unsigned int shift;
+    struct pm_randSt randSt;
 
     /* parse in 'default' parameters */
-    ppm_init(&argc, argv);
-
-    argn = 1;
-
-    /* parse in shift number */
-    if (argn == argc)
-        pm_usage(usage);
-    if (sscanf(argv[argn], "%d", &shiftArg) != 1)
-        pm_usage(usage);
-    if (shiftArg < 0)
-        pm_error("shift factor must be 0 or more");
-    ++argn;
-
-    /* parse in filename (if present, stdin otherwise) */
-    if (argn != argc)
-    {
-        ifP = pm_openr(argv[argn]);
-        ++argn;
-    }
-    else
-        ifP = stdin;
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    pm_randinit(&randSt);
+    pm_srand2(&randSt, cmdline.seedSpec, cmdline.seed);
 
-    if (argn != argc)
-        pm_usage(usage);
+    ifP = pm_openr(cmdline.inputFileName);
 
     /* read first data from file */
     ppm_readppminit(ifP, &cols, &rows, &maxval, &format);
 
-    if (shiftArg > cols) {
+    if (cmdline.shift > cols) {
         shift = cols;
-        pm_message("shift amount is larger than picture width - reset to %d",
+        pm_message("shift amount is larger than picture width - reset to %u",
                    shift);
     } else
-        shift = shiftArg;
-
-    srcrow = ppm_allocrow(cols);
+        shift = cmdline.shift;
 
+    srcrow  = ppm_allocrow(cols);
     destrow = ppm_allocrow(cols);
 
     ppm_writeppminit(stdout, cols, rows, maxval, 0);
 
-    srand(pm_randseed());
-
-    /** now do the shifting **/
-    /* the range by which a line is shifted lays in the range from */
-    /* -shift/2 .. +shift/2 pixels; however, within this range it is */
-    /* randomly chosen */
     for (row = 0; row < rows; ++row) {
-        pixel * pP;
-        pixel * pP2;
-
-        if (shift != 0)
-            nowshift = (rand() % (shift+1)) - ((shift+1) / 2);
-        else
-            nowshift = 0;
-
         ppm_readppmrow(ifP, srcrow, cols, maxval, format);
 
-        pP  = &srcrow[0];
-        pP2 = &destrow[0];
-
-        /* if the shift value is less than zero, we take the original
-           pixel line and copy it into the destination line translated
-           to the left by x pixels. The empty pixels on the right end
-           of the destination line are filled up with the pixel that
-           is the right-most in the original pixel line.
-        */
-        if (nowshift < 0) {
-            unsigned int col;
-            pP += abs(nowshift);
-            for (col = 0; col < cols; ++col) {
-                PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP));
-                ++pP2;
-                if (col < (cols + nowshift) - 1)
-                    ++pP;
-            }
-        } else {
-            unsigned int col;
-            /* The shift value is 0 or positive, so fill the first
-               <nowshift> pixels of the destination line with the
-               first pixel from the source line, and copy the rest of
-               the source line to the dest line
-            */
-            for (col = 0; col < cols; ++col) {
-                PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP));
-                ++pP2;
-                if (col >= nowshift)
-                    ++pP;
-            }
-        }
+        shiftRow(srcrow, cols, shift, destrow, &randSt);
 
         ppm_writeppmrow(stdout, destrow, cols, maxval, 0);
     }
 
-    pm_close(ifP);
-    ppm_freerow(srcrow);
     ppm_freerow(destrow);
+    ppm_freerow(srcrow);
+    pm_close(ifP);
+    pm_randterm(&randSt);
 
     return 0;
 }
diff --git a/editor/specialty/ppmspread.c b/editor/specialty/ppmspread.c
index 6753f4fe..7b9558e3 100644
--- a/editor/specialty/ppmspread.c
+++ b/editor/specialty/ppmspread.c
@@ -10,102 +10,158 @@
 
 #include <string.h>
 
+#include "nstring.h"
+#include "rand.h"
+#include "shhopt.h"
 #include "ppm.h"
 
 
+struct CmdlineInfo {
+    /* This structure represents all of the information the user
+       supplied in the command line but in a form that's easy for the
+       program to use.
+    */
+    const char * inputFilename;  /* '-' if stdin */
+    unsigned int spread;
+    unsigned int randomseedSpec;
+    unsigned int randomseed;
+};
+
+
+
+static void
+parseCommandLine(int argc, const char ** const argv,
+                 struct CmdlineInfo * const cmdlineP ) {
+
+    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 */
+
+    OPTENT3(0, "randomseed", OPT_UINT,   &cmdlineP->randomseed,
+            &cmdlineP->randomseedSpec, 0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = 0;
+    opt.allowNegNum = 1;
+
+    pm_optParseOptions3( &argc, (char **)argv, opt, sizeof(opt), 0 );
+
+    if (argc-1 < 1)
+        pm_error("You must specify the spread factor as an argument");
+    else {
+        const char * error;
+        pm_string_to_uint(argv[1], &cmdlineP->spread, &error);
+
+        if (error)
+            pm_error("Spread factor '%s' is not an unsigned integer.  %s",
+                     argv[1], error);
+
+        if (argc-1 < 2)
+            cmdlineP->inputFilename = "-";
+        else {
+            cmdlineP->inputFilename = argv[2];
+            if (argc-1 >2)
+                pm_error("Too many arguments: %u.  "
+                         "The only possible arguments are "
+                         "the spread factor and the optional input file name",
+                         argc-1);
+        }
+    }
+}
+
+
+
+static void
+spreadRow(pixel **           const srcarray,
+          unsigned int       const cols,
+          unsigned int       const rows,
+          unsigned int       const spread,
+          unsigned int       const row,
+          pixel **           const destarray,
+          struct pm_randSt * const randStP) {
+
+    unsigned int col;
+
+    for (col = 0; col < cols; ++col) {
+        pixel const p = srcarray[row][col];
+
+        int const xdis = (pm_rand(randStP) % (spread + 1) )
+            - ((spread + 1) / 2);
+        int const ydis = (pm_rand(randStP) % (spread + 1))
+            - ((spread + 1) / 2);
+
+        int const xnew = col + xdis;
+        int const ynew = row + ydis;
+
+        /* only set the displaced pixel if it's within the bounds
+           of the image
+        */
+        if (xnew >= 0 && xnew < cols && ynew >= 0 && ynew < rows) {
+            /* Displacing a pixel is accomplished by swapping it
+               with another pixel in its vicinity.
+            */
+            pixel const p2 = srcarray[ynew][xnew];
+                /* Original value of second pixel */
+
+            /* Set second pixel to new value */
+            PPM_ASSIGN(destarray[ynew][xnew],
+                       PPM_GETR(p), PPM_GETG(p), PPM_GETB(p));
+
+            /* Set first pixel to (old) value of second */
+            PPM_ASSIGN(destarray[row][col],
+                       PPM_GETR(p2), PPM_GETG(p2), PPM_GETB(p2));
+        } else {
+            /* Displaced pixel is out of bounds; leave the old pixel there.
+            */
+            PPM_ASSIGN(destarray[row][col],
+                       PPM_GETR(p), PPM_GETG(p), PPM_GETB(p));
+        }
+    }
+}
+
+
 
 int
-main(int    argc,
-     char * argv[]) {
+main(int          argc,
+     const char * argv[]) {
 
+    struct CmdlineInfo cmdline;
     FILE * ifP;
-    int argn, rows, cols;
+    int rows, cols;
     unsigned int row;
-    pixel ** destarray, ** srcarray;
-    pixel * pP;
-    pixel * pP2;
+    pixel ** destarray;
+    pixel ** srcarray;
     pixval maxval;
-    pixval r1, g1, b1;
-    int amount;
-    const char * const usage = "amount [ppmfile]\n        amount: # of pixels to displace a pixel by at most\n";
-
-    /* parse in 'default' parameters */
-    ppm_init(&argc, argv);
-
-    argn = 1;
-
-    /* parse in amount & seed */
-    if (argn == argc)
-        pm_usage(usage);
-    if (sscanf(argv[argn], "%d", &amount) != 1)
-        pm_usage(usage);
-    if (amount < 0)
-        pm_error("amount should be a positive number");
-    ++argn;
-
-    /* parse in filename (if present, stdin otherwise) */
-    if (argn != argc)
-    {
-        ifP = pm_openr(argv[argn]);
-        ++argn;
-    }
-    else
-        ifP = stdin;
+    struct pm_randSt randSt;
 
-    if (argn != argc)
-        pm_usage(usage);
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFilename);
 
     srcarray = ppm_readppm(ifP, &cols, &rows, &maxval);
 
     destarray = ppm_allocarray(cols, rows);
 
+    pm_randinit(&randSt);
+    pm_srand2(&randSt, cmdline.randomseedSpec, cmdline.randomseed);
+
     /* clear out the buffer */
     for (row = 0; row < rows; ++row)
         memset(destarray[row], 0, cols * sizeof(pixel));
 
-    srand(pm_randseed());
-
-    /* start displacing pixels */
+    /* Displace pixels */
     for (row = 0; row < rows; ++row) {
-        unsigned int col;
-        pP = &srcarray[row][0];
-
-        for (col = 0; col < cols; ++col) {
-            int const xdis = (rand() % (amount+1)) - ((amount+1) / 2);
-            int const ydis = (rand() % (amount+1)) - ((amount+1) / 2);
+        spreadRow(srcarray, cols, rows, cmdline.spread, row,
+                  destarray, &randSt);
 
-            int const xnew = col + xdis;
-            int const ynew = row + ydis;
-
-            /* only set the displaced pixel if it's within the bounds
-               of the image
-            */
-            if (xnew >= 0 && xnew < cols && ynew >= 0 && ynew < rows) {
-                /* displacing a pixel is accomplished by swapping it
-                   with another pixel in its vicinity - so, first
-                   store other pixel's RGB
-                */
-                pP2 = &srcarray[ynew][xnew];
-                r1 = PPM_GETR(*pP2);
-                g1 = PPM_GETG(*pP2);
-                b1 = PPM_GETB(*pP2);
-                /* set second pixel to new value */
-                pP2 = &destarray[ynew][xnew];
-                PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP));
-                
-                /* now, set first pixel to (old) value of second */
-                pP2 = &destarray[row][col];
-                PPM_ASSIGN(*pP2, r1, g1, b1);
-            } else {
-                /* displaced pixel is out of bounds; leave the old
-                   pixel there
-                */
-                pP2 = &destarray[row][col];
-                PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP));
-            }
-            ++pP;
-        }
     }
+    pm_randterm(&randSt);
 
     ppm_writeppm(stdout, destarray, cols, rows, maxval, 0);
 
@@ -115,3 +171,5 @@ main(int    argc,
 
     return 0;
 }
+
+
diff --git a/generator/Makefile b/generator/Makefile
index d54a6cc5..761181bd 100644
--- a/generator/Makefile
+++ b/generator/Makefile
@@ -18,7 +18,7 @@ SUBDIRS = pamtris
 
 PORTBINARIES = pamcrater pamgauss pamgradient \
 	       pamseq pamshadedrelief pamstereogram \
-	       pbmpage pbmmake pbmtext pbmupc \
+	       pbmpage pbmmake pbmnoise pbmtext pbmupc \
 	       pgmkernel pgmmake pgmnoise pgmramp \
 	       ppmcie ppmcolors ppmforge ppmmake ppmpat ppmrough ppmwheel \
 
diff --git a/generator/pamcrater.c b/generator/pamcrater.c
index 43c27dbc..b8ceafa5 100644
--- a/generator/pamcrater.c
+++ b/generator/pamcrater.c
@@ -48,6 +48,7 @@
 
 #include "pm_c_util.h"
 #include "mallocvar.h"
+#include "rand.h"
 #include "shhopt.h"
 #include "nstring.h"
 #include "pam.h"
@@ -169,11 +170,12 @@ static double const DepthBias2  = 0.5;      /* Square of depth bias */
 
 
 static double const
-cast(double const high) {
+cast(double             const high,
+     struct pm_randSt * const randStP) {
 /*----------------------------------------------------------------------------
    A random number in the range [0, 'high'].
 -----------------------------------------------------------------------------*/
-    return high * ((rand() & 0x7FFF) / arand);
+    return high * ((pm_rand(randStP) & 0x7FFF) / arand);
 }
 
 
@@ -252,11 +254,12 @@ setElev(struct pam * const pamP,
 
 
 static void
-smallCrater(struct pam * const pamP,
-            tuple **     const terrain,
-            int          const cx,
-            int          const cy,
-            double       const radius) {
+smallCrater(struct pam *       const pamP,
+            tuple **           const terrain,
+            int                const cx,
+            int                const cy,
+            double             const radius,
+            struct pm_randSt * const randStP) {
 /*----------------------------------------------------------------------------
    Generate a crater with a special method for tiny craters.
 
@@ -283,10 +286,10 @@ smallCrater(struct pam * const pamP,
             /* The mean elevation of the Moore neighborhood (9 pixels
                centered on the crater location).
             */
-        
+
         /* Perturb the mean elevation by a small random factor. */
 
-        int const x = radius >= 1 ? ((rand() >> 8) & 0x3) - 1 : 0;
+        int const x = radius >= 1 ? ((pm_rand(randStP) >> 8) & 0x3) - 1 : 0;
 
         assert(axelev > 0);
 
@@ -374,7 +377,7 @@ normalCrater(struct pam * const pamP,
                 av = (axelev + cz) * (1 - roll) +
                     (terrainMod(pamP, terrain, x, y) + cz) * roll;
                 av = MAX(1000, MIN(64000, av));
-                
+
                 setElev(pamP, terrain, x, y, av);
             }
         }
@@ -388,19 +391,20 @@ normalCrater(struct pam * const pamP,
 
 
 static void
-plopCrater(struct pam * const pamP,
-           tuple **     const terrain,
-           int          const cx,
-           int          const cy,
-           double       const radius,
-           bool         const verbose) {
+plopCrater(struct pam *       const pamP,
+           tuple **           const terrain,
+           int                const cx,
+           int                const cy,
+           double             const radius,
+           bool               const verbose,
+           struct pm_randSt * const randStP) {
 
     if (verbose && pm_have_float_format())
         pm_message("Plopping crater at (%4d, %4d) with radius %g",
                    cx, cy, radius);
 
     if (radius < 3)
-        smallCrater (pamP, terrain, cx, cy, radius);
+        smallCrater (pamP, terrain, cx, cy, radius, randStP);
     else
         normalCrater(pamP, terrain, cx, cy, radius);
 }
@@ -448,6 +452,7 @@ genCraters(struct CmdlineInfo const cmdline) {
 -----------------------------------------------------------------------------*/
     tuple ** terrain;    /* elevation array */
     struct pam pam;
+    struct pm_randSt randSt;
 
     /* Allocate the elevation array and initialize it to mean surface
        elevation.
@@ -455,18 +460,22 @@ genCraters(struct CmdlineInfo const cmdline) {
 
     initCanvas(cmdline.width, cmdline.height, &pam, &terrain);
 
+    pm_randinit(&randSt);
+    pm_srand2(&randSt, cmdline.randomseedSpec, cmdline.randomseed);
+
     if (cmdline.test)
         plopCrater(&pam, terrain,
                    pam.width/2 + cmdline.offset,
                    pam.height/2 + cmdline.offset,
-                   (double) cmdline.radius, cmdline.verbose);
+                   (double) cmdline.radius, cmdline.verbose,
+                   &randSt);
     else {
         unsigned int const ncraters = cmdline.number; /* num of craters */
         unsigned int l;
 
         for (l = 0; l < ncraters; ++l) {
-            int const cx = cast((double) pam.width  - 1);
-            int const cy = cast((double) pam.height - 1);
+            int const cx = cast((double) pam.width  - 1, &randSt);
+            int const cy = cast((double) pam.height - 1, &randSt);
 
             /* Thanks, Rudy, for this equation that maps the uniformly
                distributed numbers from cast() into an area-law distribution
@@ -475,9 +484,11 @@ genCraters(struct CmdlineInfo const cmdline) {
                Produces values within the interval:
                0.56419 <= radius <= 56.419
             */
-            double const radius = sqrt(1 / (M_PI * (1 - cast(0.9999))));
+            double const radius =
+                sqrt(1 / (M_PI * (1 - cast(0.9999, &randSt))));
 
-            plopCrater(&pam, terrain, cx, cy, radius, cmdline.verbose);
+            plopCrater(&pam, terrain, cx, cy, radius,
+                       cmdline.verbose, &randSt);
 
             if (((l + 1) % 100000) == 0)
                 pm_message("%u craters generated of %u (%u%% done)",
@@ -485,6 +496,8 @@ genCraters(struct CmdlineInfo const cmdline) {
         }
     }
 
+    pm_randterm(&randSt);
+
     pnm_writepam(&pam, terrain);
 
     pnm_freepamarray(terrain, &pam);
@@ -503,12 +516,9 @@ main(int argc, const char ** argv) {
 
     parseCommandLine(argc, argv, &cmdline);
 
-    srand(cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed());
-
     genCraters(cmdline);
 
     return 0;
 }
 
 
-
diff --git a/generator/pamseq.c b/generator/pamseq.c
index 1af5252a..4c00e2a5 100644
--- a/generator/pamseq.c
+++ b/generator/pamseq.c
@@ -1,3 +1,4 @@
+#include <assert.h>
 #include <string.h>
 #include <unistd.h>
 #include <stdlib.h>
@@ -6,49 +7,173 @@
 #include "pm_c_util.h"
 #include "pam.h"
 #include "shhopt.h"
+#include "mallocvar.h"
+#include "nstring.h"
 
 
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
     unsigned int depth;
     sample maxval;
     const char * tupletype;
+    sample * min;   /* array of size 'depth' */
+    sample * max;   /* array of size 'depth' */
+    sample * step;  /* array of size 'depth' */
 };
 
 
 
 static void
-parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo * const cmdlineP) {
+destroyCmdline(struct CmdlineInfo * const cmdlineP)  {
+
+    if (cmdlineP->min)
+        free(cmdlineP->min);
+    if (cmdlineP->max)
+        free(cmdlineP->max);
+    if (cmdlineP->step)
+        free(cmdlineP->step);
+}
+
+
+
+static unsigned int
+entryCt(char ** const stringList) {
+
+    unsigned int i;
+
+    for (i = 0; stringList[i]; ++i) {}
+
+    return i;
+}
+
+
+
+static void
+parseOptList(bool         const isSpec,
+             char **      const stringList,
+             unsigned int const depth,
+             sample       const maxval,
+             const char * const optNm,
+             sample **    const sampleListP) {
+
+    if (!isSpec)
+        *sampleListP = NULL;
+    else {
+        unsigned int i;
+        sample * sampleList;
+        const char * memberError;
+
+        if (entryCt(stringList) != depth) {
+            pm_error("Wrong number of values for -%s: %u.  Need %u",
+                     optNm, entryCt(stringList), depth);
+        }
+
+        MALLOCARRAY(sampleList, depth);
+
+        for (i = 0, memberError = NULL; i < depth && !memberError; ++i) {
+            char * endPtr;
+            long const n = strtol(stringList[i], &endPtr, 10);
+
+            if (strlen(stringList[i]) == 0)
+                pm_asprintf(&memberError, "is null string");
+            else if (*endPtr != '\0')
+                pm_asprintf(&memberError,
+                            "contains non-numeric character '%c'",
+                            *endPtr);
+            else if (n < 0)
+                pm_asprintf(&memberError, "is negative");
+            else if (n > maxval)
+                pm_asprintf(&memberError, "is greater than maxval %lu",
+                            maxval);
+            else
+                sampleList[i] = n;
+        }
+        if (memberError) {
+            free(sampleList);
+            pm_errormsg("Value in -%s %s", optNm, memberError);
+            pm_longjmp();
+        }
+        *sampleListP = sampleList;
+    }
+}
+
+
+
+static void
+validateMinIsAtMostMax(sample *     const min,
+                       sample *     const max,
+                       unsigned int const depth) {
+
+    unsigned int plane;
+
+    for (plane = 0; plane < depth; ++plane) {
+        if (min[plane] > max[plane])
+            pm_error("-min for plane %u (%lu) is greater than -max (%lu)",
+                     plane, min[plane], max[plane]);
+    }
+}
+
+
+
+static void
+validateStepIsPositive(sample *     const step,
+                       unsigned int const depth) {
+
+    unsigned int plane;
+
+    for (plane = 0; plane < depth; ++plane) {
+        if (step[plane] <= 0)
+            pm_error("-step for plane %u (%lu) is not positive",
+                     plane, step[plane]);
+    }
+}
+
+
+
+static void
+parseCommandLine(int argc, const char ** argv,
+                 struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
-  Convert program invocation arguments (argc,argv) into a format the 
+  Convert program invocation arguments (argc,argv) into a format the
   program can use easily, struct cmdlineInfo.  Validate arguments along
   the way and exit program with message if invalid.
 
-  Note that some string information we return as *cmdlineP is in the storage 
+  Note that some string information we return as *cmdlineP is in the storage
   argv[] points to.
 -----------------------------------------------------------------------------*/
-    optEntry *option_def = malloc(100*sizeof(optEntry));
-        /* Instructions to OptParseOptions2 on how to parse our options.
-         */
+    optEntry *option_def;
     optStruct3 opt;
-
+        /* Instructions to pm_optParseOptions3 on how to parse our options. */
+
+    unsigned int maxSpec;
+    char ** max;
+    unsigned int minSpec;
+    char ** min;
+    unsigned int stepSpec;
+    char ** step;
     unsigned int tupletypeSpec;
     unsigned int option_def_index;
 
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
     option_def_index = 0;   /* incremented by OPTENT3 */
-    OPTENT3(0,   "tupletype",  OPT_STRING, &cmdlineP->tupletype, 
+    OPTENT3(0,   "tupletype",  OPT_STRING, &cmdlineP->tupletype,
             &tupletypeSpec,     0);
-
+    OPTENT3(0,   "min",         OPT_STRINGLIST, &min,
+            &minSpec,           0);
+    OPTENT3(0,   "max",         OPT_STRINGLIST, &max,
+            &maxSpec,           0);
+    OPTENT3(0,   "step",        OPT_STRINGLIST, &step,
+            &stepSpec,          0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (!tupletypeSpec)
@@ -57,9 +182,9 @@ parseCommandLine(int argc, char ** argv,
         struct pam pam;
         if (strlen(cmdlineP->tupletype)+1 > sizeof(pam.tuple_type))
             pm_error("The tuple type you specified is too long.  "
-                     "Maximum %u characters.", 
+                     "Maximum %u characters.",
                      (unsigned)sizeof(pam.tuple_type)-1);
-    }        
+    }
 
     if (argc-1 < 2)
         pm_error("Need two arguments: depth and maxval.");
@@ -77,73 +202,154 @@ parseCommandLine(int argc, char ** argv,
                      "specified '%s'", argv[2]);
         if (cmdlineP->maxval > PNM_OVERALLMAXVAL)
             pm_error("The maxval you specified (%u) is too big.  "
-                     "Maximum is %u", (unsigned int) cmdlineP->maxval, 
+                     "Maximum is %u", (unsigned int) cmdlineP->maxval,
                      PNM_OVERALLMAXVAL);
-        if (pm_maxvaltobits(cmdlineP->maxval) + 
+        if (pm_maxvaltobits(cmdlineP->maxval) +
             pm_maxvaltobits(cmdlineP->depth-1) > sizeof(unsigned int)*8)
             pm_error("The maxval (%u) and depth (%u) you specified result "
                      "in a larger number of tuples than this program can "
-                     "handle (roughly %u)", 
+                     "handle (roughly %u)",
                      (unsigned int) cmdlineP->maxval, cmdlineP->depth,
                      (unsigned int) -1);
     }
+    parseOptList(minSpec, min,  cmdlineP->depth, cmdlineP->maxval, "min",
+                 &cmdlineP->min);
+    parseOptList(maxSpec, max,  cmdlineP->depth, cmdlineP->maxval, "max",
+                 &cmdlineP->max);
+    parseOptList(stepSpec, step, cmdlineP->depth, cmdlineP->maxval, "step",
+                 &cmdlineP->step);
+
+    if (cmdlineP->min && cmdlineP->max)
+        validateMinIsAtMostMax(cmdlineP->min, cmdlineP->max, cmdlineP->depth);
+
+    if (cmdlineP->step)
+        validateStepIsPositive(cmdlineP->step, cmdlineP->depth);
+
+    if (minSpec)
+        free(min);
+    if (maxSpec)
+        free(max);
+    if (stepSpec)
+        free(step);
 }
 
 
 
-static unsigned int
-powint(unsigned int base, unsigned int exponent) {
+static void
+computeMinMaxStep(unsigned int   const depth,
+                  sample         const maxval,
+                  const sample * const min,
+                  const sample * const max,
+                  const sample * const step,
+                  sample **      const minP,
+                  sample **      const maxP,
+                  sample **      const stepP) {
+
+    unsigned int plane;
+
+    MALLOCARRAY(*minP,  depth);
+    MALLOCARRAY(*maxP,  depth);
+    MALLOCARRAY(*stepP, depth);
+
+    for (plane = 0; plane < depth; ++plane) {
+        (*minP)[plane]  = min  ? min[plane]  : 0;
+        (*maxP)[plane]  = max  ? max[plane]  : maxval;
+        (*stepP)[plane] = step ? step[plane] : 1;
+    }
+}
+
+
+
+static int
+imageWidth(unsigned int   const depth,
+           const sample * const min,
+           const sample * const max,
+           const sample * const step) {
 /*----------------------------------------------------------------------------
-   This is standard pow(), but for integers and optimized for small
-   exponents.
+   The width of the output image (i.e. the number of pixels in the image),
+   given that the minimum and maximum sample values in Plane P are min[P] and
+   max[P] and the samples step by step[P].
+
+   E.g. in the sample case of min 0, max 4, and step 1 everywhere, with
+   depth 2,  We return 5*5 = 25.
 -----------------------------------------------------------------------------*/
-    unsigned int result;
-    unsigned int i;
+    unsigned int product;
+    unsigned int plane;
+
+    for (plane = 0, product=1; plane < depth; ++plane) {
+        assert(max[plane] >= min[plane]);
+
+        unsigned int const valueCtThisPlane =
+            ROUNDUP((max[plane] - min[plane] + 1), step[plane])/step[plane];
 
-    result = 1;  /* initial value */
-    for (i = 0; i < exponent; ++i) 
-        result *= base;
+        if (INT_MAX / valueCtThisPlane < product)
+            pm_error("Uncomputably large number of pixels (greater than %u",
+                     INT_MAX);
 
-    return(result);
+        product *= valueCtThisPlane;
+    }
+    assert(product < INT_MAX);
+
+    return product;
 }
 
 
+
 static void
-permuteHigherPlanes(struct pam const pam, int const nextplane, 
-                    tuple * const tuplerow, int * const colP, 
-                    tuple const lowerPlanes) {
+permuteHigherPlanes(unsigned int   const depth,
+                    const sample * const min,
+                    const sample * const max,
+                    const sample * const step,
+                    unsigned int   const nextPlane,
+                    tuple *        const tuplerow,
+                    int *          const colP,
+                    tuple          const lowerPlanes) {
 /*----------------------------------------------------------------------------
    Create all the possible permutations of tuples whose lower-numbered planes
    contain the values from 'lowerPlanes'.  I.e. vary the higher-numbered
-   planes between zero and maxval.
+   planes according to min[], max[], and step[].
 
    Write them sequentially into *tuplerow, starting at *colP.  Adjust
    *colP to next the column after the ones we write.
 
-   lower-numbered means with plane numbers less than 'nextplane'.
+   lower-numbered means with plane numbers less than 'nextPlane'.
 
    We modify 'lowerPlanes' in the higher planes to undefined values.
 -----------------------------------------------------------------------------*/
-    if (nextplane == pam.depth - 1) {
+    if (nextPlane == depth - 1) {
+        /* lowerPlanes[] contains values for all the planes except the
+           highest, so we just vary the highest plane and combine that
+           with lowerPlanes[] and output that to tuplerow[].
+        */
         sample value;
-        for (value = 0; value <= pam.maxval; ++value) {
+
+        for (value = min[nextPlane];
+             value <= max[nextPlane];
+             value += step[nextPlane]) {
+
             unsigned int plane;
-            for (plane = 0; plane < nextplane; ++plane)
+
+            for (plane = 0; plane < nextPlane; ++plane)
                 tuplerow[*colP][plane] = lowerPlanes[plane];
-            tuplerow[*colP][nextplane] = value;
+
+            tuplerow[*colP][nextPlane] = value;
+
             ++(*colP);
         }
     } else {
         sample value;
 
-        for (value = 0; value <= pam.maxval; ++value) {
+        for (value = min[nextPlane];
+             value <= max[nextPlane];
+             value += step[nextPlane]) {
             /* We do something sleazy here and use Caller's lowerPlanes[]
                variable as a local variable, modifying it in the higher
                plane positions.  That's just for speed.
             */
-            lowerPlanes[nextplane] = value;
+            lowerPlanes[nextPlane] = value;
 
-            permuteHigherPlanes(pam, nextplane+1, tuplerow, colP, lowerPlanes);
+            permuteHigherPlanes(depth, min, max, step,
+                                nextPlane+1, tuplerow, colP, lowerPlanes);
         }
     }
 }
@@ -151,52 +357,65 @@ permuteHigherPlanes(struct pam const pam, int const nextplane,
 
 
 int
-main(int argc, char **argv) {
+main(int argc, const char **argv) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     struct pam pam;
     int col;
     tuple lowerPlanes;
         /* This is working storage passed to permuteHigherPlanes(),
            which we call.  Note that because we always pass zero as the
-           "planes" argument to permuteHigherPlanes(), none of the 
-           "lower planes" value is defined as an input to 
+           "planes" argument to permuteHigherPlanes(), none of the
+           "lower planes" value is defined as an input to
            permuteHigherPlanes().
         */
     tuple * tuplerow;
-    
-    pnm_init(&argc, argv);
-   
+    sample * min;   /* malloc'ed array */
+    sample * max;   /* malloc'ed array */
+    sample * step;  /* malloc'ed array */
+
+    pm_proginit(&argc, argv);
+
     parseCommandLine(argc, argv, &cmdline);
 
+    computeMinMaxStep(cmdline.depth, cmdline.maxval,
+                      cmdline.min, cmdline.max, cmdline.step,
+                      &min, &max, &step);
+
     pam.size = sizeof(pam);
     pam.len = PAM_STRUCT_SIZE(tuple_type);
     pam.file = stdout;
     pam.format = PAM_FORMAT;
     pam.plainformat = 0;
-    pam.width = powint(cmdline.maxval+1, cmdline.depth);
+    pam.width = imageWidth(cmdline.depth, min, max, step);
     pam.height = 1;
     pam.depth = cmdline.depth;
     pam.maxval = cmdline.maxval;
     strcpy(pam.tuple_type, cmdline.tupletype);
 
     pnm_writepaminit(&pam);
-   
+
     tuplerow = pnm_allocpamrow(&pam);
 
     lowerPlanes = pnm_allocpamtuple(&pam);
 
     col = 0;
 
-    permuteHigherPlanes(pam, 0, tuplerow, &col, lowerPlanes);
+    permuteHigherPlanes(pam.depth, min, max, step,
+                        0, tuplerow, &col, lowerPlanes);
 
     if (col != pam.width)
         pm_error("INTERNAL ERROR: Wrote %d columns; should have written %d.",
                  col, pam.width);
 
     pnm_writepamrow(&pam, tuplerow);
-    
+
     pnm_freepamrow(tuplerow);
 
+    destroyCmdline(&cmdline);
+
     return 0;
 }
+
+
+
diff --git a/generator/pamstereogram.c b/generator/pamstereogram.c
index 6e5f5ce0..4bc1ea92 100644
--- a/generator/pamstereogram.c
+++ b/generator/pamstereogram.c
@@ -16,7 +16,7 @@
  *
  * ----------------------------------------------------------------------
  *
- * Copyright (C) 2006-2015 Scott Pakin <scott+pbm@pakin.org>
+ * Copyright (C) 2006-2021 Scott Pakin <scott+pbm@pakin.org>
  *
  * All rights reserved.
  *
@@ -58,11 +58,12 @@
 #include "pm_c_util.h"
 #include "mallocvar.h"
 #include "nstring.h"
+#include "rand.h"
 #include "shhopt.h"
 #include "pam.h"
 
 
-enum outputType {OUTPUT_BW, OUTPUT_GRAYSCALE, OUTPUT_COLOR};
+enum OutputType {OUTPUT_BW, OUTPUT_GRAYSCALE, OUTPUT_COLOR};
 
 /* ---------------------------------------------------------------------- */
 
@@ -85,15 +86,17 @@ struct cmdlineInfo {
     unsigned int magnifypat;     /* -magnifypat option */
     int xshift;                  /* -xshift option */
     int yshift;                  /* -yshift option */
+    int yfillshift;              /* -yfillshift option */
     const char * patfile;        /* -patfile option.  Null if none */
     const char * texfile;        /* -texfile option.  Null if none */
     const char * bgcolor;        /* -bgcolor option */
     unsigned int smoothing;      /* -smoothing option */
     unsigned int randomseed;     /* -randomseed option */
     unsigned int randomseedSpec; /* -randomseed option count */
-    enum outputType outputType;  /* Type of output file */
+    enum OutputType outputType;  /* Type of output file */
     unsigned int xbegin;         /* -xbegin option */
     unsigned int xbeginSpec;     /* -xbegin option count */
+    unsigned int tileable;       /* -tileable option */
 };
 
 
@@ -152,8 +155,8 @@ parseCommandLine(int                  argc,
     unsigned int option_def_index;
 
     unsigned int patfileSpec, texfileSpec, dpiSpec, eyesepSpec, depthSpec,
-        guidesizeSpec, magnifypatSpec, xshiftSpec, yshiftSpec,
-      bgcolorSpec, smoothingSpec, planesSpec;
+        guidesizeSpec, magnifypatSpec, xshiftSpec, yshiftSpec, yfillshiftSpec,
+        bgcolorSpec, smoothingSpec, planesSpec;
 
     unsigned int blackandwhite, grayscale, color;
     const char ** planes;
@@ -193,6 +196,8 @@ parseCommandLine(int                  argc,
             &xshiftSpec,              0);
     OPTENT3(0, "yshift",          OPT_INT,    &cmdlineP->yshift,
             &yshiftSpec,              0);
+    OPTENT3(0, "yfillshift",      OPT_INT,    &cmdlineP->yfillshift,
+            &yfillshiftSpec,          0);
     OPTENT3(0, "patfile",         OPT_STRING, &cmdlineP->patfile,
             &patfileSpec,             0);
     OPTENT3(0, "texfile",         OPT_STRING, &cmdlineP->texfile,
@@ -207,6 +212,8 @@ parseCommandLine(int                  argc,
             &planesSpec,              0);
     OPTENT3(0, "xbegin",          OPT_UINT,   &cmdlineP->xbegin,
             &cmdlineP->xbeginSpec,    0);
+    OPTENT3(0, "tileable",        OPT_FLAG,   NULL,
+            (unsigned int *)&cmdlineP->tileable,  0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
@@ -279,9 +286,10 @@ parseCommandLine(int                  argc,
 
     if (!xshiftSpec)
         cmdlineP->xshift = 0;
-
     if (!yshiftSpec)
         cmdlineP->yshift = 0;
+    if (!yfillshiftSpec)
+        cmdlineP->yfillshift = 0;
 
     if (xshiftSpec && !cmdlineP->patfile)
         pm_error("-xshift is valid only with -patfile");
@@ -291,6 +299,11 @@ parseCommandLine(int                  argc,
     if (cmdlineP->makemask && cmdlineP->patfile)
         pm_error("You may not specify both -makemask and -patfile");
 
+    if (cmdlineP->tileable && cmdlineP->xbeginSpec)
+        pm_error("You may not specify both -tileable and -xbegin");
+    if (cmdlineP->tileable && !cmdlineP->patfile)
+        pm_error("-tileable is valid only with -patfile");
+
     if (cmdlineP->patfile && blackandwhite)
         pm_error("-blackandwhite is not valid with -patfile");
     if (cmdlineP->patfile && grayscale)
@@ -394,11 +407,12 @@ typedef struct outGenerator {
 
 
 
-struct randomState {
+struct RandomState {
     /* The state of a randomColor generator. */
     unsigned int magnifypat;
     tuple *      currentRow;
     unsigned int prevy;
+    struct pm_randSt * randStP;
 };
 
 
@@ -413,7 +427,7 @@ randomColor(outGenerator * const outGenP,
 /*----------------------------------------------------------------------------
    Return a random RGB value.
 -----------------------------------------------------------------------------*/
-    struct randomState * const stateP = outGenP->stateP;
+    struct RandomState * const stateP = outGenP->stateP;
 
     /* Every time we start a new row, we select a new sequence of random
        colors.
@@ -428,7 +442,7 @@ randomColor(outGenerator * const outGenP,
             unsigned int plane;
 
             for (plane = 0; plane < outGenP->pam.depth; ++plane) {
-                unsigned int const randval = rand();
+                unsigned int const randval = pm_rand(stateP->randStP);
                 thisTuple[plane] = randval % modulus;
             }
         }
@@ -448,9 +462,13 @@ static outGenStateTerm termRandomColor;
 static void
 termRandomColor(outGenerator * const outGenP) {
 
-    struct randomState * const stateP = outGenP->stateP;
+    struct RandomState * const stateP = outGenP->stateP;
 
     pnm_freepamrow(stateP->currentRow);
+
+    pm_randterm(stateP->randStP);
+
+    free(stateP->randStP);
 }
 
 
@@ -460,7 +478,7 @@ initRandomColor(outGenerator *     const outGenP,
                 const struct pam * const inPamP,
                 struct cmdlineInfo const cmdline) {
 
-    struct randomState * stateP;
+    struct RandomState * stateP;
 
     outGenP->pam.format      = PAM_FORMAT;
     outGenP->pam.plainformat = 0;
@@ -491,6 +509,10 @@ initRandomColor(outGenerator *     const outGenP,
     stateP->magnifypat = cmdline.magnifypat;
     stateP->prevy      = (unsigned int)(-cmdline.magnifypat);
 
+    MALLOCVAR_NOFAIL(stateP->randStP);
+    pm_randinit(stateP->randStP);
+    pm_srand2(stateP->randStP, cmdline.randomseedSpec, cmdline.randomseed);
+
     outGenP->stateP         = stateP;
     outGenP->getTuple       = &randomColor;
     outGenP->terminateState = &termRandomColor;
@@ -844,11 +866,12 @@ makeStereoRow(const struct pam * const inPamP,
               unsigned int       const dpi,
               unsigned int       const optWidth,
               unsigned int       const smoothing) {
+/*----------------------------------------------------------------------------
+  Given a row of the depth map inRow[], compute the sameL and sameR arrays,
+  which indicate for each pixel which pixel to its left and right it should be
+  colored the same as.
+-----------------------------------------------------------------------------*/
 
-/* Given a row of the depth map, compute the sameL and sameR arrays,
- * which indicate for each pixel which pixel to its left and right it
- * should be colored the same as.
- */
 #define Z(X) (inRow[X][0]/(double)inPamP->maxval)
 
     unsigned int col;
@@ -865,7 +888,7 @@ makeStereoRow(const struct pam * const inPamP,
 
         if (left >= 0 && right < inPamP->width) {
             bool isVisible;
-        
+
             if (sameL[right] != right) {
                 /* Right point already linked */
                 if (sameL[right] < left) {
@@ -1114,12 +1137,15 @@ static void
 makeImageRowMts(outGenerator *       const outGenP,
                 unsigned int         const row,
                 const unsigned int * const same,
-                unsigned int *       const sameFp,
+                unsigned int *       const colNumBuffer,
                 tuple *              const rowBuffer,
                 const tuple *        const outRow) {
 /*----------------------------------------------------------------------------
   Make a row of a mapped-texture stereogram.
 -----------------------------------------------------------------------------*/
+    unsigned int * const sameFp = colNumBuffer;
+        /* Fixed point of same[] */
+
     unsigned int * tuplesInCol;
         /* tuplesInCol[C] is the number of tuples averaged together to make
            Column C.
@@ -1165,8 +1191,9 @@ makeImageRowMts(outGenerator *       const outGenP,
 static void
 makeImageRow(outGenerator *       const outGenP,
              unsigned int         const row,
-             unsigned int         const optWidth,
              unsigned int         const xbegin,
+             unsigned int         const farWidth,
+             int                  const yfillshift,
              const unsigned int * const sameL,
              const unsigned int * const sameR,
              const tuple *        const outRow) {
@@ -1189,42 +1216,59 @@ makeImageRow(outGenerator *       const outGenP,
 
   sameL[N] > N is not allowed.
 -----------------------------------------------------------------------------*/
-    int col;
-    int lastLinked;
+    unsigned int const width  = outGenP->pam.width;
+    unsigned int const height = outGenP->pam.height;
 
-    for (col = (int)xbegin, lastLinked = INT_MIN;
-         col < outGenP->pam.width;
-         ++col) {
+    unsigned int col;
+    bool colHasBeenLinked;
+    unsigned int lastLinkedCol;
+        /* Last column to have been linked; meaningless if 'colHasBeenLinked'
+           is false.
+        */
+
+    for (col = xbegin, colHasBeenLinked = false; col < width; ++col) {
 
         tuple newtuple;
 
-        if (sameL[col] == col || sameL[col] < (int)xbegin) {
-            if (lastLinked == col - 1)
-                newtuple = outRow[col - 1];
-            else
-                newtuple = outGenP->getTuple(outGenP, col, row);
+        if (sameL[col] == col || sameL[col] < xbegin) {
+            if (colHasBeenLinked && lastLinkedCol == col - 1)
+                newtuple = outRow[lastLinkedCol];
+            else {
+                if (col < xbegin + farWidth)
+                    newtuple = outGenP->getTuple(outGenP, col, row);
+                else
+                    newtuple = outGenP->getTuple(
+                        outGenP, col, (row + height - yfillshift) % height);
+            }
         } else {
-          newtuple = outRow[sameL[col]];
-          lastLinked = col;
-              /* Keep track of the last pixel to be constrained. */
+            newtuple = outRow[sameL[col]];
+            colHasBeenLinked = true;
+            lastLinkedCol = col;
+                /* Keep track of the last pixel to be constrained. */
         }
         pnm_assigntuple(&outGenP->pam, outRow[col], newtuple);
     }
 
-    for (col = (int)xbegin - 1, lastLinked = INT_MIN; col >= 0; --col) {
+    for (col = xbegin, colHasBeenLinked = false; col > 0; --col) {
         tuple newtuple;
 
-        if (sameR[col] == col) {
-            if (lastLinked == col + 1)
-                newtuple = outRow[col + 1];
-            else
-                newtuple = outGenP->getTuple(outGenP, col, row);
+        if (sameR[col-1] == col-1) {
+            if (colHasBeenLinked && lastLinkedCol == col)
+                newtuple = outRow[lastLinkedCol];
+            else {
+                if (col > xbegin - farWidth)
+                    newtuple = outGenP->getTuple(outGenP, col-1, row);
+                else
+                    newtuple = outGenP->getTuple(
+                        outGenP, col-1, (row + height - yfillshift) % height);
+            }
         } else {
-            newtuple = outRow[sameR[col]];
-            lastLinked = col;
+            newtuple = outRow[sameR[col-1]];
+            colHasBeenLinked = true;
+            lastLinkedCol = col - 1;
                 /* Keep track of the last pixel to be constrained. */
         }
-        pnm_assigntuple(&outGenP->pam, outRow[col], newtuple);
+        pnm_assigntuple(&outGenP->pam, outRow[col-1], newtuple);
     }
 }
 
@@ -1243,6 +1287,174 @@ invertHeightRow(const struct pam * const heightPamP,
 
 
 static void
+makeOneImageRow(unsigned int         const row,
+                outGenerator *       const outputGeneratorP,
+                bool                 const makeMask,
+                const unsigned int * const sameL,
+                const unsigned int * const sameR,
+                unsigned int *       const colNumBuffer,
+                unsigned int         const xbegin,
+                unsigned int         const farWidth,
+                int                  const yfillshift,
+                tuple *              const rowBuffer,
+                tuple *              const outRow) {
+
+    if (makeMask)
+        makeMaskRow(&outputGeneratorP->pam, xbegin, sameL, sameR, outRow);
+    else {
+        if (outputGeneratorP->textureP)
+            makeImageRowMts(outputGeneratorP, row, sameR, colNumBuffer,
+                            rowBuffer, outRow);
+        else
+            makeImageRow(outputGeneratorP, row,
+                         xbegin, farWidth, yfillshift, sameL, sameR, outRow);
+    }
+}
+
+
+
+static void
+constructRowTileable(const struct pam *   const inPamP,
+                     outGenerator *       const outputGeneratorP,
+                     bool                 const makeMask,
+                     const unsigned int * const sameL,
+                     const unsigned int * const sameR,
+                     unsigned int         const farWidth,
+                     int                  const yfillshift,
+                     unsigned int         const row,
+                     tuple *              const outRow,
+                     tuple *              const outRowBuf1,
+                     tuple *              const outRowBuf2,
+                     unsigned int *       const colNumBuf2) {
+
+    tuple * const outRowMax = outRowBuf1;
+
+    unsigned int col;
+
+    /* Create two rows with extreme xbegin values and blend the second
+       into the first.  outRow[] serves as both the buffer for the xbegin=0
+       version and the merged output.  outRowMax[] is the buffer for the
+       xbegin=maximum case.
+    */
+    makeOneImageRow(row, outputGeneratorP, makeMask, sameL, sameR, colNumBuf2,
+                    farWidth, yfillshift, 0, outRowBuf2, outRow);
+
+    makeOneImageRow(row, outputGeneratorP, makeMask, sameL, sameR, colNumBuf2,
+                    farWidth, yfillshift, inPamP->width - 1, outRowBuf2, outRowMax);
+
+    for (col = 0; col < inPamP->width; ++col) {
+        unsigned int plane;
+        unsigned int oplane;
+
+        if (outputGeneratorP->pam.have_opacity)
+            oplane = outputGeneratorP->pam.opacity_plane;
+
+        for (plane = 0; plane < outputGeneratorP->pam.color_depth; ++plane) {
+
+            sample samp, sampMax;
+
+            if (outputGeneratorP->pam.have_opacity) {
+                /* If one sample is fully transparent, use the
+                   other sample for both purposes
+                */
+                if (outRow[col][oplane] == 0)
+                    samp = sampMax = outRowMax[col][plane];
+                else if (outRowMax[col][oplane] == 0)
+                    samp = sampMax = outRow[col][plane];
+                else {
+                    samp    = outRow[col][plane];
+                    sampMax = outRowMax[col][plane];
+                }
+            } else {
+                samp    = outRow[col][plane];
+                sampMax = outRowMax[col][plane];
+            }
+
+            outRow[col][plane] =
+                (col*sampMax + (inPamP->width - col - 1)*samp) /
+                (inPamP->width - 1);
+        }
+        if (outputGeneratorP->pam.have_opacity) {
+            sample samp, sampMax;
+
+            /* Take the maximum alpha for partially transparent samples. */
+            samp    = outRow[col][oplane];
+            sampMax = outRowMax[col][oplane];
+            outRow[col][oplane] = MAX(samp, sampMax);
+        }
+    }
+}
+
+
+
+static void
+doRow(const struct pam * const inPamP,
+      outGenerator *     const outputGeneratorP,
+      double             const depthOfField,
+      double             const eyesep,
+      unsigned int       const dpi,
+      bool               const crossEyed,
+      bool               const makeMask,
+      bool               const tileable,
+      unsigned int       const magnifypat,
+      unsigned int       const smoothing,
+      unsigned int       const xbegin,
+      unsigned int       const farWidth,
+      int                const yfillshift,
+      unsigned int       const row,
+      tuple *            const inRow,
+      tuple *            const outRowBuf0,
+      tuple *            const outRowBuf1,
+      tuple *            const outRowBuf2,
+      unsigned int *     const colNumBuf0,
+      unsigned int *     const colNumBuf1,
+      unsigned int *     const colNumBuf2) {
+
+    tuple *        const outRow = outRowBuf0;
+    unsigned int * const sameL  = colNumBuf0;
+        /* sameL[N] is the column number of a pixel to the
+           left forced to have the same color as the one in column N
+        */
+    unsigned int * const sameR = colNumBuf1;
+        /* sameR[N] is the column number of a pixel to the
+           right forced to have the same color as the one in column N
+        */
+
+    pnm_readpamrow(inPamP, inRow);
+
+    if (crossEyed)
+        /* Invert heights for cross-eyed (as opposed to wall-eyed)
+           people.
+        */
+        invertHeightRow(inPamP, inRow);
+
+    /* Determine color constraints. */
+    makeStereoRow(inPamP, inRow, sameL, sameR, depthOfField, eyesep, dpi,
+                  ROUNDU(eyesep * dpi)/(magnifypat * 2),
+                  smoothing);
+
+    /* Construct a single row. */
+    if (tileable) {
+        constructRowTileable(inPamP, outputGeneratorP, makeMask,
+                             sameL, sameR,
+                             farWidth, yfillshift,
+                             row, outRow,
+                             outRowBuf1, outRowBuf2, colNumBuf2);
+
+    } else {
+        makeOneImageRow(row, outputGeneratorP, makeMask,
+                        sameL, sameR, colNumBuf2,
+                        xbegin, farWidth, yfillshift,
+                        outRowBuf1, outRow);
+    }
+
+    /* Write the resulting row. */
+    pnm_writepamrow(&outputGeneratorP->pam, outRow);
+}
+
+
+
+static void
 makeImageRows(const struct pam * const inPamP,
               outGenerator *     const outputGeneratorP,
               double             const depthOfField,
@@ -1250,72 +1462,56 @@ makeImageRows(const struct pam * const inPamP,
               unsigned int       const dpi,
               bool               const crossEyed,
               bool               const makeMask,
+              bool               const tileable,
               unsigned int       const magnifypat,
               unsigned int       const smoothing,
-              unsigned int       const xbegin) {
-
-    tuple * inRow;     /* One row of pixels read from the height-map file */
-    tuple * outRow;    /* One row of pixels to write to the height-map file */
-    unsigned int * sameR;
-        /* Malloced array: sameR[N] is the column number of a pixel to the
-           right forced to have the same color as the one in column N
-        */
-    unsigned int * sameL;
-        /* Malloced array: sameL[N] is the column number of a pixel to the
-           left forced to have the same color as the one in column N
-        */
-    unsigned int * sameRfp;
-        /* Malloced array: Fixed point of sameR[] */
-    tuple * rowBuffer;     /* Scratch row needed for texture manipulation */
+              unsigned int       const xbegin,
+              int                const yfillshift) {
+
+    tuple * inRow;    /* Buffer for use in reading from the height-map image */
+    tuple * outRowBuf0; /* Buffer for use in generating output rows */
+    tuple * outRowBuf1; /* Buffer for use in generating output rows */
+    tuple * outRowBuf2; /* Buffer for use in generating output rows */
+    unsigned int * colNumBuf0;
+    unsigned int * colNumBuf1;
+    unsigned int * colNumBuf2;
     unsigned int row;      /* Current row in the input and output files */
+    unsigned int pixelEyesep;
+    unsigned int farWidth;
 
     inRow = pnm_allocpamrow(inPamP);
-    outRow = pnm_allocpamrow(&outputGeneratorP->pam);
-    MALLOCARRAY(sameR, inPamP->width);
-    if (sameR == NULL)
-        pm_error("Unable to allocate space for \"sameR\" array.");
-    MALLOCARRAY(sameL, inPamP->width);
-    if (sameL == NULL)
-        pm_error("Unable to allocate space for \"sameL\" array.");
-
-    MALLOCARRAY(sameRfp, inPamP->width);
-    if (sameRfp == NULL)
-        pm_error("Unable to allocate space for \"sameRfp\" array.");
-    rowBuffer = pnm_allocpamrow(&outputGeneratorP->pam);
+    outRowBuf0 = pnm_allocpamrow(&outputGeneratorP->pam);
+    outRowBuf1 = pnm_allocpamrow(&outputGeneratorP->pam);
+    outRowBuf2 = pnm_allocpamrow(&outputGeneratorP->pam);
+    MALLOCARRAY(colNumBuf0, inPamP->width);
+    if (colNumBuf0 == NULL)
+        pm_error("Unable to allocate space for %u column buffer",
+                 inPamP->width);
+    MALLOCARRAY(colNumBuf1, inPamP->width);
+    if (colNumBuf1 == NULL)
+        pm_error("Unable to allocate space for %u column buffer",
+                 inPamP->width);
+    MALLOCARRAY(colNumBuf2, inPamP->width);
+    if (colNumBuf2 == NULL)
+        pm_error("Unable to allocate space for %u column buffer",
+                 inPamP->width);
+
+    pixelEyesep = ROUNDU(eyesep * dpi);
+    farWidth = pixelEyesep/(magnifypat * 2);
 
     for (row = 0; row < inPamP->height; ++row) {
-        pnm_readpamrow(inPamP, inRow);
-        if (crossEyed)
-            /* Invert heights for cross-eyed (as opposed to wall-eyed)
-               people.
-            */
-            invertHeightRow(inPamP, inRow);
-
-        /* Determine color constraints. */
-        makeStereoRow(inPamP, inRow, sameL, sameR, depthOfField, eyesep, dpi,
-                      ROUNDU(eyesep * dpi)/(magnifypat * 2),
-                      smoothing);
-
-        if (makeMask)
-            makeMaskRow(&outputGeneratorP->pam, xbegin, sameL, sameR, outRow);
-        else {
-            if (outputGeneratorP->textureP)
-                makeImageRowMts(outputGeneratorP, row, sameR, sameRfp,
-                                rowBuffer, outRow);
-            else
-                makeImageRow(outputGeneratorP, row,
-                             ROUNDU(eyesep * dpi)/(magnifypat * 2),
-                             xbegin, sameL, sameR, outRow);
-        }
-        /* Write the resulting row. */
-        pnm_writepamrow(&outputGeneratorP->pam, outRow);
+        doRow(inPamP, outputGeneratorP,  depthOfField, eyesep, dpi,
+              crossEyed, makeMask, tileable, magnifypat, smoothing, xbegin,
+              farWidth, yfillshift, row,
+              inRow, outRowBuf0, outRowBuf1, outRowBuf2,
+              colNumBuf0, colNumBuf1, colNumBuf2);
     }
 
-    pnm_freepamrow(rowBuffer);
-    free(sameRfp);
-    free(sameL);
-    free(sameR);
-    pnm_freepamrow(outRow);
+    free(colNumBuf2);
+    free(colNumBuf1);
+    free(colNumBuf0);
+    pnm_freepamrow(outRowBuf1);
+    pnm_freepamrow(outRowBuf0);
     pnm_freepamrow(inRow);
 }
 
@@ -1361,8 +1557,9 @@ produceStereogram(FILE *             const ifP,
 
     makeImageRows(&inPam, outputGeneratorP,
                   cmdline.depth, cmdline.eyesep, cmdline.dpi,
-                  cmdline.crosseyed, cmdline.makemask, cmdline.magnifypat,
-                  cmdline.smoothing, xbegin);
+                  cmdline.crosseyed, cmdline.makemask, cmdline.tileable,
+                  cmdline.magnifypat, cmdline.smoothing, xbegin,
+                  cmdline.yfillshift);
 
     if (cmdline.guidebottom)
         drawguides(cmdline.guidesize, &outputGeneratorP->pam,
@@ -1419,8 +1616,6 @@ main(int argc, const char *argv[]) {
     if (cmdline.verbose)
         reportParameters(cmdline);
 
-    srand(cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed());
-
     ifP = pm_openr(cmdline.inputFilespec);
 
     /* Produce a stereogram. */
@@ -1432,4 +1627,3 @@ main(int argc, const char *argv[]) {
 }
 
 
-
diff --git a/generator/pamtris/boundaries.c b/generator/pamtris/boundaries.c
index 7045cbc7..cfcc4c1d 100644
--- a/generator/pamtris/boundaries.c
+++ b/generator/pamtris/boundaries.c
@@ -120,7 +120,7 @@ gen_triangle_boundaries(Xy              const xy,
     }
 
     if (xy._[0][1] == xy._[1][1] && xy._[1][1] == xy._[2][1]) {
-        /* Triangle is degenarate: its visual representation consists only of
+        /* Triangle is degenerate: its visual representation consists only of
            a horizontal straight line.
         */
 
diff --git a/generator/pamtris/framebuffer.c b/generator/pamtris/framebuffer.c
index 93263c91..5665e9a4 100644
--- a/generator/pamtris/framebuffer.c
+++ b/generator/pamtris/framebuffer.c
@@ -164,7 +164,7 @@ realloc_image_buffer(int32_t            const new_maxval,
   function "process_next_command", which is the only function that calls this
   one.
 
-  If the function suceeds, the image buffer is left in cleared state. The
+  If the function succeeds, the image buffer is left in cleared state. The
   Z-Buffer, however, is not touched at all.
 
   If the new depth is equal to the previous one, no actual reallocation is
@@ -313,7 +313,7 @@ draw_span(uint32_t           const base,
         unsigned int l;
 
         /* The following statements will only have any effect if the depth
-           test, performed above, has suceeded. I. e. if the depth test fails,
+           test, performed above, has succeeded. I. e. if the depth test fails,
            no changes will be made on the frame buffer; otherwise, the
            frame buffer will be updated with the new values.
         */
diff --git a/generator/pbmnoise.c b/generator/pbmnoise.c
new file mode 100644
index 00000000..e316dafc
--- /dev/null
+++ b/generator/pbmnoise.c
@@ -0,0 +1,485 @@
+/* pbmnoise.c - create a random bitmap of a specified size
+                with a specified ratio of white/black pixels
+
+   Written by Akira F Urushibata and contributed to the public domain 
+   December 2021
+*/
+
+#include <math.h>
+#include <string.h>
+#include <assert.h>
+
+#include "pm_c_util.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+#include "rand.h"
+#include "nstring.h"
+
+#include "pbm.h"
+
+
+
+static void
+parseFraction(const char *   const fraction,
+              unsigned int * const numeratorP,
+              unsigned int * const precisionP) {
+
+    unsigned int numerator, denominator;
+
+    sscanf(fraction, "%u/%u", &numerator, &denominator);
+
+    if (denominator > 65536)
+        pm_error("Denominator (%u) too large.", denominator);
+    else if (denominator == 0 || (denominator & (denominator - 1)) != 0)
+        pm_error("Denominator must be a power of two.  You specified %u.",
+                 denominator);
+    else if (numerator > denominator)
+        pm_error("Invalid fraction (%s).  Denominator must be larger than "
+                 "numerator.", fraction);
+    else {
+        /* Reduce fraction to lowest terms */
+        unsigned int numerator2, denominator2;
+            /* The fraction reduced to lowest terms */
+        unsigned int precision2;
+
+        if (numerator == 0) { /* all white image */
+            numerator2   = 0;
+            denominator2 = 1;
+            precision2   = 0;
+        } else if (numerator == denominator) { /* all black */
+            numerator2   = 1;
+            denominator2 = 1;
+            precision2   = 0;
+        } else {
+            numerator2   = numerator;   /* initial value */
+            denominator2 = denominator; /* initial value */
+
+            while ((numerator2 & 0x01) != 0x01) {
+                denominator2 /= 2;
+                numerator2   /= 2;
+            }
+            precision2 = 1;
+        }
+
+      if (denominator != denominator2)
+          pm_message("Ratio %u/%u = %u/%u",
+                     numerator, denominator, numerator2, denominator2);
+
+      *precisionP = (precision2 == 0) ? 0 : pm_maxvaltobits(denominator2 - 1);
+          /* pm_maxvaltobits(N):  Max of N is 65535 */
+
+      *numeratorP = numerator2;
+    }
+}
+
+
+
+static void
+setRatio(const char *   const ratioArg,
+         unsigned int * const numeratorP,
+         unsigned int * const precisionP) {
+/*----------------------------------------------------------------------------
+    Convert string "ratioArg" to ratio: numerator / (2 ^ precision) The input
+    string must be in fraction "n/d" form and the denominator must be a power
+    of 2.
+
+    Ratio is the probability of one binary digit being "1".  The ratio of "1"
+    (=PBM black) pixels in the entire output image will be close to this
+    value.
+
+    Most invalid strings are rejected here.
+----------------------------------------------------------------------------*/
+    if (strspn(ratioArg, "0123456789/") == strlen(ratioArg) &&
+             ratioArg[0] != '/' &&
+             ratioArg[strlen(ratioArg) - 1] != '/' &&
+             strchr(ratioArg, '/') != NULL &&
+             strchr(ratioArg, '/') == strrchr(ratioArg, '/'))
+        parseFraction(ratioArg, numeratorP, precisionP);
+    else
+        pm_error("Invalid ratio: '%s'", ratioArg);
+}
+
+
+
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    unsigned int width;
+    unsigned int height;
+    unsigned int numerator;
+    unsigned int precision;
+    unsigned int randomseed;
+    unsigned int randomseedSpec;
+    unsigned int bswap;   /* boolean */
+    unsigned int pack;    /* boolean */
+};
+
+
+
+static void
+parseCommandLine(int argc, const 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 pm_optParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+    const char * ratioArg;
+    unsigned int ratioSpec;
+    const char * endianArg;
+    unsigned int endianSpec;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "ratio",         OPT_STRING, &ratioArg,
+            &ratioSpec,                     0);
+    OPTENT3(0, "randomseed",    OPT_UINT,   &cmdlineP->randomseed,
+            &cmdlineP->randomseedSpec,      0);
+    OPTENT3(0, "endian",        OPT_STRING, &endianArg,
+            &endianSpec,                    0);
+    OPTENT3(0, "pack",          OPT_FLAG,   NULL,
+            &cmdlineP->pack,                0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We may have parms that are negative numbers */
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+    /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+    free(option_def);
+
+    if (ratioSpec)
+        setRatio(ratioArg, &cmdlineP->numerator, &cmdlineP->precision);
+    else {
+        /* Set ratio to default: 1/2 */
+        cmdlineP->numerator = 1;
+        cmdlineP->precision = 1;
+    }
+
+    if (!endianSpec)
+        cmdlineP->bswap = false;
+    else {
+        if      (streq(endianArg, "native"))
+            cmdlineP->bswap = false;
+        else if (streq(endianArg, "swap"))
+            cmdlineP->bswap = true;
+        else if (streq(endianArg, "big"))
+            cmdlineP->bswap = (BYTE_ORDER == LITTLE_ENDIAN);
+        else if (streq(endianArg, "little"))
+            cmdlineP->bswap = (BYTE_ORDER != LITTLE_ENDIAN);
+        else
+            pm_error("Invalid value '%s' for -endian argument.", endianArg);
+    }
+
+    if (argc-1 != 2)
+        pm_error("Wrong number of arguments (%d).  There are two "
+                 "non-option arguments: width and height in pixels",
+                 argc-1);
+    else {
+        cmdlineP->width  = pm_parse_width (argv[1]);
+        cmdlineP->height = pm_parse_height(argv[2]);
+    }
+}
+
+
+
+static void
+writeSingleColorRaster(unsigned int const cols,
+                       unsigned int const rows,
+                       bit          const color,
+                       FILE *       const ofP) {
+/*-----------------------------------------------------------------------------
+  Generate a single-color raster of color 'color', dimensions
+  'cols' by 'rows', to output file *ofP.
+-----------------------------------------------------------------------------*/
+    unsigned int const lastColChar = (cols - 1) / 8;
+
+    unsigned char * bitrow0;
+    unsigned int i;
+
+    bitrow0 = pbm_allocrow_packed(cols + 32);
+
+    for (i = 0; i <= lastColChar; ++i)
+        bitrow0[i] = color * 0xff;
+
+    if (color != 0)
+        pbm_cleanrowend_packed(bitrow0, cols);
+
+    /* row end trimming, not necessary with white */
+
+    {
+        unsigned int row;
+        for (row = 0; row < rows; ++row)
+            pbm_writepbmrow_packed(ofP, bitrow0, cols, 0);
+    }
+    pbm_freerow(bitrow0);
+}
+
+
+
+static uint32_t
+randombits(unsigned int       const precision,
+           unsigned int       const numerator,
+           struct pm_randSt * const randStP) {
+/*----------------------------------------------------------------------------
+  Generate 32 random bits so that for each bit the probability of "1"
+  being generated is numerator / (2 ^ precision).
+
+  How this works:
+
+  Ratios such as 1/8, 7/8, 1/16, 15/16, 1/32, 31/32 are straightforward.  How
+  do you get intermediate values such as 3/8, 5/8, 3/16, 5/16, 7/16?
+
+  Imagine a set of 10 bits which are 90% 1, 10% 0 and a random number source
+  which produces 1 and 0 in even proportions.
+
+  Conduct "and" and "or" on these bits:
+
+           0011111111 (90%)       0011111111 (90%)
+      and) 0101010101 (50%)   or) 0101010101 (50%)
+      ---------------------   --------------------
+           0001010101 (45%)       0111111111 (95%)
+
+  It can be seen from this example that an "and" operation gives a new ratio
+  which is halfway between the old ratio (90% in this example) and 0%, while
+  "or" gives one at the middle of the old ratio and 100% The corresponding
+  binary operations for fixed-point fractions are: "right-shift by one and
+  insert a 0 behind the fixed point" and "right-shift by one and insert a 1
+  behind the fixed point" respecatbly.
+
+  115/128 = 89.84% (near 90%)  In binary fix-point: 0.1110011
+  0.01110011 = 115/256 = 44.92%
+  0.11110011 = 243/256 = 94.92%
+
+  So to achieve the desired ratio, start at the LSB (right end) of
+  'numerator'.  Initialize the output bits to zero.  Conduct an "and" for each
+  0 and an "or" for each 1 with a freshly drawn random number until the fixed
+  point is reached.
+
+  An "and" operation of a random number and zero always yields zero.  To avoid
+  waste, we reduce terms to eliminate the trailing zeroes in 'numerator' and
+  indicate the fixed point with 'precision'.  Each time the program is
+  executed the location of the fixed point is set anew, but it stays constant
+  until the program exits.
+----------------------------------------------------------------------------*/
+    unsigned int i;
+    uint32_t mask;
+    uint32_t retval;
+
+    for (i = 0, mask = 0x01, retval=0x00000000;
+         i < precision;
+         ++i, mask <<= 1) {
+
+        uint32_t const randval = pm_rand32(randStP);
+
+        if ((numerator & mask) != 0 )
+            retval |= randval;
+        else
+            retval &= randval;
+    }
+    return retval;
+}
+
+
+
+static uint32_t
+swapWord(uint32_t const word) {
+/*----------------------------------------------------------------------------
+  Swap four bytes.
+  This swap method works regardless of native system endianness.
+----------------------------------------------------------------------------*/
+    uint32_t const retval =
+        ((word >> 24) & 0xff) |
+        ((word >>  8) & 0xff00) |
+        ((word <<  8) & 0xff0000) |
+        ((word << 24) & 0xff000000)
+        ;
+
+    return retval;
+}
+
+
+
+static void
+swapBitrow(unsigned char * const bitrow,
+           unsigned int    const words,
+           bool            const bswap) {
+/*----------------------------------------------------------------------------
+  Modify bits in 'bitrow', swapping as indicated.
+----------------------------------------------------------------------------*/
+    uint32_t * const bitrowByWord = (uint32_t *) bitrow;
+
+    unsigned int wordCnt;
+
+    for (wordCnt=0; wordCnt < words; ++wordCnt) {
+        uint32_t const inWord = bitrowByWord[wordCnt];
+
+        bitrowByWord[wordCnt] = bswap ? swapWord(inWord) : inWord;
+    }
+}
+
+
+
+static void
+pbmnoise(FILE *             const ofP,
+         unsigned int       const cols,
+         unsigned int       const rows,
+         unsigned int       const numerator,
+         unsigned int       const precision,
+         bool               const bswap,
+         struct pm_randSt * const randStP) {
+/*----------------------------------------------------------------------------
+  Default method of constructing rows.
+
+  Generate pixels in units of 32 bits.
+
+  If cols is not a multiple of 32, discard pixels beyond row end.
+-----------------------------------------------------------------------------*/
+    unsigned int const words = (cols + 31) / 32;
+
+    unsigned char * bitrow;
+    unsigned int row;
+    unsigned int wordCnt;
+
+    bitrow = pbm_allocrow_packed(cols + 32);
+
+    for (row = 0; row < rows; ++row) {
+        uint32_t * const bitrowByWord = (uint32_t *) bitrow;
+
+        for (wordCnt = 0; wordCnt < words; ++wordCnt)
+            bitrowByWord[wordCnt] = randombits(precision, numerator, randStP);
+
+        if (bswap)
+            swapBitrow(bitrow, words, bswap);
+
+        pbm_cleanrowend_packed(bitrow, cols);
+        pbm_writepbmrow_packed(ofP, bitrow, cols, 0);
+    }
+    pbm_freerow(bitrow);
+}
+
+
+
+static void
+pbmnoise_packed(FILE *             const ofP,
+                unsigned int       const cols,
+                unsigned int       const rows,
+                unsigned int       const numerator,
+                unsigned int       const precision,
+                bool               const bswap,
+                struct pm_randSt * const randStP) {
+/*----------------------------------------------------------------------------
+  Alternate method of constructing rows.
+  Like the default pbmnoise(), generate pixels in units of 32 bits
+  but carry over unused pixel data at row end to the next row.
+-----------------------------------------------------------------------------*/
+    unsigned char * bitrow0;
+    uint32_t * bitrowByWord;
+    unsigned int offset;
+    unsigned int row;
+    uint32_t wordSave;    /* Pixels carried over to next row */
+
+    bitrow0 = pbm_allocrow_packed(cols + 63);
+    bitrowByWord = (uint32_t *) bitrow0;
+
+    for (row = 0, offset = 0; row < rows; ++row) {
+        if (offset == 0) {
+            unsigned int const words = (cols + 31 ) / 32;
+
+            unsigned int wordCnt;
+
+            for (wordCnt = 0; wordCnt< words; ++wordCnt) {
+                bitrowByWord[wordCnt] =
+                    randombits(precision, numerator, randStP);
+            }
+
+            if (bswap)
+                swapBitrow(bitrow0, words, bswap);
+
+            wordSave = bitrowByWord[words - 1];
+
+            pbm_cleanrowend_packed(bitrow0, cols);
+            pbm_writepbmrow_packed(ofP, bitrow0, cols, 0);
+            offset = cols % 32;
+        } else {
+            unsigned int const wordsToFetch = (cols - (32 - offset) + 31) / 32;
+            unsigned int const lastWord = wordsToFetch;
+
+            unsigned int wordCnt;
+
+            bitrowByWord[0] = wordSave;
+
+            for (wordCnt = 0; wordCnt < wordsToFetch; ++wordCnt) {
+                bitrowByWord[wordCnt + 1] =
+                    randombits(precision, numerator, randStP);
+            }
+
+            if (bswap)
+                swapBitrow((unsigned char *) & bitrowByWord[1],
+                           wordsToFetch, bswap);
+
+            wordSave = bitrowByWord [lastWord];
+
+            pbm_writepbmrow_bitoffset(ofP, bitrow0, cols, 0, offset);
+            offset = (offset + cols) % 32;
+        }
+    }
+    pbm_freerow(bitrow0);
+}
+
+
+int
+main(int argc, const char *argv[]) {
+
+    struct CmdlineInfo cmdline;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    pbm_writepbminit(stdout, cmdline.width, cmdline.height, 0);
+
+    if (cmdline.precision == 0) {
+        bit color;
+
+        if (cmdline.numerator == 0)
+            color = PBM_WHITE;
+        else {
+            assert (cmdline.numerator == 1);
+            color = PBM_BLACK;
+        }
+        writeSingleColorRaster(cmdline.width, cmdline.height, color, stdout);
+    } else if (cmdline.width % 32 == 0 || !cmdline.pack) {
+        struct pm_randSt randSt;
+
+        pm_randinit(&randSt);
+        pm_srand2(&randSt, cmdline.randomseedSpec, cmdline.randomseed);
+
+        pbmnoise(stdout, cmdline.width, cmdline.height,
+                 cmdline.numerator, cmdline.precision,
+                 cmdline.bswap, &randSt);
+
+        pm_randterm(&randSt);
+    } else {
+        struct pm_randSt randSt;
+
+        pm_randinit(&randSt);
+        pm_srand2(&randSt, cmdline.randomseedSpec, cmdline.randomseed);
+
+        pbmnoise_packed(stdout, cmdline.width, cmdline.height,
+                        cmdline.numerator, cmdline.precision,
+                        cmdline.bswap, &randSt);
+
+        pm_randterm(&randSt);
+    }
+    return 0;
+}
+
+
diff --git a/generator/pbmpage.c b/generator/pbmpage.c
index a2f47bcc..96dca876 100644
--- a/generator/pbmpage.c
+++ b/generator/pbmpage.c
@@ -1,6 +1,6 @@
-/***************************************************************************
+/*=============================================================================
                                 pbmpage
-
+===============================================================================
   This program produces a printed page test pattern in PBM format.
 
   This was adapted from Tim Norman's 'pbmtpg' program, part of his
@@ -10,7 +10,7 @@
 
   For copyright and licensing information, see the pbmtoppa program,
   which was also derived from the same package.
-****************************************************************************/
+=============================================================================*/
 
 #include <stdlib.h>
 #include <string.h>
@@ -18,73 +18,139 @@
 #include <stdio.h>
 
 #include "pm_c_util.h"
+#include "mallocvar.h"
+#include "shhopt.h"
+#include "nstring.h"
 #include "pbm.h"
 
+enum Pattern {PAT_GRID, PAT_VERTICAL, PAT_DIAGONAL};
+
 /* US is 8.5 in by 11 in */
 
-#define USWIDTH  (5100)
-#define USHEIGHT (6600)
+static unsigned int const usWidth  = 5100;
+static unsigned int const usHeight = 6600;
 
 /* A4 is 210 mm by 297 mm == 8.27 in by 11.69 in */
 
-#define A4WIDTH  (4960)
-#define A4HEIGHT (7016)
+static unsigned int const a4Width  = 4960;
+static unsigned int const a4Height = 7016;
 
 
-struct bitmap {
-    unsigned int Width;      /* width and height in 600ths of an inch */
-    unsigned int Height;
-    bit ** bitmap;
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    enum Pattern pattern;
+    unsigned int a4;
 };
 
-static struct bitmap bitmap;
+
+
+static void
+parseCommandLine(int argc, const 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;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "a4",         OPT_FLAG, NULL, &cmdlineP->a4,       0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+    /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (argc-1 < 1)
+        cmdlineP->pattern = PAT_GRID;
+    else {
+        if (argc-1 > 1)
+            pm_error("Too many arguments (%u).  The only possible argument "
+                     "is the pattern number", argc-1);
+        if (streq(argv[1], "1"))
+            cmdlineP->pattern = PAT_GRID;
+        else if (streq(argv[1], "2"))
+            cmdlineP->pattern = PAT_VERTICAL;
+        else if (streq(argv[1], "3"))
+            cmdlineP->pattern = PAT_DIAGONAL;
+        else
+            pm_error("Invalid test pattern name '%s'.  "
+                     "We recognize only '1', '2', and '3'", argv[1]);
+    }
+    free(option_def);
+}
+
+
+
+struct Bitmap {
+    /* width and height in 600ths of an inch */
+    unsigned int width;
+    unsigned int height;
+
+    unsigned char ** bitmap;
+};
 
 
 
 static void
-setpixel(unsigned int const x,
-         unsigned int const y,
-         unsigned int const c) {
+setpixel(struct Bitmap * const bitmapP,
+         unsigned int    const x,
+         unsigned int    const y,
+         bit             const c) {
 
     char const bitmask = 128 >> (x % 8);
 
-    if (x < 0 || x >= bitmap.Width)
-        return;
-    if (y < 0 || y >= bitmap.Height)
-        return;
-
-    if (c)
-        bitmap.bitmap[y][x/8] |= bitmask;
-    else
-        bitmap.bitmap[y][x/8] &= ~bitmask;
+    if (x < 0 || x >= bitmapP->width) {
+        /* Off the edge of the canvas */
+    } else if (y < 0 || y >= bitmapP->height) {
+        /* Off the edge of the canvas */
+    } else {
+        if (c == PBM_BLACK)
+            bitmapP->bitmap[y][x/8] |= bitmask;
+        else
+            bitmapP->bitmap[y][x/8] &= ~bitmask;
+    }
 }
 
 
 
-static void 
-setplus(unsigned int const x,
-        unsigned int const y,
-        unsigned int const s) {
+static void
+setplus(struct Bitmap * const bitmapP,
+        unsigned int    const x,
+        unsigned int    const y,
+        unsigned int    const s) {
 /*----------------------------------------------------------------------------
-   Draw a black plus sign centered at (x,y) with arms 's' pixels long.  
+   Draw a black plus sign centered at (x,y) with arms 's' pixels long.
    Leave the exact center of the plus white.
 -----------------------------------------------------------------------------*/
     unsigned int i;
 
     for (i = 0; i < s; ++i) {
-        setpixel(x+i, y,   1);
-        setpixel(x-i, y,   1);
-        setpixel(x,   y+i, 1);
-        setpixel(x,   y-i, 1);
+        setpixel(bitmapP, x + i, y,     PBM_BLACK);
+        setpixel(bitmapP, x - i, y,     PBM_BLACK);
+        setpixel(bitmapP, x ,    y + i, PBM_BLACK);
+        setpixel(bitmapP, x ,    y - i, PBM_BLACK);
     }
 }
 
 
 
-static void 
-setblock(unsigned int const x,
-         unsigned int const y,
-         unsigned int const s) {
+static void
+setblock(struct Bitmap * const bitmapP,
+         unsigned int    const x,
+         unsigned int    const y,
+         unsigned int    const s) {
 
     unsigned int i;
 
@@ -92,16 +158,17 @@ setblock(unsigned int const x,
         unsigned int j;
 
         for (j = 0; j < s; ++j)
-            setpixel(x+i, y+j, 1);
+            setpixel(bitmapP, x + i, y + j, PBM_BLACK);
     }
 }
 
 
 
-static void 
-setchar(unsigned int const x,
-        unsigned int const y,
-        char         const c) {
+static void
+setchar(struct Bitmap * const bitmapP,
+        unsigned int    const x,
+        unsigned int    const y,
+        char            const c) {
 
     static char const charmap[10][5]= { { 0x3e, 0x41, 0x41, 0x41, 0x3e },
                                         { 0x00, 0x42, 0x7f, 0x40, 0x00 },
@@ -113,7 +180,7 @@ setchar(unsigned int const x,
                                         { 0x01, 0x01, 0x61, 0x19, 0x07 },
                                         { 0x36, 0x49, 0x49, 0x49, 0x36 },
                                         { 0x26, 0x49, 0x49, 0x49, 0x3e } };
-    
+
     if (c <= '9' && c >= '0') {
         unsigned int xo;
 
@@ -122,7 +189,7 @@ setchar(unsigned int const x,
 
             for (yo = 0; yo < 8; ++yo) {
                 if ((charmap[c-'0'][xo] >> yo) & 0x01)
-                    setblock(x + xo*3, y + yo*3, 3);
+                    setblock(bitmapP, x + xo*3, y + yo*3, 3);
             }
         }
     }
@@ -130,23 +197,25 @@ setchar(unsigned int const x,
 
 
 
-static void 
-setstring(unsigned int const x,
-          unsigned int const y,
-          const char * const s) {
+static void
+setstring(struct Bitmap * const bitmapP,
+          unsigned int    const x,
+          unsigned int    const y,
+          const char *    const s) {
 
     const char * p;
     unsigned int xo;
 
     for (xo = 0, p = s; *p; xo += 21, ++p)
-        setchar(x + xo, y, *p);
+        setchar(bitmapP, x + xo, y, *p);
 }
 
 
 
-static void 
-setCG(unsigned int const x,
-      unsigned int const y) {
+static void
+setCG(struct Bitmap * const bitmapP,
+      unsigned int    const x,
+      unsigned int    const y) {
 
     unsigned int xo;
 
@@ -155,16 +224,16 @@ setCG(unsigned int const x,
 
         unsigned int zo;
 
-        setpixel(x + xo, y + yo, 1);
-        setpixel(x+yo,   y + xo, 1);
-        setpixel(x-1-xo, y-1-yo, 1);
-        setpixel(x-1-yo, y-1-xo, 1);
-        setpixel(x+xo,   y-1-yo, 1);
-        setpixel(x-1-xo, y+yo,   1);
+        setpixel(bitmapP, x + xo    , y + yo    , PBM_BLACK);
+        setpixel(bitmapP, x + yo    , y + xo    , PBM_BLACK);
+        setpixel(bitmapP, x - 1 - xo, y - 1 - yo, PBM_BLACK);
+        setpixel(bitmapP, x - 1 - yo, y - 1 - xo, PBM_BLACK);
+        setpixel(bitmapP, x + xo    , y - 1 - yo, PBM_BLACK);
+        setpixel(bitmapP, x - 1 - xo, y + yo    , PBM_BLACK);
 
-        for(zo = 0; zo < yo; ++zo) {
-            setpixel(x + xo, y-1-zo, 1);
-            setpixel(x-1-xo, y+zo,   1);
+        for (zo = 0; zo < yo; ++zo) {
+            setpixel(bitmapP, x + xo    , y - 1 - zo, PBM_BLACK);
+            setpixel(bitmapP, x - 1 - xo, y + zo    , PBM_BLACK);
         }
     }
 }
@@ -173,129 +242,178 @@ setCG(unsigned int const x,
 
 static void
 outputPbm(FILE *        const ofP,
-          struct bitmap const bitmap) {
+          struct Bitmap const bitmap) {
 /*----------------------------------------------------------------------------
   Create a pbm file containing the image from the global variable bitmap[].
 -----------------------------------------------------------------------------*/
     int const forceplain = 0;
 
     unsigned int row;
-    
-    pbm_writepbminit(ofP, bitmap.Width, bitmap.Height, forceplain);
-    
-    for (row = 0; row < bitmap.Height; ++row) {
+
+    pbm_writepbminit(ofP, bitmap.width, bitmap.height, forceplain);
+
+    for (row = 0; row < bitmap.height; ++row) {
         pbm_writepbmrow_packed(ofP, bitmap.bitmap[row],
-                               bitmap.Width, forceplain); 
+                               bitmap.width, forceplain);
     }
 }
 
 
 
 static void
-framePerimeter(unsigned int const Width, 
-               unsigned int const Height) {
+framePerimeter(struct Bitmap * const bitmapP) {
 
     unsigned int x, y;
 
     /* Top edge */
-    for (x = 0; x < Width; ++x)
-        setpixel(x, 0, 1);
+    for (x = 0; x < bitmapP->width; ++x)
+        setpixel(bitmapP, x, 0, PBM_BLACK);
 
     /* Bottom edge */
-    for (x = 0; x < Width; ++x)
-        setpixel(x, Height-1, 1);
+    for (x = 0; x < bitmapP->width; ++x)
+        setpixel(bitmapP, x, bitmapP->height - 1, PBM_BLACK);
 
     /* Left edge */
-    for (y = 0; y < Height; ++y)
-        setpixel(0, y, 1);
+    for (y = 0; y < bitmapP->height; ++y)
+        setpixel(bitmapP, 0, y, PBM_BLACK);
 
     /* Right edge */
-    for (y = 0; y < Height; ++y)
-        setpixel(Width-1, y, 1);
+    for (y = 0; y < bitmapP->height; ++y)
+        setpixel(bitmapP, bitmapP->width - 1, y, PBM_BLACK);
 }
 
 
 
-int 
-main(int argc, const char** argv) {
+static void
+makeWhite(struct Bitmap * const bitmapP) {
 
-    int TP;
-    unsigned int x, y;
-    char buf[128];
-    /* width and height in 600ths of an inch */
-    unsigned int Width;
-    unsigned int Height;
+    unsigned int y;
 
-    pm_proginit(&argc, argv);
-
-    if (argc > 1 && strcmp(argv[1], "-a4") == 0) {
-        Width  = A4WIDTH;
-        Height = A4HEIGHT;
-        --argc;
-        ++argv;
-    } else {
-        Width  = USWIDTH;
-        Height = USHEIGHT;
+    for (y = 0; y < bitmapP->height; ++y) {
+        unsigned int x;
+        for (x = 0; x < pbm_packed_bytes(bitmapP->width); ++x)
+            bitmapP->bitmap[y][x] = 0x00;  /* 8 white pixels */
     }
+}
 
-    if (argc > 1)
-        TP = atoi(argv[1]);
-    else
-        TP = 1;
 
-    bitmap.Width  = Width;
-    bitmap.Height = Height;
-    bitmap.bitmap = pbm_allocarray_packed(Width, bitmap.Height);
 
-    for (y = 0; y < bitmap.Height; ++y) {
-        unsigned int x;
-        for (x = 0; x < pbm_packed_bytes(bitmap.Width); ++x) 
-            bitmap.bitmap[y][x] = 0x00; 
-    }
+static void
+drawGrid(struct Bitmap * const bitmapP) {
 
-    switch (TP) {
-    case 1:
-        framePerimeter(Width, Height);
-        for (x = 0; x < Width; x += 100) {
+    char buf[128];
+
+    framePerimeter(bitmapP);
+    {
+        unsigned int x;
+        for (x = 0; x < bitmapP->width; x += 100) {
             unsigned int y;
-            for(y = 0; y < Height; y += 100)
-                setplus(x, y, 4);
+            for (y = 0; y < bitmapP->height; y += 100)
+                setplus(bitmapP, x, y, 4);
         }
-        for(x = 0; x < Width; x += 100) {
-            sprintf(buf,"%d", x);
-            setstring(x + 3, (Height/200) * 100 + 3, buf);
+    }
+    {
+        unsigned int x;
+        for (x = 0; x < bitmapP->width; x += 100) {
+            sprintf(buf,"%u", x);
+            setstring(bitmapP, x + 3, (bitmapP->height/200) * 100 + 3, buf);
         }
-        for (y = 0; y < Height; y += 100) {
-            sprintf(buf, "%d", y);
-            setstring((Width/200) * 100 + 3, y + 3, buf);
+    }
+    {
+        unsigned int y;
+        for (y = 0; y < bitmapP->height; y += 100) {
+            sprintf(buf, "%u", y);
+            setstring(bitmapP, (bitmapP->width/200) * 100 + 3, y + 3, buf);
         }
-        for (x = 0; x < Width; x += 10)
-            for (y = 0; y < Height; y += 100)
-                setplus(x, y, ((x%100) == 50) ? 2 : 1);
-        for (x = 0; x < Width; x += 100) {
+    }
+    {
+        unsigned int x;
+        for (x = 0; x < bitmapP->width; x += 10) {
             unsigned int y;
-            for (y = 0; y < Height; y += 10)
-                setplus(x, y, ((y%100) == 50) ? 2 : 1);
+            for (y = 0; y < bitmapP->height; y += 100)
+                setplus(bitmapP, x, y, ((x%100) == 50) ? 2 : 1);
         }
-        setCG(Width/2, Height/2);
+    }
+    {
+        unsigned int x;
+        for (x = 0; x < bitmapP->width; x += 100) {
+            unsigned int y;
+            for (y = 0; y < bitmapP->height; y += 10)
+                setplus(bitmapP, x, y, ((y%100) == 50) ? 2 : 1);
+        }
+    }
+    setCG(bitmapP, bitmapP->width/2, bitmapP->height/2);
+}
+
+
+
+static void
+drawVertical(struct Bitmap * const bitmapP) {
+
+    unsigned int y;
+
+    for (y = 0; y < 300; ++y)
+        setpixel(bitmapP, bitmapP->width/2, bitmapP->height/2 - y, PBM_BLACK);
+}
+
+
+
+static void
+drawDiagonal(struct Bitmap * const bitmapP) {
+
+    unsigned int y;
+
+    for (y = 0; y < 300; ++y) {
+        setpixel(bitmapP, y, y, PBM_BLACK);
+        setpixel(bitmapP, bitmapP->width - 1 - y, bitmapP->height - 1 - y,
+                 PBM_BLACK);
+    }
+}
+
+
+
+int
+main(int argc, const char** argv) {
+
+    struct CmdlineInfo cmdline;
+    /* width and height in 600ths of an inch */
+    unsigned int width;
+    unsigned int height;
+    struct Bitmap bitmap;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    if (cmdline.a4) {
+        width  = a4Width;
+        height = a4Height;
+    } else {
+        width  = usWidth;
+        height = usHeight;
+    }
+
+    bitmap.width  = width;
+    bitmap.height = height;
+    bitmap.bitmap = pbm_allocarray_packed(width, height);
+
+    makeWhite(&bitmap);
+
+    switch (cmdline.pattern) {
+    case PAT_GRID:
+        drawGrid(&bitmap);
         break;
-    case 2:
-        for (y = 0; y < 300; ++y)
-            setpixel(Width/2, Height/2-y, 1);
+    case PAT_VERTICAL:
+        drawVertical(&bitmap);
         break;
-    case 3:
-        for (y = 0; y < 300; ++y) {
-            setpixel(y, y, 1);
-            setpixel(Width-1-y, Height-1-y, 1);
-        }
+    case PAT_DIAGONAL:
+        drawDiagonal(&bitmap);
         break;
-    default:
-        pm_error("unknown test pattern (%d)", TP);
     }
 
     outputPbm(stdout, bitmap);
 
-    pbm_freearray(bitmap.bitmap, Height);
+    pbm_freearray(bitmap.bitmap, height);
 
     pm_close(stdout);
 
diff --git a/generator/pbmtext.c b/generator/pbmtext.c
index e6f27865..a4566d12 100644
--- a/generator/pbmtext.c
+++ b/generator/pbmtext.c
@@ -30,7 +30,17 @@
 #include "pbm.h"
 #include "pbmfont.h"
 
-#define  MAXLINECHARS 5000
+
+/* Max length of input text.  Valid for text which is part of the
+   command line and also for text fed from standard input.
+   Note that newline is counted as a character.
+*/
+#define  MAXLINECHARS 4999
+
+/* We add one slot for the terminating NULL charter
+   and another slot as a margin to detect overruns.
+*/
+#define  LINEBUFSIZE  (MAXLINECHARS + 2)
 
 struct CmdlineInfo {
     /* All the information the user supplied in the command line,
@@ -46,6 +56,7 @@ struct CmdlineInfo {
     unsigned int nomargins;  /* -nomargins option specified  */
     unsigned int dryrun;     /* -dry-run option specified */
     unsigned int textdump;   /* -text-dump option specified */
+    unsigned int entirefont; /* -load-entire-font option specified */
     unsigned int verbose;    /* -verbose option specified */
         /* undocumented option */
     unsigned int dumpsheet; /* font data sheet in PBM format for -font */
@@ -61,7 +72,7 @@ textFmCmdLine(int argc, const char ** argv) {
     unsigned int i;
     unsigned int totaltextsize;
 
-    MALLOCARRAY(text, MAXLINECHARS+1);
+    MALLOCARRAY(text, LINEBUFSIZE);
 
     if (!text)
         pm_error("Unable to allocate memory for a buffer of up to %u "
@@ -69,13 +80,15 @@ textFmCmdLine(int argc, const char ** argv) {
 
     text[0] = '\0';
 
-    for (i = 1, totaltextsize = 1; i < argc; ++i) {
+    for (i = 1, totaltextsize = 0; i < argc; ++i) {
         if (i > 1) {
             strcat(text, " ");
         }
-        totaltextsize += strlen(argv[i]) + 1;
+        totaltextsize += strlen(argv[i]) + (i > 1 ? 1 : 0);
         if (totaltextsize > MAXLINECHARS)
-            pm_error("input text too long");
+           pm_error("Input text is %u characters.  "
+                    "Cannot process longer than %u",
+                    totaltextsize, (unsigned int) MAXLINECHARS);
         strcat(text, argv[i]);
     }
     MALLOCARRAY(wtext, totaltextsize * sizeof(PM_WCHAR));
@@ -84,7 +97,7 @@ textFmCmdLine(int argc, const char ** argv) {
         pm_error("Unable to allocate memory for a buffer of up to %u "
                  "wide characters of text", totaltextsize);
 
-    for (i = 0; i < totaltextsize; ++i)
+    for (i = 0; i < totaltextsize + 1; ++i)
         wtext[i] = (PM_WCHAR) text[i];
 
     free(text);
@@ -122,6 +135,7 @@ parseCommandLine(int argc, const char ** argv,
     OPTENT3(0, "dry-run",    OPT_FLAG,   NULL, &cmdlineP->dryrun,    0);
     OPTENT3(0, "text-dump",  OPT_FLAG,   NULL, &cmdlineP->textdump,  0);
     OPTENT3(0, "dump-sheet", OPT_FLAG,   NULL, &cmdlineP->dumpsheet, 0);
+    OPTENT3(0, "load-entire-font", OPT_FLAG,   NULL, &cmdlineP->entirefont, 0);
 
     /* Set the defaults */
     cmdlineP->font    = NULL;
@@ -153,6 +167,11 @@ parseCommandLine(int argc, const char ** argv,
     else if (cmdlineP->lspace < -pbm_maxfontheight())
         pm_error("negative -lspace value too large");
 
+    if (cmdlineP->font != NULL && cmdlineP->builtin != NULL)
+        pm_error("You cannot specify both -font and -builtin");
+    else if (cmdlineP->font == NULL && cmdlineP->entirefont)
+        pm_error("You cannot specify -load-entire-font without -font");
+
     if (cmdlineP->textdump) {
         if (cmdlineP->dryrun)
             pm_error("You cannot specify both -dry-run and -text-dump");
@@ -170,9 +189,8 @@ parseCommandLine(int argc, const char ** argv,
             pm_error("-wchar is not valid when text is from command line");
 
         cmdlineP->text = textFmCmdLine(argc, argv);
-
-
     }
+
     free(option_def);
 }
 
@@ -193,12 +211,10 @@ reportFont(const struct font2 * const fontP) {
 
 
 
-
-
-
 static struct font2 *
-font2FromFile(const char * const fileName,
-              PM_WCHAR     const maxmaxglyph) {
+font2FromFile(const char *               const fileName,
+              PM_WCHAR                   const maxmaxglyph,
+              const struct pm_selector * const selectorP) {
 
     struct font2 * font2P;
 
@@ -211,7 +227,7 @@ font2FromFile(const char * const fileName,
         /* This is the normal program flow */
         pm_setjmpbuf(&jmpbuf);
 
-        font2P = pbm_loadfont2(fileName, maxmaxglyph);
+        font2P = pbm_loadfont2select(fileName, maxmaxglyph, selectorP);
 
         pm_setjmpbuf(NULL);
     } else {
@@ -228,23 +244,176 @@ font2FromFile(const char * const fileName,
 
 
 
+static bool
+codepointIsValid(struct font2 * const fontP,
+                 PM_WCHAR       const codepoint) {
+/*----------------------------------------------------------------------------
+  'codepoint' is a valid entry in the font indicated by 'fontP'.
+-----------------------------------------------------------------------------*/
+    bool retval;
+
+    assert(pm_selector_is_marked(fontP->selectorP, codepoint));
+
+    if (codepoint > fontP->maxglyph || fontP->glyph[codepoint] == NULL)
+        retval = false;
+    else retval = true;
+
+    return (retval);
+
+}
+
+
+
+static const char *
+charDescription(PM_WCHAR const codepoint) {
+/*----------------------------------------------------------------------------
+   Descriptive string for codepoint 'codepoint'.
+
+   Certain codepoints appear frequently in text files and cause problems when
+   missing in the font set, so we give those descriptions.  For other
+   codepoint, we just return a null string.
+-----------------------------------------------------------------------------*/
+
+  const char * name;
+
+  switch (codepoint) {
+  case '\r' : name="carriage return";  break;
+  case '\n' : name="line feed";        break; /* for future use */
+  case '\t' : name="tab";              break; /* for future use */
+  case ' '  : name="space";            break;
+  case 0xFEFF: name="byte order mark"; break;
+  default : name=""; break;
+  }
+
+  return name;
+}
+
+
+
+enum FixMode {SILENT, /* convert silently */
+              WARN,   /* output message to stderr */
+              QUIT    /* abort */ };
+
+
+
 static void
-computeFont(struct CmdlineInfo const cmdline,
-            struct font2 **    const fontPP) {
+reportAbsentGlyphs(bool                       const wchar,
+                   struct font2 *             const fontP,
+                   const struct pm_selector * const textSelectorP,
+                   unsigned int *             const missingCharCtP) {
+/*----------------------------------------------------------------------------
+   Compare the glyph entries in *fontP with the requests in *textSelectorP.
 
-    struct font2 * font2P;
+   Note that we may need the space character as a substitute for missing
+   glyphs while the input text has no spaces.  In rare cases the font may not
+   have a space character.
+
+   Currently, this program reads the font file only once.  A future version
+   may opt to read it a second time to load the substitute glyph.
+-----------------------------------------------------------------------------*/
+    PM_WCHAR     codepoint;
+    unsigned int missingCharCt;
+
+    for (codepoint = textSelectorP->min, missingCharCt = 0;
+         codepoint <= textSelectorP->max; ++codepoint) {
+
+        if (pm_selector_is_marked(textSelectorP, codepoint) &&
+            !codepointIsValid(fontP, codepoint)) {
+            ++missingCharCt;
+            if (missingCharCt == 1)  { /* initial */
+                pm_message("failed to load glyph data for these code points "
+                           "in input:");
+            }
+
+            pm_message(wchar ? "+%05X %s" : "%02X %s",
+                       (unsigned int) codepoint,
+                       charDescription(codepoint));
+        }
+    }
+
+    *missingCharCtP = missingCharCt;
+}
+
+
+
+static void
+validateFont(bool                       const wchar,
+             struct font2 *             const fontP,
+             const struct pm_selector * const textSelectorP,
+             enum   FixMode             const fixmode,
+             bool                       const verbose,
+             bool *                     const hasAllCharsP) {
+/*----------------------------------------------------------------------------
+   If any glyphs required by the text indicated by *textSelectorP are missing
+   from font *fontP, issue a warning message or abort the program according to
+   'fixmode'.
+
+   Abort the program if one or more characters are missing and the space
+   character is one of them.
+
+   Return (if we return) as *hasAllCharsP whether the font has all the glyphs.
+-----------------------------------------------------------------------------*/
+    unsigned int missingCharCt;
+
+    assert (textSelectorP != NULL);
+    assert(pm_selector_marked_ct(textSelectorP) >= 0);
+
+    reportAbsentGlyphs(wchar, fontP, textSelectorP, &missingCharCt);
+
+    if (missingCharCt > 0) {
+        if (verbose)
+            pm_message("%u characters absent in font", missingCharCt);
+
+        if (fixmode == QUIT)
+            pm_error("aborting");
+        else if (!codepointIsValid(fontP, L' '))
+            pm_error ("replacement character (space) absent; aborting");
+        else
+            pm_message("undefined code points will be converted to space");
+    }
+
+    *hasAllCharsP = (missingCharCt == 0);
+}
 
-    if (cmdline.font)
-        font2P = font2FromFile(cmdline.font,
-                               cmdline.wchar ? PM_FONT2_MAXGLYPH :
-                                               PM_FONT_MAXGLYPH);
-    else if (cmdline.builtin)
+
+
+static void
+computeFont(struct CmdlineInfo         const cmdline,
+            struct font2 **            const fontPP,
+            const struct pm_selector * const textSelectorP,
+            enum   FixMode             const fixmode,
+            bool *                     const fontHasAllCharsP) {
+
+    struct font2 *       font2P;
+    struct pm_selector * fontSelectorP;
+
+    if (cmdline.font) {
+        if(cmdline.entirefont)
+            fontSelectorP = NULL;
+        else if(!pm_selector_is_marked(textSelectorP, L' ')) {
+            pm_selector_copy(MAX(textSelectorP->max, L' '),
+                             textSelectorP, &fontSelectorP);
+            pm_selector_mark(fontSelectorP, L' ');
+        } else
+            fontSelectorP = (struct pm_selector *) textSelectorP;
+
+        font2P = font2FromFile(cmdline.font, cmdline.wchar ?
+                               PM_FONT2_MAXGLYPH : PM_FONT_MAXGLYPH,
+                               fontSelectorP);
+    } else if (cmdline.builtin)
         font2P = pbm_defaultfont2(cmdline.builtin);
     else
         font2P = pbm_defaultfont2(cmdline.wchar ? "bdf" : "bdf");
 
-    if (cmdline.verbose)
+    if (cmdline.verbose) {
         reportFont(font2P);
+        pm_message("%u code points found in text",
+                   pm_selector_marked_ct(textSelectorP));
+    }
+
+    validateFont(cmdline.wchar, font2P, textSelectorP, fixmode,
+                 cmdline.verbose,
+                 fontHasAllCharsP);
 
     *fontPP = font2P;
 }
@@ -253,9 +422,6 @@ computeFont(struct CmdlineInfo const cmdline,
 
 struct Text {
     PM_WCHAR **  textArray;  /* malloc'ed */
-        /* This is strictly characters that are in user's font - no control
-           characters, no undefined code points.
-        */
     unsigned int allocatedLineCount;
     unsigned int lineCount;
 };
@@ -296,28 +462,19 @@ freeTextArray(struct Text const text) {
 
 
 
-enum FixMode {SILENT, /* convert silently */
-              WARN,   /* output message to stderr */
-              QUIT    /* abort */ };
-
 
 static void
-fixControlChars(const PM_WCHAR  * const input,
-                struct font2    * const fontP,
-                const PM_WCHAR ** const outputP,
-                enum FixMode      const fixMode) {
+setupSelector(const PM_WCHAR *     const input,
+              const PM_WCHAR **    const outputP,
+              struct pm_selector * const selectorP) {
 /*----------------------------------------------------------------------------
-   Return a translation of input[] that can be rendered as glyphs in
-   the font 'fontP'.  Return it as newly malloced *outputP.
+   Read through input[] and record the codepoints encountered.  Return it as
+   newly malloced *outputP.
 
    Expand tabs to spaces.
 
    Remove any trailing newline.  (But leave intermediate ones as line
    delimiters).
-
-   Depending on value of fixMode, turn anything that isn't a code point
-   in the font to a single space (which isn't guaranteed to be in the
-   font either, of course).
 -----------------------------------------------------------------------------*/
     /* We don't know in advance how big the output will be because of the
        tab expansions.  So we make sure before processing each input
@@ -357,33 +514,19 @@ fixControlChars(const PM_WCHAR  * const input,
             unsigned int const nextTabStop =
                 (outCursor + tabSize) / tabSize * tabSize;
 
-            if (fontP->glyph[L' '] == NULL)
-                pm_error("space character not defined in font");
-
             while (outCursor < nextTabStop)
                 output[outCursor++] = L' ';
-        } else if (currentChar > fontP->maxglyph ||
-                   !fontP->glyph[currentChar]) {
-            if (currentChar > PM_FONT2_MAXGLYPH)
+
+            pm_selector_mark(selectorP, L' ');
+
+        } else if (currentChar > PM_FONT2_MAXGLYPH)
                 pm_message("code point %X is beyond what this program "
                            "can handle.  Max=%X",
                            (unsigned int)currentChar, PM_FONT2_MAXGLYPH);
-
-            /* Turn this unknown char into a single space. */
-            if (fontP->glyph[L' '] == NULL)
-                pm_error("space character not defined in font");
-            else if (fixMode == QUIT)
-                pm_error("code point %X not defined in font",
-                         (unsigned int) currentChar );
-            else {
-                if (fixMode == WARN)
-                    pm_message("converting code point %X to space",
-                               (unsigned int) currentChar );
-                output[outCursor++] = ' ';
-            }
-        } else
+        else {
             output[outCursor++] = input[inCursor];
-
+            pm_selector_mark(selectorP, currentChar);
+        }
         assert(outCursor <= outputSize);
     }
     output[outCursor++] = L'\0';
@@ -424,7 +567,8 @@ getEdges(double               const currentPosition,
     double rightEdge;
 
     if (glyphP == NULL)
-        pm_error("Unrenderable char: %04X", (unsigned int) currentChar);
+        pm_error("encountered unrenderable char: %04X",
+                  (unsigned int) currentChar);
     else {
         leftEdge  =  (int) MIN(currentPosition + glyphP->x, currLeftEdge);
         rightEdge =  MAX(currentPosition + glyphP->x + glyphP->width,
@@ -462,8 +606,8 @@ advancePosition(double               const currentPosition,
             pm_error("Negative -space value too large");
         else
             pm_error("Abnormal horizontal advance value %d "
-                     "for code point 0x%lx.",
-                     glyphP->xadd, (unsigned long int) currentChar);
+                     "for code point +%05X",
+                     glyphP->xadd, (unsigned int) currentChar);
     }
     else if (currentPosition + advance > INT_MAX)
         pm_error("Image is too wide");
@@ -522,8 +666,8 @@ getLineDimensions(PM_WCHAR             const line[],
 
     for (cursor = 0; line[cursor] != L'\0'; ++cursor) {
         PM_WCHAR          const currentChar = line[cursor];
-        unsigned long int const glyphIndex  = (unsigned long int) currentChar;
-        struct glyph *    const glyphP      = fontP->glyph[glyphIndex];
+        unsigned int      const index       = (unsigned int) currentChar;
+        struct glyph *    const glyphP      = fontP->glyph[index];
 
         getEdges(currentPosition, currentChar, glyphP, leftEdge, rightEdge,
                  &leftEdge, &rightEdge);
@@ -580,9 +724,8 @@ getCharsWithinWidth(PM_WCHAR             const line[],
              currentWidth <= targetWidth && line[cursor] != L'\0';
              ++cursor) {
             PM_WCHAR const currentChar = line[cursor];
-            unsigned long int const glyphIndex =
-              (unsigned long int) currentChar;
-            struct glyph * const glyphP = fontP->glyph[glyphIndex];
+            unsigned int const index = (unsigned int) currentChar;
+            struct glyph * const glyphP = fontP->glyph[index];
 
             getEdges(currentPosition, currentChar, glyphP, leftEdge, rightEdge,
                      &leftEdge, &rightEdge);
@@ -597,7 +740,7 @@ getCharsWithinWidth(PM_WCHAR             const line[],
         if (currentWidth > targetWidth) {
             if (cursor == 1)
                 pm_error("-width value too small "
-                         "to accomodate single character");
+                         "to accommodate single character");
             else
                 *charCountP = cursor - 1;
         } else
@@ -681,9 +824,8 @@ insertCharacters(bit **         const bits,
 
         for (cursor = 0; lp.textArray[line][cursor] != '\0'; ++cursor) {
             PM_WCHAR const currentChar = lp.textArray[line][cursor];
-            unsigned long int const glyphIndex =
-                (unsigned long int)currentChar;
-            struct glyph * const glyphP = fontP->glyph[glyphIndex];
+            unsigned int const index = (unsigned int) currentChar;
+            struct glyph * const glyphP = fontP->glyph[index];
             int const toprow =
                 row + fontP->maxheight + fontP->y - glyphP->height - glyphP->y;
                 /* row number in image of top row in glyph */
@@ -798,7 +940,7 @@ fgetWideString(PM_WCHAR *    const widestring,
     wchar_t * rc;
 
     assert(widestring);
-    assert(size > 0);
+    assert(size > 1);
 
     rc = fgetws(widestring, size, ifP);
 
@@ -836,7 +978,7 @@ fgetNarrowString(PM_WCHAR *    const widestring,
     assert(widestring);
     assert(size > 0);
 
-    MALLOCARRAY_NOFAIL(bufNarrow, MAXLINECHARS+1);
+    MALLOCARRAY_NOFAIL(bufNarrow, LINEBUFSIZE);
 
     rc = fgets(bufNarrow, size, ifP);
 
@@ -869,7 +1011,8 @@ fgetNarrowWideString(PM_WCHAR *    const widestring,
                      bool *        const eofP,
                      const char ** const errorP) {
 /*----------------------------------------------------------------------------
-  Return the next line from file *ifP, as *widestring.
+  Return the next line from file *ifP, as *widestring, a buffer 'size'
+  characters long.
 
   Lines are delimited by newline characters and EOF.
 
@@ -929,10 +1072,9 @@ fgetNarrowWideString(PM_WCHAR *    const widestring,
 
 
 static void
-getText(PM_WCHAR       const cmdlineText[],
-        struct font2 * const fontP,
-        struct Text  * const inputTextP,
-        enum FixMode   const fixMode) {
+getText(PM_WCHAR             const cmdlineText[],
+        struct Text *        const inputTextP,
+        struct pm_selector * const selectorP) {
 /*----------------------------------------------------------------------------
    Get as *inputTextP the text to format, given that the text on the
    command line (one word per command line argument, separated by spaces),
@@ -955,14 +1097,16 @@ getText(PM_WCHAR       const cmdlineText[],
         MALLOCARRAY_NOFAIL(inputText.textArray, 1);
         inputText.allocatedLineCount = 1;
         inputText.lineCount = 1;
-        fixControlChars(cmdlineText, fontP,
-                        (const PM_WCHAR**)&inputText.textArray[0], fixMode);
+        setupSelector(cmdlineText, (const PM_WCHAR**) &inputText.textArray[0],
+                      selectorP);
         free((void *) cmdlineText);
     } else {
         /* Read text from stdin. */
 
+        unsigned int const lineBufTerm = LINEBUFSIZE - 1;
+
         unsigned int maxlines;
-            /* Maximum number of lines for which we presently have space in
+            /* Maximum number of lines for which we currently have space in
                the text array
             */
         PM_WCHAR *   buf;
@@ -970,11 +1114,13 @@ getText(PM_WCHAR       const cmdlineText[],
         unsigned int lineCount;
         bool         eof;
 
-        MALLOCARRAY(buf, MAXLINECHARS+1);
+        MALLOCARRAY(buf, LINEBUFSIZE);
 
         if (!buf)
             pm_error("Unable to allocate memory for up to %u characters of "
                      "text", MAXLINECHARS);
+        buf[lineBufTerm] = L'\1';  /* Initialize to non-zero value */
+                                   /* to detect input overrun */
 
         maxlines = 50;  /* initial value */
         MALLOCARRAY(textArray, maxlines);
@@ -985,27 +1131,27 @@ getText(PM_WCHAR       const cmdlineText[],
 
         for (lineCount = 0, eof = false; !eof; ) {
             const char * error;
-            fgetNarrowWideString(buf, MAXLINECHARS, stdin, &eof, &error);
+            fgetNarrowWideString(buf, LINEBUFSIZE, stdin, &eof, &error);
             if (error)
                 pm_error("Unable to read line %u from file.  %s",
                          lineCount, error);
             else {
                 if (!eof) {
-                    if (wcslen(buf) + 1 >= MAXLINECHARS)
+                    if (buf[lineBufTerm] == L'\0') /* overrun */
                         pm_error(
                             "Line %u (starting at zero) of input text "
-                            "is longer than %u characters."
+                            "is longer than %u characters. "
                             "Cannot process",
-                            lineCount, (unsigned int) MAXLINECHARS-1);
+                            lineCount, (unsigned int) MAXLINECHARS);
                     if (lineCount >= maxlines) {
                         maxlines *= 2;
                         REALLOCARRAY(textArray, maxlines);
                         if (textArray == NULL)
                             pm_error("out of memory");
                     }
-                    fixControlChars(buf, fontP,
-                                    (const PM_WCHAR **)&textArray[lineCount],
-                                    fixMode);
+                    setupSelector(buf,
+                                  (const PM_WCHAR **) &textArray[lineCount],
+                                  selectorP);
                     if (textArray[lineCount] == NULL)
                         pm_error("out of memory");
                     ++lineCount;
@@ -1046,6 +1192,33 @@ computeMargins(struct CmdlineInfo const cmdline,
 
 
 static void
+refineText(struct Text        const inputText,
+           struct font2 *     const fontP) {
+/*----------------------------------------------------------------------------
+   Replace missing characters with space
+
+   A future version of this program may provide various alternatives
+   here including simply deleting the offending character, based on a
+   command-line option
+-----------------------------------------------------------------------------*/
+    PM_WCHAR ** const textArray = inputText.textArray;
+
+    unsigned int lineNum;
+
+    for (lineNum = 0; lineNum < inputText.lineCount; ++lineNum) {
+        PM_WCHAR * const line = textArray[lineNum];
+
+        unsigned int cursor;
+
+        for (cursor = 0; line[cursor] != L'\0'; ++cursor)
+            if ( !codepointIsValid(fontP, line[cursor]) )
+                line[cursor] = L' ';
+    }
+}
+
+
+
+static void
 formatText(struct CmdlineInfo const cmdline,
            struct Text        const inputText,
            struct font2 *     const fontP,
@@ -1109,6 +1282,8 @@ computeImageWidth(struct Text          const formattedText,
                   unsigned int *       const colsP,
                   unsigned int *       const maxleftbP) {
 
+    assert (pbm_maxfontwidth() < (INT_MAX - 10) / LINEBUFSIZE);
+
     if (intercharacterSpace < 0 && fontP->maxwidth < -intercharacterSpace)
         pm_error("negative -space value %.2f exceeds font width",
                  intercharacterSpace);
@@ -1173,7 +1348,7 @@ renderText(unsigned int   const cols,
                      space, cols, rows, lspace, fixedAdvance);
 
     /* Free all font data */
-    pbm_destroybdffont2(fontP); 
+    pbm_destroybdffont2(fontP);
 
     {
         unsigned int row;
@@ -1206,36 +1381,31 @@ L"M \",/^_[`jpqy| M" };
 
 
 static void
-validateText(const PM_WCHAR ** const textArray,
-             struct font2    * const fontP) {
-/*----------------------------------------------------------------------------
-   Abort the program if there are characters in 'textArray' which cannot be
-   rendered in font *fontP.
------------------------------------------------------------------------------*/
-    const PM_WCHAR * output;
-    unsigned int textRow;
-
-    for (textRow = 0; textRow < 12; ++textRow)
-        fixControlChars(textArray[textRow], fontP, &output, QUIT);
-
-    free((PM_WCHAR *)output);
-}
+renderSheet(struct CmdlineInfo const cmdline,
+            FILE *             const ofP) {
 
+    struct Text const sheetText =
+        { (PM_WCHAR ** const) sheetTextArray, 12, 12};
+    static unsigned char const sheetRequestArray[16] = {
+         0x00, 0x00, 0x00, 0x00,  0xff, 0xff, 0xff, 0xff,
+         0xff, 0xff, 0xff, 0xff,  0xff, 0xff, 0xff, 0xfe};
 
+    struct pm_selector * selectorP;
+    struct font2 *       fontP;
+    bool                 fontIsComplete;
 
-static void
-renderSheet(struct font2 * const fontP,
-            FILE *         const ofP) {
+    pm_selector_create_fixed(sheetRequestArray, 32, 126,95, &selectorP);
 
-    int const cols  = fontP->maxwidth  * 16;
-    int const rows  = fontP->maxheight * 12;
-    struct Text const sheetText =
-        { (PM_WCHAR ** const) sheetTextArray, 12, 12};
+    computeFont(cmdline, &fontP, selectorP, QUIT, &fontIsComplete);
 
-    validateText(sheetTextArray, fontP);
+    {
+        unsigned int const cols  = fontP->maxwidth  * 16;
+        unsigned int const rows  = fontP->maxheight * 12;
 
-    renderText(cols, rows, fontP, 0, 0, sheetText, MAX(-(fontP->x),0),
-               0.0, 0, TRUE, ofP);
+        renderText(cols, rows, fontP, 0, 0, sheetText, MAX(-(fontP->x),0),
+                   0.0, 0, TRUE, ofP);
+    }
+    pm_selector_destroy(selectorP);
 }
 
 
@@ -1286,8 +1456,8 @@ textDumpOutput(struct Text   const lp,
 
 static void
 pbmtext(struct CmdlineInfo const cmdline,
-        struct font2 *     const fontP,
-        FILE *             const ofP) {
+        FILE *             const ofP,
+        bool               const wchar) {
 
     unsigned int rows, cols;
         /* Dimensions in pixels of the output image */
@@ -1297,19 +1467,30 @@ pbmtext(struct CmdlineInfo const cmdline,
     unsigned int hmargin0;
     struct Text inputText;
     struct Text formattedText;
+    struct font2 * fontP;
+    struct pm_selector * selectorP;
     unsigned int maxleftb, maxleftb0;
+    bool fontIsComplete;
+
+    pm_selector_create(wchar ? PM_FONT2_MAXGLYPH : PM_FONT_MAXGLYPH,
+                       &selectorP);
 
-    getText(cmdline.text, fontP, &inputText,
-            cmdline.verbose ? WARN : SILENT);
+    getText(cmdline.text, &inputText, selectorP);
+
+    if (pm_selector_marked_ct(selectorP) == 0)
+        pm_error("No input text.  Aborting.");
+
+    computeFont(cmdline, &fontP, selectorP, cmdline.verbose ? WARN : SILENT,
+                &fontIsComplete);
 
     computeMargins(cmdline, inputText, fontP, &vmargin, &hmargin0);
 
+    if (!fontIsComplete)
+        refineText(inputText, fontP);
+
     formatText(cmdline, inputText, fontP, hmargin0,
                &formattedText, &maxleftb0);
 
-    if (formattedText.lineCount == 0)
-        pm_error("No input text");
-
     computeImageHeight(formattedText, fontP, cmdline.lspace, vmargin, &rows);
 
     computeImageWidth(formattedText, fontP, cmdline.space,
@@ -1343,6 +1524,8 @@ pbmtext(struct CmdlineInfo const cmdline,
                    maxleftb, cmdline.space, cmdline.lspace, FALSE, ofP);
 
     freeTextArray(formattedText);
+
+    pm_selector_destroy(selectorP);
 }
 
 
@@ -1351,7 +1534,6 @@ int
 main(int argc, const char *argv[]) {
 
     struct CmdlineInfo cmdline;
-    struct font2 * fontP;
 
     pm_proginit(&argc, argv);
 
@@ -1371,12 +1553,10 @@ main(int argc, const char *argv[]) {
     if (cmdline.verbose)
         pm_message("LC_CTYPE is set to '%s'", setlocale(LC_CTYPE, NULL) );
 
-    computeFont(cmdline, &fontP);
-
     if (cmdline.dumpsheet)
-        renderSheet(fontP, stdout);
+        renderSheet(cmdline, stdout);
     else
-        pbmtext(cmdline, fontP, stdout);
+        pbmtext(cmdline, stdout, cmdline.wchar);
 
     pm_close(stdout);
 
diff --git a/generator/pbmtextps.c b/generator/pbmtextps.c
index f543618d..2a1173de 100644
--- a/generator/pbmtextps.c
+++ b/generator/pbmtextps.c
@@ -27,6 +27,7 @@
 
 #define _XOPEN_SOURCE 500
   /* Make sure popen() is in stdio.h, strdup() is in string.h */
+
 #include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -41,6 +42,8 @@
 #include "pm_system.h"
 #include "pbm.h"
 
+enum InputFmt {INPUT_LITERAL, INPUT_ASCIIHEX, INPUT_ASCII85};
+
 static void
 validateFontName(const char * const name) {
 /*-----------------------------------------------------------------------------
@@ -52,6 +55,9 @@ validateFontName(const char * const name) {
 -----------------------------------------------------------------------------*/
     unsigned int idx;
 
+    if (name[0] == '\0')
+        pm_error("Font name is empty string");
+
     for (idx = 0; name[idx] != '\0'; ++idx) {
         char const c = name[idx];
 
@@ -71,8 +77,8 @@ validateFontName(const char * const name) {
 
 
 static void
-asciiHexEncode(char *          const inbuff,
-               char *          const outbuff) {
+asciiHexEncode(const char * const inbuff,
+               char *       const outbuff) {
 /*-----------------------------------------------------------------------------
   Convert the input text string to ASCII-Hex encoding.
 
@@ -83,69 +89,357 @@ asciiHexEncode(char *          const inbuff,
 
     unsigned int idx;
 
+    outbuff[0] = '<';
+
     for (idx = 0; inbuff[idx] != '\0'; ++idx) {
         unsigned int const item = (unsigned char) inbuff[idx];
 
-        outbuff[idx*2]   = hexits[item >> 4];
-        outbuff[idx*2+1] = hexits[item & 0xF];
+        outbuff[1 + idx * 2 + 0] = hexits[item >> 4];
+        outbuff[1 + idx * 2 + 1] = hexits[item & 0xF];
     }
 
-    outbuff[idx * 2] = '\0';
+    if (idx == 0)
+        pm_message("Empty input string");
+
+    outbuff[1 + idx * 2] = '>';
+    outbuff[1 + idx * 2 + 1] = '\0';
 }
 
 
 
 static void
-buildTextFromArgs(int           const argc,
-                  const char ** const argv,
-                  const char ** const asciiHexTextP) {
+failForInvalidChar(char         const c,
+                   const char * const type) {
+
+    if (c >= 0x32 || c < 0x7F)
+        pm_error("Invalid character '%c' in '%s' input string",   c, type);
+    else
+        pm_error("Invalid character 0x%02x in '%s' input string", c, type);
+}
+
+
+
+static void
+formatNonemptyAsciiHex(const char * const inbuff,
+                       char       * const outbuff,
+                       unsigned int const inLen) {
+
+    unsigned int inIdx, outIdx;
+        /* Cursors in input and output buffers, respectively */
+    unsigned int validCharCt;
+        /* Number of valid hex characters we've processed so far in input */
+    unsigned int startIdx, endIdx;
+        /* Limits of input buffer cursor ('inIdx') */
+
+     if (inbuff[0] == '<') {
+         startIdx = 1;
+         endIdx = inLen - 2;
+     } else {
+         startIdx = 0;
+         endIdx = inLen - 1;
+     }
+
+     validCharCt = 0;  /* No valid characters seen yet */
+
+     outIdx = 0;  /* Start at beginning of output buffer */
+
+     outbuff[outIdx++] = '<';
+
+     for (inIdx = startIdx; inIdx <= endIdx; ++inIdx) {
+         switch (inbuff[inIdx]) {
+         case '<':
+         case '>':
+             pm_error("Misplaced character '%c' in Ascii Hex input string",
+                      inbuff[inIdx]);
+           break;
+         case '\f':
+         case '\n':
+         case '\r':
+         case ' ':
+         case '\t':
+             /* ignore whitespace chars */
+             break;
+         default:
+             if ((inbuff [inIdx] >='0' && inbuff [inIdx] <='9') ||
+                 (inbuff [inIdx] >='A' && inbuff [inIdx] <='F') ||
+                 (inbuff [inIdx] >='a' && inbuff [inIdx] <='f')) {
+
+                 outbuff[outIdx++] = inbuff [inIdx];
+                 ++validCharCt;
+             } else
+                 failForInvalidChar(inbuff[inIdx], "Ascii Hex");
+             break;
+         }
+     }
+
+     if (validCharCt == 0)
+         pm_message("Empty Ascii Hex input string");
+     else if (validCharCt % 2 != 0)
+         pm_error("Number of characters in Ascii Hex input string "
+                  "is not even");
+
+     outbuff[outIdx++] = '>';
+     outbuff[outIdx++] = '\0';
+}
+
+
+
+static void
+formatAsciiHexString(const char * const inbuff,
+                     char       * const outbuff,
+                     unsigned int const inLen) {
 /*----------------------------------------------------------------------------
-   Build the array of text to be included in the Postscript program to
-   be rendered, from the arguments of this program.
-
-   We encode it in ASCII-Hex notation as opposed to using the plain text from
-   the command line because 1) the command line might have Postscript control
-   characters in it; and 2) the command line might have text in 8-bit or
-   multibyte code, but a Postscript program is supposed to be entirely
-   printable ASCII characters.
------------------------------------------------------------------------------*/
-    char * text;
+  Format the ASCII Hex input 'inbuff' as a Postscript ASCII Hex string,
+  e.g. "<313233>".  Input can be just the ASCII Hex (e.g. "313233") or already
+  formatted (e.g. "<313233>").  Input may also contain white space, which we
+  ignore -- our output never contains white space.  Though in Postscript, an
+  ASCII NUL character counts as white space, we consider it the end of the
+  input.
+
+  We consider white space outside of the <> delimiters to be an error.
+
+  Abort with error message if there is anything other than valid hex digits in
+  the ASCII hex string proper.  This is necessary to prevent code injection.
+----------------------------------------------------------------------------*/
+    if (inLen == 0 ||
+        (inLen == 2 && inbuff[0] == '<' && inbuff[inLen-1] == '>' )) {
+        pm_message("Empty Ascii Hex input string");
+        strncpy(outbuff, "<>", 3);
+    } else {
+        if (inbuff[0] == '<' && inbuff[inLen-1] != '>' )
+            pm_error("Ascii Hex input string starts with '<' "
+                     "but does not end with '>'");
+        else if (inbuff[0] != '<' && inbuff[inLen-1] == '>' )
+            pm_error("Ascii Hex input string ends with '>' "
+                     "but does not start with '<'");
+
+        formatNonemptyAsciiHex(inbuff, outbuff, inLen);
+    }
+}
+
+
+
+static void
+formatNonemptyAscii85(const char * const inbuff,
+                      char       * const outbuff,
+                      unsigned int const inLen) {
+
+    unsigned int inIdx, outIdx;
+        /* Cursors in input and output buffers, respectively */
+    unsigned int seqPos;
+        /* Position in 5-character Ascii-85 sequence where 'inIdx' points */
+    unsigned int startIdx, endIdx;
+        /* Limits of input buffer cursor ('inIdx') */
+
+    if (inLen > 4 && inbuff[0] == '<' && inbuff[1] == '~' &&
+        inbuff[inLen-2] == '~' && inbuff[inLen-1] == '>') {
+        startIdx = 2;
+        endIdx = inLen - 3;
+    } else {
+        startIdx = 0;
+        endIdx = inLen - 1;
+    }
+
+    seqPos = 0;  /* No 5-character Ascii-85 sequence encountered yet */
+    outIdx = 0;  /* Start filling output buffer from beginning */
+
+    outbuff[outIdx++] = '<';
+    outbuff[outIdx++] = '~';
+
+    for (inIdx = startIdx; inIdx <= endIdx; ++inIdx) {
+      switch (inbuff[inIdx]) {
+      case '~':
+          pm_error("Misplaced character '~' in Ascii 85 input string");
+          break;
+      case '\f':
+      case '\n':
+      case '\r':
+      case ' ':
+      case '\t':
+          break;
+      case 'z':
+          /* z extension */
+          if (seqPos > 0)
+              pm_error("Special 'z' character appears in the middle of a "
+                       "5-character Ascii-85 sequence, which is invalid");
+          else
+              outbuff[outIdx++] = inbuff[inIdx];
+          break;
+        default:
+          /* valid Ascii 85 char */
+          if (inbuff [inIdx] >='!' && inbuff [inIdx] <='u') {
+              outbuff[outIdx++] = inbuff[inIdx];
+              seqPos = (seqPos + 1) % 5;
+          } else
+              failForInvalidChar(inbuff[inIdx], "Ascii 85");
+          break;
+      }
+    }
+
+    if (outIdx == 2) {
+        pm_message("Empty Ascii 85 input string");
+    }
+
+    outbuff[outIdx++]   = '~';
+    outbuff[outIdx++] = '>';
+    outbuff[outIdx++] = '\0';
+}
+
+
+
+static void
+formatAscii85String(const char * const inbuff,
+                    char       * const outbuff,
+                    unsigned int const inLen) {
+/*----------------------------------------------------------------------------
+  Format the Ascii-85 input 'inbuff' as a Postscript Ascii-85 string,
+  e.g. "<~313233~>".  Input can be just the Ascii-85 (e.g. "313233") or
+  already formatted (e.g. "<~313233~>").  Input may also contain white space,
+  which we ignore -- our output never contains white space.  Though in
+  Postscript, an ASCII NUL character counts as white space, we consider it the
+  end of the input.
+
+  We consider white space outside of the <~~> delimiters to be an error.
+
+  Abort with error message if we encounter anything other than valid Ascii-85
+  encoding characters in the string proper.  Note that the Adobe variant
+  does not support the "y" extention.
+----------------------------------------------------------------------------*/
+    if (inLen == 0 || (inLen == 4 && strncmp (inbuff, "<~~>", 4) == 0)) {
+        pm_message("Empty Ascii 85 input string");
+        strncpy(outbuff,"<~~>", 5);
+    } else {
+        if (inLen >= 2) {
+            if (inbuff[0] == '<' && inbuff[1] == '~' &&
+                (inLen < 4 || inbuff[inLen-2] != '~'
+                 || inbuff[inLen-1] != '>' ))
+                pm_error("Ascii 85 input string starts with '<~' "
+                         "but does not end with '~>'");
+            else if (inbuff[inLen-2] == '~' && inbuff[inLen-1] == '>' &&
+                     (inLen < 4 || inbuff[0] != '<' || inbuff[1] != '~'))
+                pm_error("Ascii 85 input string ends with '~>' "
+                         "but does not start with '<~'");
+        }
+        formatNonemptyAscii85(inbuff, outbuff, inLen);
+    }
+}
+
+
+
+static void
+combineArgs(int            const argc,
+            const char **  const argv,
+            const char **  const textP,
+            unsigned int * const textSizeP) {
+
     unsigned int totalTextSize;
+    char * text;
+    size_t * argSize;
     unsigned int i;
+    size_t idx;
+
+    MALLOCARRAY_NOFAIL(argSize, argc);
+        /* argv[0] not accessed; argSize[0] not used */
+
+    for (i = 1, totalTextSize = 0; i < argc; ++i) {
+        argSize[i] = strlen(argv[i]);
+        totalTextSize += argSize[i];
+    }
+
+    totalTextSize = totalTextSize + (argc - 2);  /* adjust for spaces */
+
+    MALLOCARRAY(text, totalTextSize + 1); /* add one for \0 at end */
+    if (text == NULL)
+        pm_error("out of memory allocating buffer for "
+                 "%u characters of text", totalTextSize);
+
+    strncpy(text, argv[1], argSize[1]);
+    for (i = 2, idx = argSize[1]; i < argc; ++i) {
+        text[idx++] = ' ';
+        strncpy(&text[idx], argv[i], argSize[i]);
+        idx += argSize[i];
+    }
+
+    assert(idx == totalTextSize);
+
+    text[idx++] = '\0';
+
+    assert(strlen(text) == totalTextSize);
+
+    *textP     = text;
+    *textSizeP = totalTextSize;
+
+    free(argSize);
+}
+
+
 
-    text = strdup("");
-    totalTextSize = 1;
+static void
+buildTextFromArgs(int           const argc,
+                  const char ** const argv,
+                  const char ** const inputTextP,
+                  enum InputFmt const inputFmt) {
+/*----------------------------------------------------------------------------
+   Build the string of text to be included in the Postscript program to be
+   rendered, from the arguments of this program.
+
+   We encode it in either ASCII-Hex or ASCII-85 as opposed to using the plain
+   text from the command line because 1) the command line might have
+   Postscript control characters in it; and 2) the command line might have
+   text in 8-bit or multibyte code, but a Postscript program is supposed to be
+   entirely printable ASCII characters.
+
+   Official Postscript specifications have a limit on the length of a program
+   line, which means there is a limit on the length of text string such as we
+   generate.  But we don't worry about that because Ghostscript actually
+   accepts very long program lines.
+-----------------------------------------------------------------------------*/
+    const char * text;
+        /* All the arguments ('argv') concatenated */
+    unsigned int textSize;
+        /* Length of 'text' */
 
     if (argc-1 < 1)
         pm_error("No text");
 
-    for (i = 1; i < argc; ++i) {
-        if (i > 1) {
-            totalTextSize += 1;
-            text = realloc(text, totalTextSize);
-            if (text == NULL)
-                pm_error("out of memory");
-            strcat(text, " ");
-        }
-        totalTextSize += strlen(argv[i]);
-        text = realloc(text, totalTextSize);
-        if (text == NULL)
-            pm_error("out of memory");
-        strcat(text, argv[i]);
-    }
+    combineArgs(argc, argv, &text, &textSize);
 
-    {
+    switch (inputFmt) {
+    case INPUT_LITERAL: {
         char * asciiHexText;
 
-        MALLOCARRAY(asciiHexText, totalTextSize * 2);
-
+        MALLOCARRAY(asciiHexText, textSize * 2 + 3);
         if (!asciiHexText)
             pm_error("Unable to allocate memory for hex encoding of %u "
-                     "characters of text", totalTextSize);
+                     "characters of text", textSize);
 
         asciiHexEncode(text, asciiHexText);
-        *asciiHexTextP = asciiHexText;
+        *inputTextP = asciiHexText;
+    } break;
+    case INPUT_ASCIIHEX: {
+        char * asciiHexText;
+
+        MALLOCARRAY(asciiHexText, textSize + 3);
+        if (!asciiHexText)
+            pm_error("Unable to allocate memory for hex encoding of %u "
+                     "characters of text", textSize);
+
+        formatAsciiHexString(text, asciiHexText, textSize);
+        *inputTextP = asciiHexText;
+    } break;
+    case INPUT_ASCII85: {
+        char * ascii85Text;
+
+        MALLOCARRAY(ascii85Text, textSize + 5);
+        if (!ascii85Text)
+            pm_error("Unable to allocate memory for hex encoding of %u "
+                     "characters of text", textSize);
+
+        formatAscii85String(text, ascii85Text, textSize);
+        *inputTextP = ascii85Text;
+    } break;
     }
+
     pm_strfree(text);
 }
 
@@ -155,20 +449,23 @@ struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    unsigned int res;
-    float        fontsize;
-    const char * font;
-    float        stroke;
-    float        ascent;
-    float        descent;
-    float        leftmargin;
-    float        rightmargin;
-    float        topmargin;
-    float        bottommargin;
-    unsigned int pad;
-    unsigned int verbose;
-    unsigned int dump;
-    const char * text;
+    unsigned int  res;
+    float         fontsize;
+    const char *  font;
+    float         stroke;
+    float         ascent;
+    float         descent;
+    float         leftmargin;
+    float         rightmargin;
+    float         topmargin;
+    float         bottommargin;
+    unsigned int  pad;
+    unsigned int  verbose;
+    unsigned int  dump;
+    const char *  text;
+        /* Text to render, in Postscript format, either Ascii-hex
+           (e.g. <313233>) or Ascii-85 (e.g. <~aBc-~>)
+        */
 };
 
 
@@ -189,8 +486,9 @@ parseCommandLine(int argc, const char ** argv,
     unsigned int cropSpec, ascentSpec, descentSpec;
     unsigned int leftmarginSpec, rightmarginSpec;
     unsigned int topmarginSpec, bottommarginSpec;
+    unsigned int asciihexSpec, ascii85Spec;
 
-    MALLOCARRAY(option_def, 100);
+    MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENTRY */
     OPTENT3(0, "resolution",    OPT_UINT,
@@ -217,6 +515,10 @@ parseCommandLine(int argc, const char ** argv,
             NULL,                    &cropSpec,                 0);
     OPTENT3(0, "pad",           OPT_FLAG,
             NULL,                    &cmdlineP->pad,            0);
+    OPTENT3(0, "asciihex",      OPT_FLAG,
+            NULL,                    &asciihexSpec,             0);
+    OPTENT3(0, "ascii85",       OPT_FLAG,
+            NULL,                    &ascii85Spec,              0);
     OPTENT3(0, "verbose",       OPT_FLAG,
             NULL,                    &cmdlineP->verbose,        0);
     OPTENT3(0, "dump-ps",       OPT_FLAG,
@@ -233,8 +535,6 @@ parseCommandLine(int argc, const char ** argv,
     cmdlineP->leftmargin  = 0;
     cmdlineP->topmargin   = 0;
     cmdlineP->bottommargin = 0;
-    cropSpec       = FALSE;
-    cmdlineP->pad  = FALSE;
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
@@ -244,6 +544,8 @@ parseCommandLine(int argc, const char ** argv,
 
     validateFontName(cmdlineP->font);
 
+    if (cmdlineP->res <= 0)
+        pm_error("-resolution must be positive");
     if (cmdlineP->fontsize <= 0)
         pm_error("-fontsize must be positive");
     if (cmdlineP->ascent < 0)
@@ -259,7 +561,7 @@ parseCommandLine(int argc, const char ** argv,
     if (cmdlineP->bottommargin <0)
         pm_error("-bottommargin must not be negative");
 
-    if (cropSpec == TRUE) {
+    if (cropSpec) {
         if (ascentSpec || descentSpec ||
             leftmarginSpec || rightmarginSpec ||
             topmarginSpec || bottommarginSpec ||
@@ -275,8 +577,24 @@ parseCommandLine(int argc, const char ** argv,
              cmdlineP->leftmargin = cmdlineP->fontsize / 2;
     }
 
-    buildTextFromArgs(argc, argv, &cmdlineP->text);
+    {
+        enum InputFmt inputFmt;
+
+        if (asciihexSpec) {
+            if (ascii85Spec)
+                pm_error("You cannot specify both -asciihex and -ascii85");
+            else
+                inputFmt = INPUT_ASCIIHEX;
+        } else if (ascii85Spec)
+            inputFmt = INPUT_ASCII85;
+        else
+            inputFmt = INPUT_LITERAL;
+
+        if (argc-1 < 1)
+            pm_error("No text");
 
+        buildTextFromArgs(argc, argv, &cmdlineP->text, inputFmt);
+    }
     free(option_def);
 }
 
@@ -325,7 +643,7 @@ postscriptProgram(struct CmdlineInfo const cmdline) {
         "/FindFont {/%s findfont} def\n"
         "/fontsize %f def\n"
         "/pensize %f def\n"
-        "/textstring <%s> def\n"
+        "/textstring %s def\n"
         "/ascent %f def\n"
         "/descent %f def\n"
         "/leftmargin %f def\n"
@@ -386,6 +704,13 @@ postscriptProgram(struct CmdlineInfo const cmdline) {
     const char * retval;
     const char * psVariable;
 
+    /* According to Adobe, maximum line length in a Postscript program is
+       255 characters excluding the newline.  The following may generated a
+       line longer than that if 'cmdline.text' or 'cmdline.font' is long.
+       However, Ghostscript accepts much longer lines, so we don't worry
+       about that.
+    */
+
     pm_asprintf(&psVariable, psTemplate, cmdline.font,
                 cmdline.fontsize, cmdline.stroke, cmdline.text,
                 cmdline.ascent, cmdline.descent,
@@ -413,11 +738,8 @@ gsArgList(const char *       const outputFilename,
     const char ** retval;
     unsigned int argCt;  /* Number of arguments in 'retval' so far */
 
-    if (cmdline.res <= 0)
-         pm_error("Resolution (dpi) must be positive.");
-
-    if (cmdline.fontsize <= 0)
-         pm_error("Font size must be positive.");
+    assert(cmdline.res > 0);
+    assert(cmdline.fontsize > 0);
 
     MALLOCARRAY_NOFAIL(retval, maxArgCt+2);
 
diff --git a/generator/pgmcrater b/generator/pgmcrater
index c66f5576..6d81df39 100755
--- a/generator/pgmcrater
+++ b/generator/pgmcrater
@@ -36,6 +36,16 @@ exec perl -w -x -S -- "$0" "$@"
 use strict;
 
 use Getopt::Long;
+use IO::Handle;
+
+
+
+sub pm_message($) {
+    STDERR->print("pgmcrater: $_[0]\n");
+}
+
+
+
 
 sub doVersionHack($) {
     my ($argvR) = @_;
@@ -69,7 +79,7 @@ my $validOptions = GetOptions(
     'randomseed=i' => \my $randomseedOpt);
 
 if (!$validOptions) {
-    print STDERR "Invalid syntax\n";
+    pm_message("Invalid syntax");
     exit(100);
 }
 
diff --git a/generator/pgmnoise.c b/generator/pgmnoise.c
index 40d0e189..ea35956b 100644
--- a/generator/pgmnoise.c
+++ b/generator/pgmnoise.c
@@ -3,15 +3,21 @@
    Frank Neumann, October 1993
 *********************************************************************/
 
+#include <assert.h>
 #include "pm_c_util.h"
 #include "mallocvar.h"
+#include "nstring.h"
+#include "rand.h"
 #include "shhopt.h"
 #include "pgm.h"
-#include <assert.h>
+
+/* constants */
+static unsigned long int const ceil31bits = 0x7fffffffUL;
+static unsigned long int const ceil32bits = 0xffffffffUL;
 
 
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -20,13 +26,15 @@ struct cmdlineInfo {
     unsigned int maxval;
     unsigned int randomseed;
     unsigned int randomseedSpec;
+    unsigned int verbose;
 };
 
 
 
 static void
-parseCommandLine(int argc, const char ** const argv,
-                 struct cmdlineInfo * const cmdlineP) {
+parseCommandLine(int argc,
+                 const char **        const argv,
+                 struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that the file spec array we return is stored in the storage that
    was passed to us as the argv array.
@@ -45,6 +53,8 @@ parseCommandLine(int argc, const char ** const argv,
             &cmdlineP->randomseedSpec,      0);
     OPTENT3(0,   "maxval",       OPT_UINT,    &cmdlineP->maxval,
             &maxvalSpec,                    0);
+    OPTENT3(0,   "verbose",      OPT_FLAG,    NULL,
+            &cmdlineP->verbose,             0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
@@ -56,7 +66,7 @@ parseCommandLine(int argc, const char ** const argv,
 
     if (maxvalSpec) {
         if (cmdlineP->maxval > PGM_OVERALLMAXVAL)
-            pm_error("Maxval too large: %u.  Maximu is %u",
+            pm_error("Maxval too large: %u.  Maximum is %u",
                      cmdlineP->maxval, PGM_OVERALLMAXVAL);
         else if (cmdlineP->maxval == 0)
             pm_error("Maxval must not be zero");
@@ -68,16 +78,24 @@ parseCommandLine(int argc, const char ** const argv,
                  "Arguments are width and height of image, in pixels",
                  argc-1);
     else {
-        int const width  = atoi(argv[1]);
-        int const height = atoi(argv[2]);
-
-        if (width <= 0)
-            pm_error("Width must be positive, not %d", width);
+        const char * error; /* error message of pm_string_to_uint */
+        unsigned int width, height;
+
+        pm_string_to_uint(argv[1], &width, &error);
+        if (error)
+            pm_error("Width argument is not an unsigned integer.  %s",
+                     error);
+        else if (width == 0)
+            pm_error("Width argument is zero; must be positive");
         else
             cmdlineP->width = width;
 
-        if (height <= 0)
-            pm_error("Height must be positive, not %d", width);
+        pm_string_to_uint(argv[2], &height, &error);
+        if (error)
+            pm_error("Height argument is not an unsigned integer.  %s ",
+                     error);
+        else if (height == 0)
+            pm_error("Height argument is zero; must be positive");
         else
             cmdlineP->height = height;
     }
@@ -86,38 +104,43 @@ parseCommandLine(int argc, const char ** const argv,
 
 
 static unsigned int
-randPool(unsigned int const digits) {
+randPool(unsigned int       const nDigits,
+         struct pm_randSt * const randStP) {
 /*----------------------------------------------------------------------------
-  Draw 'digits' bits from pool of random bits.  If the number of random bits
-  in pool is insufficient, call rand() and add 31 bits to it.
+  Draw 'nDigits' bits from pool of random bits.  If the number of random bits
+  in pool is insufficient, call pm_rand() and add N bits to it.
+
+  N is 31 or 32.  In raw mode we use N = 32 regardless of the actual number of
+  available bits.  If there are only 31 available, we use zero for the MSB.
 
-  'digits' must be at most 16.
+  'nDigits' must be at most 16.
 
-  We assume that each call to rand() generates 31 bits, or RAND_MAX ==
-  2147483647.
+  We assume that each call to pm_rand() generates 31 or 32 bits, or
+  randStP->max == 2147483647 or 4294967295.
 
-  The underlying logic is flexible and endian-free.  The above conditions
-  can be relaxed.
+  The underlying logic is flexible and endian-free.  The above conditions can
+  be relaxed.
 -----------------------------------------------------------------------------*/
     static unsigned long int hold=0;  /* entropy pool */
     static unsigned int len=0;        /* number of valid bits in pool */
 
-    unsigned int const mask = (1 << digits) - 1;
-
+    unsigned int const mask = (1 << nDigits) - 1;
+    unsigned int const randbits = (randStP->max == ceil31bits) ? 31 : 32;
     unsigned int retval;
 
-    assert(RAND_MAX == 2147483647 && digits <= 16);
+    assert(randStP->max == ceil31bits || randStP->max == ceil32bits);
+    assert(nDigits <= 16);
 
     retval = hold;  /* initial value */
 
-    if (len > digits) { /* Enough bits in hold to satisfy request */
-        hold >>= digits;
-        len   -= digits;
-    } else {              /* Load another 31 bits into hold */
-        hold    = rand();
+    if (len > nDigits) { /* Enough bits in hold to satisfy request */
+        hold >>= nDigits;
+        len   -= nDigits;
+    } else {            /* Load another 31 or 32 bits into hold */
+        hold    = pm_rand(randStP);
         retval |= (hold << len);
-        hold >>=  (digits - len);
-        len = 31 - digits + len;
+        hold >>=  (nDigits - len);
+        len = randbits - nDigits + len;
     }
     return (retval & mask);
 }
@@ -125,36 +148,61 @@ randPool(unsigned int const digits) {
 
 
 static void
-pgmnoise(FILE *       const ofP,
-         unsigned int const cols,
-         unsigned int const rows,
-         gray         const maxval) {
+reportVerbose(struct pm_randSt * const randStP,
+              gray               const maxval,
+              bool               const usingPool)  {
+
+    pm_message("random seed: %u", randStP->seed);
+    pm_message("random max: %u maxval: %u", randStP->max, maxval);
+    pm_message("method: %s", usingPool ? "pool" : "modulo");
+}
+
 
-    bool const usingPool = !(RAND_MAX==2147483647 && (maxval & (maxval+1)));
+
+static void
+pgmnoise(FILE *             const ofP,
+         unsigned int       const cols,
+         unsigned int       const rows,
+         gray               const maxval,
+         bool               const verbose,
+         struct pm_randSt * const randStP) {
+
+    bool const usingPool =
+        (randStP->max==ceil31bits || randStP->max==ceil32bits) &&
+        !(maxval & (maxval+1));
     unsigned int const bitLen = pm_maxvaltobits(maxval);
 
     unsigned int row;
     gray * destrow;
 
     /* If maxval is 2^n-1, we draw exactly n bits from the pool.
-       Otherwise call rand() and determine gray value by modulo.
+       Otherwise call pm_rand() and determine gray value by modulo.
 
-       In the latter case, there is a miniscule skew toward 0 (=black)
+       In the latter case, there is a minuscule skew toward 0 (=black)
        because smaller numbers are produced more frequently by modulo.
        Thus we employ the pool method only when it is certain that no
-       skew will ensue.
+       skew will result.
 
        To illustrate the point, consider converting the outcome of one
        roll of a fair, six-sided die to 5 values (0 to 4) by N % 5.  The
-       probability for values 1, 2, 3, 4 are 1/6, but 0 alone is 2/6.
+       probability for values 1, 2, 3, 4 is 1/6, but 0 alone is 2/6.
        Average is 10/6 or 1.6667, compared to 2.0 from an ideal
        generator which produces exactly 5 values.  With two dice
        average improves to 70/36 or 1.9444.
 
        The more (distinct) dice we roll, or the more binary digits we
        draw, the smaller the skew.
+
+       The pool method is economical.  But there is an additional merit:
+       No bits are lost this way.  This gives us a means to check the
+       integrity of the random number generator.
+
+       - Akira Urushibata, March 2021
     */
 
+    if (verbose)
+        reportVerbose(randStP, maxval, usingPool);
+
     destrow = pgm_allocrow(cols);
 
     pgm_writepgminit(ofP, cols, rows, maxval, 0);
@@ -163,12 +211,11 @@ pgmnoise(FILE *       const ofP,
         if (usingPool) {
             unsigned int col;
             for (col = 0; col < cols; ++col)
-                destrow[col] = randPool(bitLen);
-        }
-        else {
+                destrow[col] = randPool(bitLen, randStP);
+        } else {
             unsigned int col;
             for (col = 0; col < cols; ++col)
-                destrow[col] = rand() % (maxval + 1);
+                destrow[col] = pm_rand(randStP) % (maxval + 1);
         }
         pgm_writepgmrow(ofP, destrow, cols, maxval, 0);
     }
@@ -182,18 +229,22 @@ int
 main(int          argc,
      const char * argv[]) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
+    struct pm_randSt randSt;
 
     pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
-    srand(cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed());
+    pm_randinit(&randSt);
+    pm_srand2(&randSt, cmdline.randomseedSpec, cmdline.randomseed);
 
-    pgmnoise(stdout, cmdline.width, cmdline.height, cmdline.maxval);
+    pgmnoise(stdout, cmdline.width, cmdline.height, cmdline.maxval,
+             cmdline.verbose, &randSt);
+
+    pm_randterm(&randSt);
 
     return 0;
 }
 
 
-
diff --git a/generator/ppmforge.c b/generator/ppmforge.c
index 390180e3..47f9390e 100644
--- a/generator/ppmforge.c
+++ b/generator/ppmforge.c
@@ -34,12 +34,14 @@
 #define _XOPEN_SOURCE 500  /* get M_PI in math.h */
 
 #include <math.h>
+#include <float.h>
 #include <assert.h>
 
 #include "pm_c_util.h"
-#include "ppm.h"
 #include "mallocvar.h"
+#include "rand.h"
 #include "shhopt.h"
+#include "ppm.h"
 
 static double const hugeVal = 1e50;
 
@@ -49,36 +51,25 @@ static double const hugeVal = 1e50;
 #define Real(v, x, y)  v[1 + (((x) * meshsize) + (y)) * 2]
 #define Imag(v, x, y)  v[2 + (((x) * meshsize) + (y)) * 2]
 
-/* Co-ordinate indices within arrays. */
+/* Coordinate indices within arrays. */
 
 typedef struct {
     double x;
     double y;
-    double z; 
-} vector;
+    double z;
+} Vector;
 
 /* Definition for obtaining random numbers. */
 
-#define nrand 4               /* Gauss() sample count */
-#define Cast(low, high) ((low)+(((high)-(low)) * ((rand() & 0x7FFF) / arand)))
-
-/* prototypes */
-static void fourn ARGS((float data[], int nn[], int ndim, int isign));
-static void initgauss ARGS((unsigned int seed));
-static double gauss ARGS((void));
-static void spectralsynth ARGS((float **x, unsigned int n, double h));
-static void temprgb ARGS((double temp, double *r, double *g, double *b));
-static void etoile ARGS((pixel *pix));
 /*  Local variables  */
 
-static double arand, gaussadd, gaussfac; /* Gaussian random parameters */
 static double fracdim;            /* Fractal dimension */
 static double powscale;           /* Power law scaling exponent */
 static int meshsize = 256;        /* FFT mesh size */
 static double inclangle, hourangle;   /* Star position relative to planet */
 static bool inclspec = FALSE;      /* No inclination specified yet */
 static bool hourspec = FALSE;      /* No hour specified yet */
-static double icelevel;           /* Ice cap theshold */
+static double icelevel;           /* Ice cap threshold */
 static double glaciers;           /* Glacier level */
 static int starfraction;          /* Star fraction */
 static int starcolor;            /* Star color saturation */
@@ -111,11 +102,11 @@ static void
 parseCommandLine(int argc, const char **argv,
                  struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
-  Convert program invocation arguments (argc,argv) into a format the 
+  Convert program invocation arguments (argc,argv) into a format the
   program can use easily, struct cmdlineInfo.  Validate arguments along
   the way and exit program with message if invalid.
 
-  Note that some string information we return as *cmdlineP is in the storage 
+  Note that some string information we return as *cmdlineP is in the storage
   argv[] points to.
 -----------------------------------------------------------------------------*/
     optEntry * option_def;
@@ -179,6 +170,11 @@ parseCommandLine(int argc, const char **argv,
         if (cmdlineP->dimension <= 0.0)
             pm_error("-dimension must be greater than zero.  "
                      "You specified %f", cmdlineP->dimension);
+        else if (cmdlineP->dimension > 5.0 + FLT_EPSILON)
+            pm_error("-dimension must not be greater than 5.  "
+                     "Results are not interesting with higher numbers, so "
+                     "we assume it is a mistake.  "
+                     "You specified %f", cmdlineP->dimension);
     } else
         cmdlineP->dimension = cmdlineP->clouds ? 2.15 : 2.4;
 
@@ -243,9 +239,16 @@ parseCommandLine(int argc, const char **argv,
 }
 
 
-/*  FOURN  --  Multi-dimensional fast Fourier transform
 
-    Called with arguments:
+static void
+fourn(double *    const data,
+      const int * const nn,
+      int         const ndim,
+      int         const isign) {
+/*----------------------------------------------------------------------------
+    Multi-dimensional fast Fourier transform
+
+    Arguments:
 
        data       A  one-dimensional  array  of  floats  (NOTE!!!   NOT
               DOUBLES!!), indexed from one (NOTE!!!   NOT  ZERO!!),
@@ -265,16 +268,11 @@ parseCommandLine(int argc, const char **argv,
 
         This  function  is essentially as given in Press et al., "Numerical
         Recipes In C", Section 12.11, pp.  467-470.
-*/
-
-static void fourn(data, nn, ndim, isign)
-    float data[];
-    int nn[], ndim, isign;
-{
-    register int i1, i2, i3;
+-----------------------------------------------------------------------------*/
+    int i1, i2, i3;
     int i2rev, i3rev, ip1, ip2, ip3, ifp1, ifp2;
     int ibit, idim, k1, k2, n, nprev, nrem, ntot;
-    float tempi, tempr;
+    double tempi, tempr;
     double theta, wi, wpi, wpr, wr, wtemp;
 
 #define SWAP(a,b) tempr=(a); (a) = (b); (b) = tempr
@@ -339,61 +337,101 @@ static void fourn(data, nn, ndim, isign)
 }
 #undef SWAP
 
-/*  INITGAUSS  --  Initialize random number generators.  As given in
-           Peitgen & Saupe, page 77. */
 
-static void initgauss(seed)
-    unsigned int seed;
-{
+struct Gauss {
+    struct pm_randSt randSt;
+    unsigned int     nrand;          /* Gauss() sample count */
+    double           arand;
+    double           gaussadd;
+    double           gaussfac;
+};
+
+
+
+static void
+initgauss(struct Gauss * const gaussP,
+          unsigned int   const seed) {
+/*----------------------------------------------------------------------------
+  Initialize random number generators.
+
+  As given in Peitgen & Saupe, page 77.
+-----------------------------------------------------------------------------*/
+    gaussP->nrand = 4;
+
     /* Range of random generator */
-    arand = pow(2.0, 15.0) - 1.0;
-    gaussadd = sqrt(3.0 * nrand);
-    gaussfac = 2 * gaussadd / (nrand * arand);
-    srand(seed);
+    gaussP->arand    = pow(2.0, 15.0) - 1.0;
+    gaussP->gaussadd = sqrt(3.0 * gaussP->nrand);
+    gaussP->gaussfac = 2 * gaussP->gaussadd / (gaussP->nrand * gaussP->arand);
+
+    pm_randinit(&gaussP->randSt);
+    pm_srand(&gaussP->randSt, seed);
 }
 
-/*  GAUSS  --  Return a Gaussian random number.  As given in Peitgen
-           & Saupe, page 77. */
 
-static double gauss()
-{
-    int i;
-    double sum = 0.0;
 
-    for (i = 1; i <= nrand; i++) {
-        sum += (rand() & 0x7FFF);
+static double
+gauss(struct Gauss * const gaussP) {
+/*----------------------------------------------------------------------------
+  A Gaussian random number.
+
+  As given in Peitgen & Saupe, page 77.
+-----------------------------------------------------------------------------*/
+    unsigned int i;
+    double sum;
+
+    for (i = 1, sum = 0.0; i <= gaussP->nrand; ++i) {
+        sum += (pm_rand(&gaussP->randSt) & 0x7FFF);
     }
-    return gaussfac * sum - gaussadd;
+    return gaussP->gaussfac * sum - gaussP->gaussadd;
 }
 
-/*  SPECTRALSYNTH  --  Spectrally  synthesized  fractal  motion in two
-               dimensions.  This algorithm is given under  the
-               name   SpectralSynthesisFM2D  on  page  108  of
-               Peitgen & Saupe. */
-
-static void spectralsynth(x, n, h)
-    float **x;
-    unsigned int n;
-    double h;
-{
-    unsigned bl;
+
+
+static double
+cast(double         const low,
+     double         const high,
+     struct Gauss * const gaussP) {
+
+    return
+        low +
+        ((high-low) * ((pm_rand(&gaussP->randSt) & 0x7FFF) / gaussP->arand));
+
+}
+
+
+
+static void
+spectralsynth(double **      const aP,
+              unsigned int   const n,
+              double         const h,
+              struct Gauss * const gaussP) {
+/*----------------------------------------------------------------------------
+  Spectrally synthesized fractal motion in two dimensions.
+
+  This algorithm is given under the name SpectralSynthesisFM2D on page 108 of
+  Peitgen & Saupe.
+-----------------------------------------------------------------------------*/
+    unsigned int const bl = ((((unsigned long) n) * n) + 1) * 2;
+
     int i, j, i0, j0, nsize[3];
     double rad, phase, rcos, rsin;
-    float *a;
+    double * a;
 
-    bl = ((((unsigned long) n) * n) + 1) * 2 * sizeof(float);
-    a = (float *) calloc(bl, 1);
-    if (a == (float *) 0) {
-        pm_error("Cannot allocate %d x %d result array (% d bytes).",
+    MALLOCARRAY(a, bl);
+
+    if (!a) {
+        pm_error("Cannot allocate %u x %u result array (%u doubles).",
                  n, n, bl);
     }
-    *x = a;
+    for (i = 0; i < bl; ++i)
+        a[i] = 0.0;  /* initial value */
 
     for (i = 0; i <= n / 2; i++) {
         for (j = 0; j <= n / 2; j++) {
-            phase = 2 * M_PI * ((rand() & 0x7FFF) / arand);
+            phase = 2 * M_PI * ((pm_rand(&gaussP->randSt) & 0x7FFF) /
+                                gaussP->arand);
             if (i != 0 || j != 0) {
-                rad = pow((double) (i * i + j * j), -(h + 1) / 2) * gauss();
+                rad = pow((double) (i*i + j*j), -(h + 1) / 2) * gauss(gaussP);
             } else {
                 rad = 0;
             }
@@ -412,8 +450,9 @@ static void spectralsynth(x, n, h)
     Imag(a, n / 2, n / 2) = 0;
     for (i = 1; i <= n / 2 - 1; i++) {
         for (j = 1; j <= n / 2 - 1; j++) {
-            phase = 2 * M_PI * ((rand() & 0x7FFF) / arand);
-            rad = pow((double) (i * i + j * j), -(h + 1) / 2) * gauss();
+            phase = 2 * M_PI * ((pm_rand(&gaussP->randSt) & 0x7FFF) /
+                                gaussP->arand);
+            rad = pow((double) (i * i + j * j), -(h + 1) / 2) * gauss(gaussP);
             rcos = rad * cos(phase);
             rsin = rad * sin(phase);
             Real(a, i, n - j) = rcos;
@@ -426,24 +465,26 @@ static void spectralsynth(x, n, h)
     nsize[0] = 0;
     nsize[1] = nsize[2] = n;          /* Dimension of frequency domain array */
     fourn(a, nsize, 2, -1);       /* Take inverse 2D Fourier transform */
-}
 
+    *aP = a;
+}
 
 
-/*  TEMPRGB  --  Calculate the relative R, G, and B components  for  a
-         black  body  emitting  light  at a given temperature.
-         The Planck radiation equation is solved directly  for
-         the R, G, and B wavelengths defined for the CIE  1931
-         Standard    Colorimetric    Observer.    The   color
-         temperature is specified in degrees Kelvin. */
 
-static void temprgb(temp, r, g, b)
-    double temp;
-    double *r, *g, *b;
-{
-    double c1 = 3.7403e10,
-        c2 = 14384.0,
-        er, eg, eb, es;
+static void
+temprgb(double   const temp,
+        double * const r,
+        double * const g,
+        double * const b) {
+/*----------------------------------------------------------------------------
+  Calculate the relative R, G, and B components for a black body emitting
+  light at a given temperature.  We solve the Planck radiation equation
+  directly for the R, G, and B wavelengths defined for the CIE 1931 Standard
+  Colorimetric Observer.  The color temperature is specified in kelvins.
+-----------------------------------------------------------------------------*/
+    double const c1 = 3.7403e10;
+    double const c2 = 14384.0;
+    double er, eg, eb, es;
 
 /* Lambda is the wavelength in microns: 5500 angstroms is 0.55 microns. */
 
@@ -462,23 +503,25 @@ static void temprgb(temp, r, g, b)
         *b = eb * es;
 }
 
-/*  ETOILE  --  Set a pixel in the starry sky.  */
-
-static void etoile(pix)
-    pixel *pix;
-{
-    if ((rand() % 1000) < starfraction) {
-#define StarQuality 0.5       /* Brightness distribution exponent */
-#define StarIntensity   8         /* Brightness scale factor */
-#define StarTintExp 0.5       /* Tint distribution exponent */
-        double v = StarIntensity * pow(1 / (1 - Cast(0, 0.9999)),
-                                       (double) StarQuality),
-            temp,
-            r, g, b;
-
-        if (v > 255) {
-            v = 255;
-        }
+
+
+static void
+etoile(pixel *        const pix,
+       struct Gauss * const gaussP) {
+/*----------------------------------------------------------------------------
+    Set a pixel in the starry sky.
+-----------------------------------------------------------------------------*/
+    if ((pm_rand(&gaussP->randSt) % 1000) < starfraction) {
+        double const starQuality   = 0.5;
+            /* Brightness distribution exponent */
+        double const starIntensity = 8;
+            /* Brightness scale factor */
+        double const starTintExp = 0.5;
+            /* Tint distribution exponent */
+        double const v =
+            MIN(255.0,
+                starIntensity * pow(1 / (1 - cast(0, 0.9999, gaussP)),
+                                    (double) starQuality));
 
         /* We make a special case for star color  of zero in order to
            prevent  floating  point  roundoff  which  would  otherwise
@@ -487,14 +530,18 @@ static void etoile(pix)
            256 shades in the image. */
 
         if (starcolor == 0) {
-            int vi = v;
+            pixval const vi = v;
 
             PPM_ASSIGN(*pix, vi, vi, vi);
         } else {
+            double temp;
+            double r, g, b;
+
             temp = 5500 + starcolor *
-                pow(1 / (1 - Cast(0, 0.9999)), StarTintExp) *
-                ((rand() & 7) ? -1 : 1);
-            /* Constrain temperature to a reasonable value: >= 2600K 
+                pow(1 / (1 - cast(0, 0.9999, gaussP)), starTintExp) *
+                ((pm_rand(&gaussP->randSt) & 7) ? -1 : 1);
+
+            /* Constrain temperature to a reasonable value: >= 2600K
                (S Cephei/R Andromedae), <= 28,000 (Spica). */
             temp = MAX(2600, MIN(28000, temp));
             temprgb(temp, &r, &g, &b);
@@ -529,9 +576,9 @@ atSat(double const x,
 
 
 static unsigned char *
-makeCp(float *      const a,
-       unsigned int const n,
-       pixval       const maxval) {
+makeCp(const double * const a,
+       unsigned int   const n,
+       pixval         const maxval) {
 
     /* Prescale the grid points into intensities. */
 
@@ -544,7 +591,7 @@ makeCp(float *      const a,
     if (cp == NULL)
         pm_error("Unable to allocate %u bytes for cp array", n);
 
-    ap = cp;
+    ap = cp;  /* initial value */
     {
         unsigned int i;
         for (i = 0; i < n; i++) {
@@ -560,16 +607,17 @@ makeCp(float *      const a,
 
 static void
 createPlanetStuff(bool             const clouds,
-                  float *          const a,
+                  const double *   const a,
                   unsigned int     const n,
                   double **        const uP,
                   double **        const u1P,
                   unsigned int **  const bxfP,
                   unsigned int **  const bxcP,
                   unsigned char ** const cpP,
-                  vector *         const sunvecP,
+                  Vector *         const sunvecP,
                   unsigned int     const cols,
-                  pixval           const maxval) {
+                  pixval           const maxval,
+                  struct Gauss *   const gaussP) {
 
     double *u, *u1;
     unsigned int *bxf, *bxc;
@@ -579,8 +627,8 @@ createPlanetStuff(bool             const clouds,
 
     /* Compute incident light direction vector. */
 
-    shang = hourspec ? hourangle : Cast(0, 2 * M_PI);
-    siang = inclspec ? inclangle : Cast(-M_PI * 0.12, M_PI * 0.12);
+    shang = hourspec ? hourangle : cast(0, 2 * M_PI, gaussP);
+    siang = inclspec ? inclangle : cast(-M_PI * 0.12, M_PI * 0.12, gaussP);
 
     sunvecP->x = sin(shang) * cos(siang);
     sunvecP->y = sin(siang);
@@ -588,7 +636,7 @@ createPlanetStuff(bool             const clouds,
 
     /* Allow only 25% of random pictures to be crescents */
 
-    if (!hourspec && ((rand() % 100) < 75)) {
+    if (!hourspec && ((pm_rand(&gaussP->randSt) % 100) < 75)) {
         flipped = (sunvecP->z < 0);
         sunvecP->z = fabs(sunvecP->z);
     } else
@@ -614,23 +662,23 @@ createPlanetStuff(bool             const clouds,
        (N.b. the pictures would undoubtedly look better when generated
        with small grids if  a  more  well-behaved  interpolation  were
        used.)
-       
+
        Also compute the line-level interpolation parameters that
-       caller will need every time around his inner loop.  
+       caller will need every time around his inner loop.
     */
 
     MALLOCARRAY(u,   cols);
     MALLOCARRAY(u1,  cols);
     MALLOCARRAY(bxf, cols);
     MALLOCARRAY(bxc, cols);
-    
-    if (u == NULL || u1 == NULL || bxf == NULL || bxc == NULL) 
-        pm_error("Cannot allocate %d element interpolation tables.", cols);
+
+    if (u == NULL || u1 == NULL || bxf == NULL || bxc == NULL)
+        pm_error("Cannot allocate %u element interpolation tables.", cols);
     {
         unsigned int j;
-        for (j = 0; j < cols; j++) {
+        for (j = 0; j < cols; ++j) {
             double const bx = (n - 1) * uprj(j, cols);
-            
+
             bxf[j] = floor(bx);
             bxc[j] = MIN(bxf[j] + 1, n - 1);
             u[j] = bx - bxf[j];
@@ -645,17 +693,18 @@ createPlanetStuff(bool             const clouds,
 
 
 static void
-generateStarrySkyRow(pixel *      const pixels, 
-                     unsigned int const cols) {
+generateStarrySkyRow(pixel *        const pixels,
+                     unsigned int   const cols,
+                     struct Gauss * const gaussP) {
 /*----------------------------------------------------------------------------
   Generate a starry sky.  Note  that no FFT is performed;
   the output is  generated  directly  from  a  power  law
-  mapping  of  a  pseudorandom sequence into intensities. 
+  mapping  of  a  pseudorandom sequence into intensities.
 -----------------------------------------------------------------------------*/
     unsigned int j;
-    
-    for (j = 0; j < cols; j++)
-        etoile(pixels + j);
+
+    for (j = 0; j < cols; ++j)
+        etoile(pixels + j, gaussP);
 }
 
 
@@ -681,7 +730,7 @@ generateCloudRow(pixel *         const pixels,
     for (col = 0; col < cols; ++col) {
         double r;
         pixval w;
-        
+
         r = 0.0;  /* initial value */
         /* Note that where t1 and t are zero, the cp[] element
            referenced below does not exist.
@@ -692,9 +741,9 @@ generateCloudRow(pixel *         const pixels,
         if (t > 0.0)
             r += t * u1[col] * cp[byc + bxf[col]] +
                 t * u[col]  * cp[byc + bxc[col]];
-        
+
         w = (r > 127.0) ? (maxval * ((r - 127.0) / 128.0)) : 0;
-        
+
         PPM_ASSIGN(pixels[col], w, w, maxval);
     }
 }
@@ -747,11 +796,11 @@ makeLand(int *  const irP,
     };
 
     unsigned int const ix = ((r - 128) * (ARRAY_SIZE(pgnd) - 1)) / 127;
-    
+
     *irP = pgnd[ix][0];
     *igP = pgnd[ix][1];
     *ibP = pgnd[ix][2];
-} 
+}
 
 
 
@@ -781,9 +830,9 @@ addIce(int *  const irP,
        pixval const maxval) {
 
     /* Generate polar ice caps. */
-    
+
     double const icet = pow(fabs(sin(azimuth)), 1.0 / icelevel) - 0.5;
-    double const ice = MAX(0.0, 
+    double const ice = MAX(0.0,
                            (icet + glaciers * MAX(-0.5, (r - 128) / 128.0)));
     if  (ice > 0.125) {
         *irP = maxval;
@@ -802,11 +851,11 @@ limbDarken(int *          const irP,
            unsigned int   const row,
            unsigned int   const cols,
            unsigned int   const rows,
-           vector         const sunvec,
+           Vector         const sunvec,
            pixval         const maxval) {
 
     /* With Gcc 2.95.3 compiler optimization level > 1, I have seen this
-       function confuse all the variables and ultimately generate a 
+       function confuse all the variables and ultimately generate a
        completely black image.  Adding an extra reference to 'rows' seems
        to put things back in order, and the assert() below does that.
        Take it out, and the problem comes back!  04.02.21.
@@ -828,9 +877,9 @@ limbDarken(int *          const irP,
     double const dxsq = dx * dx;
 
     double const ds = MIN(1.0, sqrt(dxsq + dysq));
-    
+
     /* Calculate atmospheric absorption based on the thickness of
-       atmosphere traversed by light on its way to the surface.  
+       atmosphere traversed by light on its way to the surface.
     */
     double const dsq = ds * ds;
     double const dsat = atSatFac * ((sqrt(atthick * atthick - dsq) -
@@ -848,7 +897,7 @@ limbDarken(int *          const irP,
         double const svx = sunvec.x;
         double const svy = sunvec.y * dy;
         double const svz = sunvec.z * sqomdysq;
-        double const di = 
+        double const di =
             MAX(0, MIN(1.0, svx * dx + svy + svz * sqrt(1.0 - dxsq)));
         double const inx = PlanetAmbient * 1.0 + (1.0 - PlanetAmbient) * di;
 
@@ -874,8 +923,9 @@ generatePlanetRow(pixel *         const pixelrow,
                   unsigned int *  const bxf,
                   int             const byc,
                   int             const byf,
-                  vector          const sunvec,
-                  pixval          const maxval) {
+                  Vector          const sunvec,
+                  pixval          const maxval,
+                  struct Gauss *  const gaussP) {
 
     unsigned int const StarClose = 2;
 
@@ -892,9 +942,9 @@ generatePlanetRow(pixel *         const pixelrow,
         int ir, ig, ib;
 
         r = 0.0;   /* initial value */
-        
+
         /* Note that where t1 and t are zero, the cp[] element
-           referenced below does not exist.  
+           referenced below does not exist.
         */
         if (t1 > 0.0)
             r += t1 * u1[col] * cp[byf + bxf[col]] +
@@ -903,9 +953,9 @@ generatePlanetRow(pixel *         const pixelrow,
             r += t * u1[col] * cp[byc + bxf[col]] +
                 t * u[col]  * cp[byc + bxc[col]];
 
-        if (r >= 128) 
+        if (r >= 128)
             makeLand(&ir, &ig, &ib, r);
-        else 
+        else
             makeWater(&ir, &ig, &ib, r, maxval);
 
         addIce(&ir, &ig, &ib, r, azimuth, icelevel, glaciers, maxval);
@@ -918,24 +968,25 @@ generatePlanetRow(pixel *         const pixelrow,
     /* Left stars */
 
     for (col = 0; (int)col < (int)(cols/2 - (lcos + StarClose)); ++col)
-        etoile(&pixelrow[col]);
+        etoile(&pixelrow[col], gaussP);
 
     /* Right stars */
 
     for (col = cols/2 + (lcos + StarClose); col < cols; ++col)
-        etoile(&pixelrow[col]);
+        etoile(&pixelrow[col], gaussP);
 }
 
 
 
-static void 
-genplanet(bool         const stars,
-          bool         const clouds,
-          float *      const a, 
-          unsigned int const cols,
-          unsigned int const rows,
-          unsigned int const n,
-          unsigned int const rseed) {
+static void
+genplanet(bool           const stars,
+          bool           const clouds,
+          const double * const a,
+          unsigned int   const cols,
+          unsigned int   const rows,
+          unsigned int   const n,
+          unsigned int   const rseed,
+          struct Gauss * const gaussP) {
 /*----------------------------------------------------------------------------
   Generate planet from elevation array.
 
@@ -950,28 +1001,28 @@ genplanet(bool         const stars,
     pixel *pixelrow;
     unsigned int row;
 
-    vector sunvec;
+    Vector sunvec;
 
     ppm_writeppminit(stdout, cols, rows, maxval, FALSE);
 
     if (stars) {
         pm_message("night: -seed %d -stars %d -saturation %d.",
                    rseed, starfraction, starcolor);
-        cp = NULL; 
+        cp = NULL;
         u = NULL; u1 = NULL;
         bxf = NULL; bxc = NULL;
     } else {
         pm_message("%s: -seed %d -dimension %.2f -power %.2f -mesh %d",
                    clouds ? "clouds" : "planet",
                    rseed, fracdim, powscale, meshsize);
-        createPlanetStuff(clouds, a, n, &u, &u1, &bxf, &bxc, &cp, &sunvec, 
-                          cols, maxval);
+        createPlanetStuff(clouds, a, n, &u, &u1, &bxf, &bxc, &cp, &sunvec,
+                          cols, maxval, gaussP);
     }
 
     pixelrow = ppm_allocrow(cols);
     for (row = 0; row < rows; ++row) {
         if (stars)
-            generateStarrySkyRow(pixelrow, cols);
+            generateStarrySkyRow(pixelrow, cols, gaussP);
         else {
             double const by = (n - 1) * uprj(row, rows);
             int    const byf = floor(by) * n;
@@ -983,11 +1034,12 @@ genplanet(bool         const stars,
                 generateCloudRow(pixelrow, cols,
                                  t, t1, u, u1, cp, bxc, bxf, byc, byf,
                                  maxval);
-            else 
+            else
                 generatePlanetRow(pixelrow, row, rows, cols,
                                   t, t1, u, u1, cp, bxc, bxf, byc, byf,
                                   sunvec,
-                                  maxval);
+                                  maxval,
+                                  gaussP);
         }
         ppm_writeppmrow(stdout, pixelrow, cols, maxval, FALSE);
     }
@@ -1004,12 +1056,12 @@ genplanet(bool         const stars,
 
 
 static void
-applyPowerLawScaling(float * const a,
-                     int     const meshsize,
-                     double  const powscale) {
+applyPowerLawScaling(double * const a,
+                     int      const meshsize,
+                     double   const powscale) {
 
     /* Apply power law scaling if non-unity scale is requested. */
-    
+
     if (powscale != 1.0) {
         unsigned int i;
         for (i = 0; i < meshsize; i++) {
@@ -1017,7 +1069,7 @@ applyPowerLawScaling(float * const a,
             for (j = 0; j < meshsize; j++) {
                 double const r = Real(a, i, j);
                 if (r > 0)
-                    Real(a, i, j) = pow(r, powscale);
+                    Real(a, i, j) = MIN(hugeVal, pow(r, powscale));
             }
         }
     }
@@ -1026,11 +1078,11 @@ applyPowerLawScaling(float * const a,
 
 
 static void
-computeExtremeReal(const float * const a,
-                   int           const meshsize,
-                   double *      const rminP,
-                   double *      const rmaxP) {
-    
+computeExtremeReal(const double * const a,
+                   int            const meshsize,
+                   double *       const rminP,
+                   double *       const rmaxP) {
+
     /* Compute extrema for autoscaling. */
 
     double rmin, rmax;
@@ -1043,7 +1095,7 @@ computeExtremeReal(const float * const a,
         unsigned int j;
         for (j = 0; j < meshsize; j++) {
             double r = Real(a, i, j);
-            
+
             rmin = MIN(rmin, r);
             rmax = MAX(rmax, r);
         }
@@ -1055,8 +1107,8 @@ computeExtremeReal(const float * const a,
 
 
 static void
-replaceWithSpread(float * const a,
-                  int     const meshsize) {
+replaceWithSpread(double * const a,
+                  int      const meshsize) {
 /*----------------------------------------------------------------------------
   Replace the real part of each element of the 'a' array with a
   measure of how far the real is from the middle; sort of a standard
@@ -1090,28 +1142,29 @@ planet(unsigned int const cols,
 /*----------------------------------------------------------------------------
    Make a planet.
 -----------------------------------------------------------------------------*/
-    float * a;
+    double * a;
     bool error;
+    struct Gauss gauss;
+
+    initgauss(&gauss, rseed);
 
-    initgauss(rseed);
-    
     if (stars) {
         a = NULL;
         error = FALSE;
     } else {
-        spectralsynth(&a, meshsize, 3.0 - fracdim);
-        if (a == NULL) {
+        spectralsynth(&a, meshsize, 3.0 - fracdim, &gauss);
+        if (!a) {
             error = TRUE;
         } else {
             applyPowerLawScaling(a, meshsize, powscale);
-                
+
             replaceWithSpread(a, meshsize);
 
             error = FALSE;
         }
     }
     if (!error)
-        genplanet(stars, clouds, a, cols, rows, meshsize, rseed);
+        genplanet(stars, clouds, a, cols, rows, meshsize, rseed, &gauss);
 
     if (a != NULL)
         free(a);
@@ -1121,7 +1174,7 @@ planet(unsigned int const cols,
 
 
 
-int 
+int
 main(int argc, const char ** argv) {
 
     struct CmdlineInfo cmdline;
@@ -1147,13 +1200,16 @@ main(int argc, const char ** argv) {
 
     /* Force  screen to be at least  as wide as it is high.  Long,
        skinny screens  cause  crashes  because  picture  width  is
-       calculated based on height.  
+       calculated based on height.
     */
 
     cols = (MAX(cmdline.height, cmdline.width) + 1) & (~1);
     rows = cmdline.height;
 
-    success = planet(cols, rows, cmdline.night, cmdline.clouds, cmdline.seed);
+    success = planet(cols, rows, cmdline.night,
+                     cmdline.clouds, cmdline.seed);
 
     exit(success ? 0 : 1);
 }
+
+
diff --git a/generator/ppmmake.c b/generator/ppmmake.c
index 2d4bbca8..b1de7b52 100644
--- a/generator/ppmmake.c
+++ b/generator/ppmmake.c
@@ -31,11 +31,11 @@ static void
 parseCommandLine(int argc, char ** argv,
                  struct cmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
-  Convert program invocation arguments (argc,argv) into a format the 
+  Convert program invocation arguments (argc,argv) into a format the
   program can use easily, struct cmdlineInfo.  Validate arguments along
   the way and exit program with message if invalid.
 
-  Note that some string information we return as *cmdlineP is in the storage 
+  Note that some string information we return as *cmdlineP is in the storage
   argv[] points to.
 -----------------------------------------------------------------------------*/
     optEntry * option_def;
@@ -46,7 +46,7 @@ parseCommandLine(int argc, char ** argv,
     unsigned int maxvalSpec;
     unsigned int option_def_index;
 
-    MALLOCARRAY(option_def, 100);
+    MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENTRY */
     OPTENT3(0,   "maxval",    OPT_UINT, &cmdlineP->maxval, &maxvalSpec,    0);
diff --git a/generator/ppmpat.c b/generator/ppmpat.c
index 908c200f..170bfc58 100644
--- a/generator/ppmpat.c
+++ b/generator/ppmpat.c
@@ -14,7 +14,6 @@
 #define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
                            /* get M_PI in math.h */
 #define _BSD_SOURCE  /* Make sure strdup() is in <string.h> */
-#define SPIROGRAPHS 0   /* Spirograph to be added soon */
 
 #include <assert.h>
 #include <math.h>
@@ -23,8 +22,9 @@
 
 #include "pm_c_util.h"
 #include "mallocvar.h"
-#include "shhopt.h"
 #include "nstring.h"
+#include "rand.h"
+#include "shhopt.h"
 #include "ppm.h"
 #include "ppmdraw.h"
 
@@ -39,12 +39,10 @@ typedef enum {
     PAT_POLES,
     PAT_SQUIG,
     PAT_CAMO,
-    PAT_ANTICAMO,
-    PAT_SPIRO1,
-    PAT_SPIRO2,
-    PAT_SPIRO3
+    PAT_ANTICAMO
 } Pattern;
 
+
 typedef struct {
 /*----------------------------------------------------------------------------
    An ordered list of colors with a cursor.
@@ -60,16 +58,79 @@ struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    Pattern      basePattern;
-    unsigned int width;
-    unsigned int height;
-    unsigned int colorSpec;
-    ColorTable   colorTable;
-    unsigned int randomseed;
-    unsigned int randomseedSpec;
+    Pattern         basePattern;
+    unsigned int    width;
+    unsigned int    height;
+    unsigned int    colorSpec;
+    ColorTable      colorTable;
+    unsigned int    randomseed;
+    unsigned int    randomseedSpec;
+    ppmd_drawproc * drawProc;
 };
 
 
+
+static pixel
+averageTwoColors(pixel const p1,
+                 pixel const p2) {
+
+    pixel p;
+
+    PPM_ASSIGN(p,
+               (PPM_GETR(p1) + PPM_GETR(p2)) / 2,
+               (PPM_GETG(p1) + PPM_GETG(p2)) / 2,
+               (PPM_GETB(p1) + PPM_GETB(p2)) / 2);
+
+    return p;
+}
+
+
+
+static ppmd_drawproc average_drawproc;
+
+static void
+average_drawproc(pixel **     const pixels,
+                 int          const cols,
+                 int          const rows,
+                 pixval       const maxval,
+                 int          const col,
+                 int          const row,
+                 const void * const clientdata) {
+/*----------------------------------------------------------------------------
+  Reset the pixel's color to the average of the original color and the color
+  indicated by * clientdata.
+-----------------------------------------------------------------------------*/
+
+    if (col >= 0 && col < cols && row >= 0 && row < rows)
+        pixels[row][col] =
+            averageTwoColors(pixels[row][col], *((const pixel*) clientdata));
+}
+
+
+
+static ppmd_drawproc checkerboard_drawproc;
+
+static void
+checkerboard_drawproc(pixel **     const pixels,
+                      int          const cols,
+                      int          const rows,
+                      pixval       const maxval,
+                      int          const col,
+                      int          const row,
+                      const void * const clientdata) {
+/*----------------------------------------------------------------------------
+  If col and row are both even or both odd, do nothing.
+  If one is even and the other is odd, set the pixel's color to that indicated
+  by * clientdata.
+-----------------------------------------------------------------------------*/
+    if (col >= 0 && col < cols && row >= 0 &&
+        row < rows && row % 2 != col % 2)
+
+        pixels[row][col] = *((const pixel*) clientdata);
+}
+
+
+
 static void
 validateColorCount(Pattern      const basePattern,
                    unsigned int const colorCount) {
@@ -80,7 +141,6 @@ validateColorCount(Pattern      const basePattern,
     switch (basePattern) {
     case PAT_GINGHAM2:
     case PAT_ARGYLE1:
-    case PAT_SPIRO1:
         if (colorCount != 2)
             pm_error("Wrong number of colors: %u. "
                      "2 colors are required for the specified pattern.",
@@ -112,8 +172,6 @@ validateColorCount(Pattern      const basePattern,
                      colorCount);
         break;
 
-    case PAT_SPIRO2:
-    case PAT_SPIRO3:
     default:
         pm_error("INTERNAL ERROR.");
     }
@@ -188,9 +246,7 @@ parseCommandLine(int argc, const char ** argv,
     unsigned int squig;
     unsigned int camo;
     unsigned int anticamo;
-    unsigned int spiro1;
-    unsigned int spiro2;
-    unsigned int spiro3;
+    unsigned int meshSpec;
 
     MALLOCARRAY_NOFAIL(option_def, 100);
 
@@ -208,9 +264,9 @@ parseCommandLine(int argc, const char ** argv,
     OPTENT3(0, "tartan",        OPT_FLAG,   NULL,
             &tartan,     0);
     OPTENT3(0, "argyle1",       OPT_FLAG,   NULL,
-            &argyle1,     0);
+            &argyle1,    0);
     OPTENT3(0, "argyle2",       OPT_FLAG,   NULL,
-            &argyle2,     0);
+            &argyle2,    0);
     OPTENT3(0, "poles",         OPT_FLAG,   NULL,
             &poles,      0);
     OPTENT3(0, "squig",         OPT_FLAG,   NULL,
@@ -219,20 +275,12 @@ parseCommandLine(int argc, const char ** argv,
             &camo,       0);
     OPTENT3(0, "anticamo",      OPT_FLAG,   NULL,
             &anticamo,   0);
-#if SPIROGRAPHS != 0
-    OPTENT3(0, "spiro1",        OPT_FLAG,   NULL,
-            &spiro1,     0);
-    OPTENT3(0, "spiro2",        OPT_FLAG,   NULL,
-            &spiro1,     0);
-    OPTENT3(0, "spiro3",        OPT_FLAG,   NULL,
-            &spiro1,     0);
-#else
-    spiro1 = spiro2 = spiro3 = 0;
-#endif
     OPTENT3(0, "color",         OPT_STRINGLIST, &colorText,
             &cmdlineP->colorSpec,           0);
     OPTENT3(0, "randomseed",    OPT_UINT,       &cmdlineP->randomseed,
             &cmdlineP->randomseedSpec,      0);
+    OPTENT3(0, "mesh",          OPT_FLAG,   NULL,
+            &meshSpec,   0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
@@ -246,8 +294,7 @@ parseCommandLine(int argc, const char ** argv,
         gingham2 + gingham3 + madras + tartan + argyle1 + argyle2 +
         poles +
         squig +
-        camo + anticamo +
-        spiro1 + spiro2 + spiro3;
+        camo + anticamo;
 
     if (basePatternCount < 1)
         pm_error("You must specify a base pattern option such as -gingham2");
@@ -275,12 +322,6 @@ parseCommandLine(int argc, const char ** argv,
             cmdlineP->basePattern = PAT_CAMO;
         else if (anticamo)
             cmdlineP->basePattern = PAT_ANTICAMO;
-        else if (spiro1)
-            cmdlineP->basePattern = PAT_SPIRO1;
-        else if (spiro2)
-            cmdlineP->basePattern = PAT_SPIRO2;
-        else if (spiro3)
-            cmdlineP->basePattern = PAT_SPIRO3;
         else
             assert(false);  /* Every possibility is accounted for */
     }
@@ -291,6 +332,14 @@ parseCommandLine(int argc, const char ** argv,
     } else
         cmdlineP->colorTable.count = 0;
 
+    if (meshSpec) {
+        if (gingham2 + gingham3 + madras + tartan > 0)
+            cmdlineP->drawProc = &checkerboard_drawproc;
+        else
+            pm_message("-mesh ignored (no effect with specified pattern)");
+    } else
+        cmdlineP->drawProc = &average_drawproc;
+
     if (argc-1 != 2)
         pm_error("You must specify 2 non-option arguments: width and height "
                  "in pixels.  You specified %u", argc-1);
@@ -339,14 +388,15 @@ validateComputableDimensions(unsigned int const cols,
 
 
 static pixel
-randomColor(pixval const maxval) {
+randomColor(struct pm_randSt * const randStP,
+            pixval             const maxval) {
 
     pixel p;
 
     PPM_ASSIGN(p,
-               rand() % (maxval + 1),
-               rand() % (maxval + 1),
-               rand() % (maxval + 1)
+               pm_rand(randStP) % (maxval + 1),
+               pm_rand(randStP) % (maxval + 1),
+               pm_rand(randStP) % (maxval + 1)
         );
 
     return p;
@@ -354,15 +404,18 @@ randomColor(pixval const maxval) {
 
 
 
-#define DARK_THRESH 0.25
+static double const DARK_THRESH = 0.25;
+
+
 
 static pixel
-randomBrightColor(pixval const maxval) {
+randomBrightColor(struct pm_randSt * const randStP,
+                  pixval             const maxval) {
 
     pixel p;
 
     do {
-        p = randomColor(maxval);
+        p = randomColor(randStP, maxval);
     } while (PPM_LUMIN(p) <= maxval * DARK_THRESH);
 
     return p;
@@ -371,12 +424,13 @@ randomBrightColor(pixval const maxval) {
 
 
 static pixel
-randomDarkColor(pixval const maxval) {
+randomDarkColor(struct pm_randSt * const randStP,
+                pixval             const maxval) {
 
     pixel p;
 
     do {
-        p = randomColor(maxval);
+        p = randomColor(randStP, maxval);
     } while (PPM_LUMIN(p) > maxval * DARK_THRESH);
 
     return p;
@@ -384,37 +438,6 @@ randomDarkColor(pixval const maxval) {
 
 
 
-static pixel
-averageTwoColors(pixel const p1,
-                 pixel const p2) {
-
-    pixel p;
-
-    PPM_ASSIGN(p,
-               (PPM_GETR(p1) + PPM_GETR(p2)) / 2,
-               (PPM_GETG(p1) + PPM_GETG(p2)) / 2,
-               (PPM_GETB(p1) + PPM_GETB(p2)) / 2);
-
-    return p;
-}
-
-
-
-static ppmd_drawproc average_drawproc;
-
-static void
-average_drawproc(pixel **     const pixels,
-                 int          const cols,
-                 int          const rows,
-                 pixval       const maxval,
-                 int          const col,
-                 int          const row,
-                 const void * const clientdata) {
-
-    if (col >= 0 && col < cols && row >= 0 && row < rows)
-        pixels[row][col] =
-            averageTwoColors(pixels[row][col], *((const pixel*) clientdata));
-}
 
 
 
@@ -448,7 +471,8 @@ nextColorBg(ColorTable * const colorTableP) {
 
 
 static pixel
-randomAnticamoColor(pixval const maxval) {
+randomAnticamoColor(struct pm_randSt * const randStP,
+                    pixval             const maxval) {
 
     int v1, v2, v3;
     pixel p;
@@ -457,37 +481,49 @@ randomAnticamoColor(pixval const maxval) {
     v2 = (maxval + 1) / 2;
     v3 = 3 * v1;
 
-    switch (rand() % 15) {
+    switch (pm_rand(randStP) % 15) {
     case 0: case 1:
-        PPM_ASSIGN(p, rand() % v1 + v3, rand() % v2, rand() % v2);
+        PPM_ASSIGN(p, pm_rand(randStP) % v1 + v3,
+                      pm_rand(randStP) % v2,
+                      pm_rand(randStP) % v2);
         break;
 
     case 2:
     case 3:
-        PPM_ASSIGN(p, rand() % v2, rand() % v1 + v3, rand() % v2);
+        PPM_ASSIGN(p, pm_rand(randStP) % v2,
+                      pm_rand(randStP) % v1 + v3,
+                      pm_rand(randStP) % v2);
         break;
 
     case 4:
     case 5:
-        PPM_ASSIGN(p, rand() % v2, rand() % v2, rand() % v1 + v3);
+        PPM_ASSIGN(p, pm_rand(randStP) % v2,
+                      pm_rand(randStP) % v2,
+                      pm_rand(randStP) % v1 + v3);
         break;
 
     case 6:
     case 7:
     case 8:
-        PPM_ASSIGN(p, rand() % v2, rand() % v1 + v3, rand() % v1 + v3);
+        PPM_ASSIGN(p, pm_rand(randStP) % v2,
+                      pm_rand(randStP) % v1 + v3,
+                      pm_rand(randStP) % v1 + v3);
         break;
 
     case 9:
     case 10:
     case 11:
-        PPM_ASSIGN(p, rand() % v1 + v3, rand() % v2, rand() % v1 + v3);
+        PPM_ASSIGN(p, pm_rand(randStP) % v1 + v3,
+                      pm_rand(randStP) % v2,
+                      pm_rand(randStP) % v1 + v3);
         break;
 
     case 12:
     case 13:
     case 14:
-        PPM_ASSIGN(p, rand() % v1 + v3, rand() % v1 + v3, rand() % v2);
+        PPM_ASSIGN(p, pm_rand(randStP) % v1 + v3,
+                      pm_rand(randStP) % v1 + v3,
+                      pm_rand(randStP) % v2);
         break;
     }
 
@@ -497,7 +533,8 @@ randomAnticamoColor(pixval const maxval) {
 
 
 static pixel
-randomCamoColor(pixval const maxval) {
+randomCamoColor(struct pm_randSt * const randStP,
+                pixval             const maxval) {
 
     int const v1 = (maxval + 1 ) / 8;
     int const v2 = (maxval + 1 ) / 4;
@@ -505,31 +542,39 @@ randomCamoColor(pixval const maxval) {
 
     pixel p;
 
-    switch (rand() % 10) {
+    switch (pm_rand(randStP) % 10) {
     case 0:
     case 1:
     case 2:
         /* light brown */
-        PPM_ASSIGN(p, rand() % v3 + v3, rand() % v3 + v2, rand() % v3 + v2);
+        PPM_ASSIGN(p, pm_rand(randStP) % v3 + v3,
+                      pm_rand(randStP) % v3 + v2,
+                      pm_rand(randStP) % v3 + v2);
         break;
 
     case 3:
     case 4:
     case 5:
         /* dark green */
-        PPM_ASSIGN(p, rand() % v2, rand() % v2 + 3 * v1, rand() % v2);
+        PPM_ASSIGN(p, pm_rand(randStP) % v2,
+                      pm_rand(randStP) % v2 + 3 * v1,
+                      pm_rand(randStP) % v2);
         break;
 
     case 6:
     case 7:
         /* brown */
-        PPM_ASSIGN(p, rand() % v2 + v2, rand() % v2, rand() % v2);
+        PPM_ASSIGN(p, pm_rand(randStP) % v2 + v2,
+                      pm_rand(randStP) % v2,
+                      pm_rand(randStP) % v2);
         break;
 
     case 8:
     case 9:
         /* dark brown */
-        PPM_ASSIGN(p, rand() % v1 + v1, rand() % v1, rand() % v1);
+        PPM_ASSIGN(p, pm_rand(randStP) % v1 + v1,
+                      pm_rand(randStP) % v1,
+                      pm_rand(randStP) % v1);
         break;
     }
 
@@ -539,28 +584,30 @@ randomCamoColor(pixval const maxval) {
 
 
 static float
-rnduni(void) {
-    return rand() % 32767 / 32767.0;
+rnduni(struct pm_randSt * const randStP) {
+
+    return pm_rand(randStP) % 32767 / 32767.0;
 }
 
 
 
 static void
-clearBackgroundCamo(pixel **     const pixels,
-                    unsigned int const cols,
-                    unsigned int const rows,
-                    pixval       const maxval,
-                    ColorTable * const colorTableP,
-                    bool         const antiflag) {
+clearBackgroundCamo(pixel **           const pixels,
+                    unsigned int       const cols,
+                    unsigned int       const rows,
+                    pixval             const maxval,
+                    ColorTable *       const colorTableP,
+                    struct pm_randSt * const randStP,
+                    bool               const antiflag) {
 
     pixel color;
 
     if (colorTableP->count > 0) {
         color = colorTableP->color[0];
     } else if (antiflag)
-        color = randomAnticamoColor(maxval);
+        color = randomAnticamoColor(randStP, maxval);
     else
-        color = randomCamoColor(maxval);
+        color = randomCamoColor(randStP, maxval);
 
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 0, cols, rows, PPMD_NULLDRAWPROC,
@@ -570,13 +617,14 @@ clearBackgroundCamo(pixel **     const pixels,
 
 
 static void
-camoFill(pixel **         const pixels,
-         unsigned int     const cols,
-         unsigned int     const rows,
-         pixval           const maxval,
-         struct fillobj * const fh,
-         ColorTable     * const colorTableP,
-         bool             const antiflag) {
+camoFill(pixel **           const pixels,
+         unsigned int       const cols,
+         unsigned int       const rows,
+         pixval             const maxval,
+         struct fillobj *   const fh,
+         ColorTable     *   const colorTableP,
+         struct pm_randSt * const randStP,
+         bool               const antiflag) {
 
     pixel color;
 
@@ -585,9 +633,9 @@ camoFill(pixel **         const pixels,
         color = colorTableP->color[colorTableP->index];
         nextColorBg(colorTableP);
     } else if (antiflag)
-        color = randomAnticamoColor(maxval);
+        color = randomAnticamoColor(randStP, maxval);
     else
-        color = randomCamoColor(maxval);
+        color = randomCamoColor(randStP, maxval);
 
     ppmd_fill(pixels, cols, rows, maxval, fh, PPMD_NULLDRAWPROC, &color);
 }
@@ -608,25 +656,29 @@ camoFill(pixel **         const pixels,
 
 
 static void
-computeXsYs(int *        const xs,
-            int *        const ys,
-            unsigned int const cols,
-            unsigned int const rows,
-            unsigned int const pointCt) {
-
-    unsigned int const cx = rand() % cols;
-    unsigned int const cy = rand() % rows;
-    double const a = rnduni() * (MAX_ELLIPSE_FACTOR - MIN_ELLIPSE_FACTOR) +
-        MIN_ELLIPSE_FACTOR;
-    double const b = rnduni() * (MAX_ELLIPSE_FACTOR - MIN_ELLIPSE_FACTOR) +
-        MIN_ELLIPSE_FACTOR;
-    double const theta = rnduni() * 2.0 * M_PI;
+computeXsYs(int *              const xs,
+            int *              const ys,
+            unsigned int       const cols,
+            unsigned int       const rows,
+            unsigned int       const pointCt,
+            struct pm_randSt * const randStP) {
+
+    unsigned int const cx = pm_rand(randStP) % cols;
+    unsigned int const cy = pm_rand(randStP) % rows;
+    double const a = rnduni(randStP) *
+                       (MAX_ELLIPSE_FACTOR - MIN_ELLIPSE_FACTOR) +
+                        MIN_ELLIPSE_FACTOR;
+    double const b = rnduni(randStP) *
+                       (MAX_ELLIPSE_FACTOR - MIN_ELLIPSE_FACTOR) +
+                        MIN_ELLIPSE_FACTOR;
+    double const theta = rnduni(randStP) * 2.0 * M_PI;
 
     unsigned int p;
 
     for (p = 0; p < pointCt; ++p) {
-        double const c = rnduni() * (MAX_POINT_FACTOR - MIN_POINT_FACTOR) +
-            MIN_POINT_FACTOR;
+        double const c = rnduni(randStP) *
+                           (MAX_POINT_FACTOR - MIN_POINT_FACTOR) +
+                            MIN_POINT_FACTOR;
         double const tx   = a * sin(p * 2.0 * M_PI / pointCt);
         double const ty   = b * cos(p * 2.0 * M_PI / pointCt);
         double const tang = atan2(ty, tx) + theta;
@@ -638,18 +690,20 @@ computeXsYs(int *        const xs,
 
 
 static void
-camo(pixel **     const pixels,
-     unsigned int const cols,
-     unsigned int const rows,
-     ColorTable * const colorTableP,
-     pixval       const maxval,
-     bool         const antiflag) {
+camo(pixel **           const pixels,
+     unsigned int       const cols,
+     unsigned int       const rows,
+     ColorTable *       const colorTableP,
+     struct pm_randSt * const randStP,
+     pixval             const maxval,
+     bool               const antiflag) {
 
     unsigned int const n = (rows * cols) / SQR(BLOBRAD) * 5;
 
     unsigned int i;
 
-    clearBackgroundCamo(pixels, cols, rows, maxval, colorTableP, antiflag);
+    clearBackgroundCamo(pixels, cols, rows, maxval,
+                        colorTableP, randStP, antiflag);
 
     if (colorTableP->count > 0) {
         assert(colorTableP->count > 1);
@@ -658,13 +712,13 @@ camo(pixel **     const pixels,
 
     for (i = 0; i < n; ++i) {
         unsigned int const pointCt =
-            rand() % (MAX_POINTS - MIN_POINTS + 1) + MIN_POINTS;
+            pm_rand(randStP) % (MAX_POINTS - MIN_POINTS + 1) + MIN_POINTS;
 
         int xs[MAX_POINTS], ys[MAX_POINTS];
         int x0, y0;
         struct fillobj * fh;
 
-        computeXsYs(xs, ys, cols, rows, pointCt);
+        computeXsYs(xs, ys, cols, rows, pointCt, randStP);
 
         x0 = (xs[0] + xs[pointCt - 1]) / 2;
         y0 = (ys[0] + ys[pointCt - 1]) / 2;
@@ -675,7 +729,8 @@ camo(pixel **     const pixels,
             pixels, cols, rows, maxval, x0, y0, pointCt, xs, ys, x0, y0,
             ppmd_fill_drawproc, fh);
 
-        camoFill(pixels, cols, rows, maxval, fh, colorTableP, antiflag);
+        camoFill(pixels, cols, rows, maxval, fh,
+                 colorTableP, randStP, antiflag);
 
         ppmd_fill_destroy(fh);
     }
@@ -688,17 +743,21 @@ camo(pixel **     const pixels,
 -----------------------------------------------------------------------------*/
 
 static void
-gingham2(pixel **     const pixels,
-         unsigned int const cols,
-         unsigned int const rows,
-         ColorTable   const colorTable,
-         pixval       const maxval) {
+gingham2(pixel **           const pixels,
+         unsigned int       const cols,
+         unsigned int       const rows,
+         ColorTable         const colorTable,
+         struct pm_randSt * const randStP,
+         ppmd_drawproc    * const drawproc,
+         pixval             const maxval) {
 
     bool  const colorSpec = (colorTable.count > 0);
     pixel const backcolor = colorSpec ?
-                            colorTable.color[0] : randomDarkColor(maxval);
+                              colorTable.color[0] :
+                              randomDarkColor(randStP, maxval);
     pixel const forecolor = colorSpec ?
-                            colorTable.color[1] : randomBrightColor(maxval);
+                              colorTable.color[1] :
+                              randomBrightColor(randStP, maxval);
     unsigned int const colso2 = cols / 2;
     unsigned int const rowso2 = rows / 2;
 
@@ -712,29 +771,34 @@ gingham2(pixel **     const pixels,
 
     /* Woof. */
     ppmd_filledrectangle(
-        pixels, cols, rows, maxval, 0, 0, cols, rowso2, average_drawproc,
+        pixels, cols, rows, maxval, 0, 0, cols, rowso2, drawproc,
         &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rowso2, cols, rows - rowso2,
-        average_drawproc, &forecolor);
+        drawproc, &forecolor);
 }
 
 
 
 static void
-gingham3(pixel **     const pixels,
-         unsigned int const cols,
-         unsigned int const rows,
-         ColorTable   const colorTable,
-         pixval       const maxval) {
+gingham3(pixel **           const pixels,
+         unsigned int       const cols,
+         unsigned int       const rows,
+         ColorTable         const colorTable,
+         struct pm_randSt * const randStP,
+         ppmd_drawproc    * const drawproc,
+         pixval             const maxval) {
 
     bool  const colorSpec = (colorTable.count > 0);
-    pixel const backcolor = colorSpec ?
-                            colorTable.color[0] : randomDarkColor(maxval);
+    pixel const backcolor  = colorSpec ?
+                               colorTable.color[0] :
+                               randomDarkColor(randStP, maxval);
     pixel const fore1color = colorSpec ?
-                            colorTable.color[1] : randomBrightColor(maxval);
+                               colorTable.color[1] :
+                               randomBrightColor(randStP, maxval);
     pixel const fore2color = colorSpec ?
-                            colorTable.color[2] : randomBrightColor(maxval);
+                               colorTable.color[2] :
+                               randomBrightColor(randStP, maxval);
     unsigned int const colso4 = cols / 4;
     unsigned int const rowso4 = rows / 4;
 
@@ -754,35 +818,40 @@ gingham3(pixel **     const pixels,
 
     /* Woof. */
     ppmd_filledrectangle(
-        pixels, cols, rows, maxval, 0, 0, cols, rowso4, average_drawproc,
+        pixels, cols, rows, maxval, 0, 0, cols, rowso4, drawproc,
         &backcolor);
     ppmd_filledrectangle(
-        pixels, cols, rows, maxval, 0, rowso4, cols, rowso4, average_drawproc,
+        pixels, cols, rows, maxval, 0, rowso4, cols, rowso4, drawproc,
         &fore1color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 2 * rowso4, cols, rowso4,
-        average_drawproc, &fore2color);
+        drawproc, &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 3 * rowso4, cols, rows - rowso4,
-        average_drawproc, &fore1color);
+        drawproc, &fore1color);
 }
 
 
 
 static void
-madras(pixel **     const pixels,
-       unsigned int const cols,
-       unsigned int const rows,
-       ColorTable   const colorTable,
-       pixval       const maxval) {
+madras(pixel **           const pixels,
+       unsigned int       const cols,
+       unsigned int       const rows,
+       ColorTable         const colorTable,
+       struct pm_randSt * const randStP,
+       ppmd_drawproc    * const drawproc,
+       pixval             const maxval) {
 
     bool  const colorSpec = (colorTable.count > 0);
-    pixel const backcolor = colorSpec ?
-                            colorTable.color[0] : randomDarkColor(maxval);
+    pixel const backcolor  = colorSpec ?
+                               colorTable.color[0] :
+                               randomDarkColor(randStP, maxval);
     pixel const fore1color = colorSpec ?
-                            colorTable.color[1] : randomBrightColor(maxval);
+                               colorTable.color[1] :
+                               randomBrightColor(randStP, maxval);
     pixel const fore2color = colorSpec ?
-                            colorTable.color[2] : randomBrightColor(maxval);
+                               colorTable.color[2] :
+                               randomBrightColor(randStP, maxval);
     unsigned int const cols2  = cols * 2 / 44;
     unsigned int const rows2  = rows * 2 / 44;
     unsigned int const cols3  = cols * 3 / 44;
@@ -846,72 +915,77 @@ madras(pixel **     const pixels,
 
     /* Woof. */
     ppmd_filledrectangle(
-        pixels, cols, rows, maxval, 0, 0, cols, rows2, average_drawproc,
+        pixels, cols, rows, maxval, 0, 0, cols, rows2, drawproc,
         &backcolor);
     ppmd_filledrectangle(
-        pixels, cols, rows, maxval, 0, rows2, cols, rows3, average_drawproc,
+        pixels, cols, rows, maxval, 0, rows2, cols, rows3, drawproc,
         &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rows2 + rows3, cols, rows2,
-        average_drawproc, &backcolor);
+        drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 2 * rows2 + rows3, cols, rows2,
-        average_drawproc, &fore1color);
+        drawproc, &fore1color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 3 * rows2 + rows3, cols, rows2,
-        average_drawproc, &backcolor);
+        drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 4 * rows2 + rows3, cols, rows6a,
-        average_drawproc, &fore2color);
+        drawproc, &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 4 * rows2 + rows3 + rows6a, cols, rows2,
-        average_drawproc, &backcolor);
+        drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 5 * rows2 + rows3 + rows6a, cols, rows3,
-        average_drawproc, &fore1color);
+        drawproc, &fore1color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 5 * rows2 + 2 * rows3 + rows6a, cols,
-        rows2, average_drawproc, &backcolor);
+        rows2, drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 6 * rows2 + 2 * rows3 + rows6a, cols,
-        rows3, average_drawproc, &fore1color);
+        rows3, drawproc, &fore1color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 6 * rows2 + 3 * rows3 + rows6a, cols,
-        rows2, average_drawproc, &backcolor);
+        rows2, drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 7 * rows2 + 3 * rows3 + rows6a, cols,
-        rows6b, average_drawproc, &fore2color);
+        rows6b, drawproc, &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 7 * rows2 + 3 * rows3 + rows6a + rows6b,
-        cols, rows2, average_drawproc, &backcolor);
+        cols, rows2, drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 8 * rows2 + 3 * rows3 + rows6a + rows6b,
-        cols, rows2, average_drawproc, &fore1color);
+        cols, rows2, drawproc, &fore1color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 9 * rows2 + 3 * rows3 + rows6a + rows6b,
-        cols, rows2, average_drawproc, &backcolor);
+        cols, rows2, drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0,
         10 * rows2 + 3 * rows3 + rows6a + rows6b,
-        cols, rows3, average_drawproc, &fore2color);
+        cols, rows3, drawproc, &fore2color);
 }
 
 
 
 static void
-tartan(pixel **     const pixels,
-       unsigned int const cols,
-       unsigned int const rows,
-       ColorTable   const colorTable,
-       pixval       const maxval) {
+tartan(pixel **           const pixels,
+       unsigned int       const cols,
+       unsigned int       const rows,
+       ColorTable         const colorTable,
+       struct pm_randSt * const randStP,
+       ppmd_drawproc    * const drawproc,
+       pixval             const maxval) {
 
     bool  const colorSpec = (colorTable.count > 0);
-    pixel const backcolor = colorSpec ?
-                            colorTable.color[0] : randomDarkColor(maxval);
+    pixel const backcolor  = colorSpec ?
+                               colorTable.color[0] :
+                               randomDarkColor(randStP, maxval);
     pixel const fore1color = colorSpec ?
-                            colorTable.color[1] : randomBrightColor(maxval);
+                               colorTable.color[1] :
+                               randomBrightColor(randStP, maxval);
     pixel const fore2color = colorSpec ?
-                            colorTable.color[2] : randomBrightColor(maxval);
+                               colorTable.color[2] :
+                               randomBrightColor(randStP, maxval);
     unsigned int const cols1  = cols / 22;
     unsigned int const rows1  = rows / 22;
     unsigned int const cols3  = cols * 3 / 22;
@@ -951,29 +1025,29 @@ tartan(pixel **     const pixels,
 
     /* Woof. */
     ppmd_filledrectangle(
-        pixels, cols, rows, maxval, 0, 0, cols, rows5a, average_drawproc,
+        pixels, cols, rows, maxval, 0, 0, cols, rows5a, drawproc,
         &backcolor);
     ppmd_filledrectangle(
-        pixels, cols, rows, maxval, 0, rows5a, cols, rows1, average_drawproc,
+        pixels, cols, rows, maxval, 0, rows5a, cols, rows1, drawproc,
         &fore1color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rows5a + rows1, cols, rows5b,
-        average_drawproc, &backcolor);
+        drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rows10 + rows1, cols, rows3,
-        average_drawproc, &fore2color);
+        drawproc, &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rows10 + rows1 + rows3, cols, rows1,
-        average_drawproc, &backcolor);
+        drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rows10 + 2 * rows1 + rows3, cols, rows3,
-        average_drawproc, &fore2color);
+        drawproc, &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rows10 + 2 * rows1 + 2 * rows3, cols,
-        rows1, average_drawproc, &backcolor);
+        rows1, drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rows10 + 3 * rows1 + 2 * rows3, cols,
-        rows3, average_drawproc, &fore2color);
+        rows3, drawproc, &fore2color);
 }
 
 
@@ -1013,14 +1087,15 @@ argyle(pixel **     const pixels,
        unsigned int const cols,
        unsigned int const rows,
        ColorTable   const colorTable,
+       struct pm_randSt * const randStP,
        pixval       const maxval,
        bool         const stripes) {
 
     bool  const colorSpec = (colorTable.count > 0);
     pixel const backcolor = colorSpec ?
-        colorTable.color[0] : randomDarkColor(maxval);
+        colorTable.color[0] : randomDarkColor(randStP, maxval);
     pixel const forecolor = colorSpec ?
-        colorTable.color[1] : randomBrightColor(maxval);
+        colorTable.color[1] : randomBrightColor(randStP, maxval);
 
     /* Fill canvas with background to start */
     ppmd_filledrectangle(
@@ -1032,7 +1107,8 @@ argyle(pixel **     const pixels,
     if (stripes) {
          /* Connect corners with thin stripes */
          pixel const stripecolor =
-             colorSpec ? colorTable.color[2] : randomBrightColor(maxval);
+             colorSpec ? colorTable.color[2] :
+                         randomBrightColor(randStP, maxval);
 
          ppmd_line(pixels, cols, rows, maxval, 0, 0, cols-1, rows-1,
               PPMD_NULLDRAWPROC, (char *) &stripecolor);
@@ -1054,27 +1130,28 @@ argyle(pixel **     const pixels,
 
 
 static void
-placeAndColorPolesRandomly(int *        const xs,
-                           int *        const ys,
-                           pixel *      const colors,
-                           unsigned int const cols,
-                           unsigned int const rows,
-                           pixval       const maxval,
-                           ColorTable * const colorTableP,
-                           unsigned int const poleCt) {
+placeAndColorPolesRandomly(int *              const xs,
+                           int *              const ys,
+                           pixel *            const colors,
+                           unsigned int       const cols,
+                           unsigned int       const rows,
+                           pixval             const maxval,
+                           ColorTable *       const colorTableP,
+                           struct pm_randSt * const randStP,
+                           unsigned int       const poleCt) {
 
     unsigned int i;
 
     for (i = 0; i < poleCt; ++i) {
 
-        xs[i] = rand() % cols;
-        ys[i] = rand() % rows;
+        xs[i] = pm_rand(randStP) % cols;
+        ys[i] = pm_rand(randStP) % rows;
 
         if (colorTableP->count > 0) {
             colors[i] = colorTableP->color[colorTableP->index];
             nextColor(colorTableP);
         } else
-            colors[i] = randomBrightColor(maxval);
+            colors[i] = randomBrightColor(randStP, maxval);
     }
 }
 
@@ -1104,11 +1181,12 @@ assignInterpolatedColor(pixel * const resultP,
 
 
 static void
-poles(pixel **     const pixels,
-      unsigned int const cols,
-      unsigned int const rows,
-      ColorTable * const colorTableP,
-      pixval       const maxval) {
+poles(pixel **           const pixels,
+      unsigned int       const cols,
+      unsigned int       const rows,
+      ColorTable *       const colorTableP,
+      struct pm_randSt * const randStP,
+      pixval             const maxval) {
 
     unsigned int const poleCt = MAX(2, MIN(MAXPOLES, cols * rows / 30000));
 
@@ -1117,7 +1195,7 @@ poles(pixel **     const pixels,
     unsigned int row;
 
     placeAndColorPolesRandomly(xs, ys, colors, cols, rows, maxval,
-                               colorTableP, poleCt);
+                               colorTableP, randStP, poleCt);
 
     /* Interpolate points */
 
@@ -1236,11 +1314,12 @@ sqRainbowCircleDrawproc(pixel **     const pixels,
 
 
 static void
-chooseSqPoleColors(ColorTable * const colorTableP,
-                   pixval       const maxval,
-                   pixel *      const color1P,
-                   pixel *      const color2P,
-                   pixel *      const color3P) {
+chooseSqPoleColors(ColorTable *       const colorTableP,
+                   pixval             const maxval,
+                   pixel *            const color1P,
+                   pixel *            const color2P,
+                   pixel *            const color3P,
+                   struct pm_randSt * const randStP) {
 
     if (colorTableP->count > 0) {
         *color1P = colorTableP->color[colorTableP->index];
@@ -1250,19 +1329,20 @@ chooseSqPoleColors(ColorTable * const colorTableP,
         *color3P = colorTableP->color[colorTableP->index];
         nextColor(colorTableP);
     } else {
-        *color1P = randomBrightColor(maxval);
-        *color2P = randomBrightColor(maxval);
-        *color3P = randomBrightColor(maxval);
+        *color1P = randomBrightColor(randStP, maxval);
+        *color2P = randomBrightColor(randStP, maxval);
+        *color3P = randomBrightColor(randStP, maxval);
     }
 }
 
 
 
 static void
-sqAssignColors(unsigned int const circlecount,
-               pixval       const maxval,
-               ColorTable * const colorTableP,
-               pixel *      const colors) {
+sqAssignColors(unsigned int       const circlecount,
+               pixval             const maxval,
+               ColorTable *       const colorTableP,
+               pixel *            const colors,
+               struct pm_randSt * const randStP) {
 
     float const cco3 = (circlecount - 1) / 3.0;
 
@@ -1271,7 +1351,7 @@ sqAssignColors(unsigned int const circlecount,
     pixel rc3;
     unsigned int i;
 
-    chooseSqPoleColors(colorTableP, maxval, &rc1, &rc2, &rc3);
+    chooseSqPoleColors(colorTableP, maxval, &rc1, &rc2, &rc3, randStP);
 
     for (i = 0; i < circlecount; ++i) {
         if (i < cco3) {
@@ -1333,24 +1413,25 @@ clearBackgroundSquig(pixel **     const pixels,
 
 
 static void
-chooseWrapAroundPoint(unsigned int const cols,
-                      unsigned int const rows,
-                      ppmd_point * const pFirstP,
-                      ppmd_point * const pLastP,
-                      ppmd_point * const p0P,
-                      ppmd_point * const p1P,
-                      ppmd_point * const p2P,
-                      ppmd_point * const p3P) {
-
-    switch (rand() % 4) {
+chooseWrapAroundPoint(unsigned int       const cols,
+                      unsigned int       const rows,
+                      ppmd_point *       const pFirstP,
+                      ppmd_point *       const pLastP,
+                      ppmd_point *       const p0P,
+                      ppmd_point *       const p1P,
+                      ppmd_point *       const p2P,
+                      ppmd_point *       const p3P,
+                      struct pm_randSt * const randStP) {
+
+    switch (pm_rand(randStP) % 4) {
     case 0:
-        p1P->x = rand() % cols;
+        p1P->x = pm_rand(randStP) % cols;
         p1P->y = 0;
         if (p1P->x < cols / 2)
-            pFirstP->x = rand() % (p1P->x * 2 + 1);
+            pFirstP->x = pm_rand(randStP) % (p1P->x * 2 + 1);
         else
-            pFirstP->x = cols - 1 - rand() % ((cols - p1P->x) * 2);
-        pFirstP->y = rand() % rows;
+            pFirstP->x = cols - 1 - pm_rand(randStP) % ((cols - p1P->x) * 2);
+        pFirstP->y = pm_rand(randStP) % rows;
         p2P->x = p1P->x;
         p2P->y = rows - 1;
         pLastP->x = 2 * p2P->x - pFirstP->x;
@@ -1362,13 +1443,13 @@ chooseWrapAroundPoint(unsigned int const cols,
         break;
 
     case 1:
-        p2P->x = rand() % cols;
+        p2P->x = pm_rand(randStP) % cols;
         p2P->y = 0;
         if (p2P->x < cols / 2)
-            pLastP->x = rand() % (p2P->x * 2 + 1);
+            pLastP->x = pm_rand(randStP) % (p2P->x * 2 + 1);
         else
-            pLastP->x = cols - 1 - rand() % ((cols - p2P->x) * 2);
-        pLastP->y = rand() % rows;
+            pLastP->x = cols - 1 - pm_rand(randStP) % ((cols - p2P->x) * 2);
+        pLastP->y = pm_rand(randStP) % rows;
         p1P->x = p2P->x;
         p1P->y = rows - 1;
         pFirstP->x = 2 * p1P->x - pLastP->x;
@@ -1381,12 +1462,12 @@ chooseWrapAroundPoint(unsigned int const cols,
 
     case 2:
         p1P->x = 0;
-        p1P->y = rand() % rows;
-        pFirstP->x = rand() % cols;
+        p1P->y = pm_rand(randStP) % rows;
+        pFirstP->x = pm_rand(randStP) % cols;
         if (p1P->y < rows / 2)
-            pFirstP->y = rand() % (p1P->y * 2 + 1);
+            pFirstP->y = pm_rand(randStP) % (p1P->y * 2 + 1);
         else
-            pFirstP->y = rows - 1 - rand() % ((rows - p1P->y) * 2);
+            pFirstP->y = rows - 1 - pm_rand(randStP) % ((rows - p1P->y) * 2);
         p2P->x = cols - 1;
         p2P->y = p1P->y;
         pLastP->x = p2P->x - pFirstP->x;
@@ -1399,12 +1480,12 @@ chooseWrapAroundPoint(unsigned int const cols,
 
     case 3:
         p2P->x = 0;
-        p2P->y = rand() % rows;
-        pLastP->x = rand() % cols;
+        p2P->y = pm_rand(randStP) % rows;
+        pLastP->x = pm_rand(randStP) % cols;
         if (p2P->y < rows / 2)
-            pLastP->y = rand() % (p2P->y * 2 + 1);
+            pLastP->y = pm_rand(randStP) % (p2P->y * 2 + 1);
         else
-            pLastP->y = rows - 1 - rand() % ((rows - p2P->y) * 2);
+            pLastP->y = rows - 1 - pm_rand(randStP) % ((rows - p2P->y) * 2);
         p1P->x = cols - 1;
         p1P->y = p2P->y;
         pFirstP->x = p1P->x - pLastP->x;
@@ -1420,11 +1501,12 @@ chooseWrapAroundPoint(unsigned int const cols,
 
 
 static void
-squig(pixel **     const pixels,
-      unsigned int const cols,
-      unsigned int const rows,
-      ColorTable * const colorTableP,
-      pixval       const maxval) {
+squig(pixel **           const pixels,
+      unsigned int       const cols,
+      unsigned int       const rows,
+      ColorTable *       const colorTableP,
+      struct pm_randSt * const randStP,
+      pixval             const maxval) {
 
     int i;
 
@@ -1453,10 +1535,11 @@ squig(pixel **     const pixels,
         ppmd_circlep(pixels, cols, rows, maxval,
                      ppmd_makePoint(0, 0), radius,
                      sqMeasureCircleDrawproc, &sqClientData);
-        sqAssignColors(squig.circleCt, maxval, colorTableP, squig.color);
+        sqAssignColors(squig.circleCt, maxval, colorTableP, squig.color,
+                       randStP);
 
         chooseWrapAroundPoint(cols, rows, &c[0], &c[SQ_POINTS-1],
-                              &p0, &p1, &p2, &p3);
+                              &p0, &p1, &p2, &p3, randStP);
 
         {
             /* Do the middle points */
@@ -1466,8 +1549,8 @@ squig(pixel **     const pixels,
               /* validateSquigAspect() assures that
                  cols - 2 * radius, rows -2 * radius are positive
               */
-                c[j].x = (rand() % (cols - 2 * radius)) + radius;
-                c[j].y = (rand() % (rows - 2 * radius)) + radius;
+                c[j].x = (pm_rand(randStP) % (cols - 2 * radius)) + radius;
+                c[j].y = (pm_rand(randStP) % (rows - 2 * radius)) + radius;
             }
         }
 
@@ -1490,6 +1573,7 @@ main(int argc, const char ** argv) {
 
     struct CmdlineInfo cmdline;
     pixel ** pixels;
+    struct pm_randSt randSt;
 
     pm_proginit(&argc, argv);
 
@@ -1497,65 +1581,68 @@ main(int argc, const char ** argv) {
 
     validateComputableDimensions(cmdline.width, cmdline.height);
 
-    srand(cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed());
+    pm_randinit(&randSt);
+    pm_srand2(&randSt, cmdline.randomseedSpec, cmdline.randomseed);
 
     pixels = ppm_allocarray(cmdline.width, cmdline.height);
 
     switch (cmdline.basePattern) {
     case PAT_GINGHAM2:
         gingham2(pixels, cmdline.width, cmdline.height,
-                 cmdline.colorTable, PPM_MAXMAXVAL);
+                 cmdline.colorTable, &randSt, cmdline.drawProc, PPM_MAXMAXVAL);
         break;
 
     case PAT_GINGHAM3:
         gingham3(pixels, cmdline.width, cmdline.height,
-                 cmdline.colorTable, PPM_MAXMAXVAL);
+                 cmdline.colorTable, &randSt, cmdline.drawProc, PPM_MAXMAXVAL);
         break;
 
     case PAT_MADRAS:
         madras(pixels, cmdline.width, cmdline.height,
-               cmdline.colorTable, PPM_MAXMAXVAL);
+               cmdline.colorTable, &randSt, cmdline.drawProc, PPM_MAXMAXVAL);
         break;
 
     case PAT_TARTAN:
         tartan(pixels, cmdline.width, cmdline.height,
-               cmdline.colorTable, PPM_MAXMAXVAL);
+               cmdline.colorTable, &randSt, cmdline.drawProc, PPM_MAXMAXVAL);
         break;
 
     case PAT_ARGYLE1:
         argyle(pixels, cmdline.width, cmdline.height,
-               cmdline.colorTable, PPM_MAXMAXVAL, FALSE);
+               cmdline.colorTable, &randSt, PPM_MAXMAXVAL, FALSE);
         break;
 
     case PAT_ARGYLE2:
         argyle(pixels, cmdline.width, cmdline.height,
-               cmdline.colorTable, PPM_MAXMAXVAL, TRUE);
+               cmdline.colorTable, &randSt, PPM_MAXMAXVAL, TRUE);
         break;
 
     case PAT_POLES:
         poles(pixels, cmdline.width, cmdline.height,
-              &cmdline.colorTable, PPM_MAXMAXVAL);
+              &cmdline.colorTable, &randSt, PPM_MAXMAXVAL);
         break;
 
     case PAT_SQUIG:
         squig(pixels, cmdline.width, cmdline.height,
-              &cmdline.colorTable, PPM_MAXMAXVAL);
+              &cmdline.colorTable, &randSt, PPM_MAXMAXVAL);
         break;
 
     case PAT_CAMO:
         camo(pixels, cmdline.width, cmdline.height,
-             &cmdline.colorTable, PPM_MAXMAXVAL, 0);
+             &cmdline.colorTable, &randSt, PPM_MAXMAXVAL, 0);
         break;
 
     case PAT_ANTICAMO:
         camo(pixels, cmdline.width, cmdline.height,
-             &cmdline.colorTable, PPM_MAXMAXVAL, 1);
+             &cmdline.colorTable, &randSt, PPM_MAXMAXVAL, 1);
         break;
 
     default:
         pm_error("can't happen!");
     }
 
+    pm_randterm(&randSt);
+
     ppm_writeppm(stdout, pixels, cmdline.width, cmdline.height,
                  PPM_MAXMAXVAL, 0);
 
@@ -1567,4 +1654,3 @@ main(int argc, const char ** argv) {
 }
 
 
-
diff --git a/generator/ppmrainbow b/generator/ppmrainbow
index e8a329ff..68d519a0 100755
--- a/generator/ppmrainbow
+++ b/generator/ppmrainbow
@@ -26,6 +26,19 @@ exec perl -w -x -S -- "$0" "$@"
 use strict;
 use Getopt::Long;
 use File::Temp;
+use IO::Handle;
+
+
+
+sub pm_message($) {
+    STDERR->print("ppmrainbow: $_[0]\n");
+}
+
+sub pm_error($) {
+    pm_message($_[0]);
+    exit(1);
+}
+
 
 my ($FALSE, $TRUE) = (0,1);
 
@@ -46,15 +59,6 @@ sub doVersionHack($) {
 
 
 
-sub fatal($) {
-    my ($msg) = @_;
-
-    print(STDERR "ppmrainbow: $msg\n");
-    exit(1);
-}
-
-
-
 ##############################################################################
 #
 #                                 MAINLINE
@@ -79,14 +83,14 @@ GetOptions("width=i"   => \$Twid,
            "verbose!"  => \$verbose);
 
 if ($Twid < 1 || $Thgt < 1) {
-    fatal("invalid width and/or height");
+    pm_error("invalid width and/or height");
 }
 my $verboseCommand = $verbose ? "set -x;" : "";
 
 if (@ARGV < 1) {
-    fatal("You must specify at least one color as an argument");
+    pm_error("You must specify at least one color as an argument");
 } elsif (@ARGV < 2 && ! $repeat) {
-    fatal("With the -norepeat option, you must specify at least two colors " .
+    pm_error("With the -norepeat option, you must specify at least two colors " .
           "as arguments.");
 }
 
@@ -115,15 +119,18 @@ while (@colorlist >= 2) {
     my $rc = system("$verboseCommand pgmramp -lr $w $Thgt | " .
                     "pgmtoppm \"$colorlist[0]-$colorlist[1]\" >$outfile");
     if ($rc != 0) {
-        fatal("pgmramp|pgmtoppm pipe failed.");
+        pm_error("pgmramp|pgmtoppm pipe failed.");
     }
     $widthRemaining -= $w;
     $n++;
     shift @colorlist;
 }
 
-0 == system qq{$verboseCommand pnmcat -lr @outlist}
-    or exit 1;
+my $termStat =
+    system("$verboseCommand pamcat -leftright @outlist");
+if ($termStat != 0) {
+    exit 1;
+}
 
 exit 0;
 
diff --git a/generator/ppmrough.c b/generator/ppmrough.c
index e749c9c2..a4a1f14d 100644
--- a/generator/ppmrough.c
+++ b/generator/ppmrough.c
@@ -16,11 +16,10 @@
 
 #include "pm_c_util.h"
 #include "mallocvar.h"
+#include "rand.h"
 #include "shhopt.h"
 #include "ppm.h"
 
-static pixel** PIX;
-static pixval BG_RED, BG_GREEN, BG_BLUE;
 
 
 struct CmdlineInfo {
@@ -28,50 +27,58 @@ struct CmdlineInfo {
      in a form easy for the program to use.
   */
     unsigned int left, right, top, bottom;
-    unsigned int width, height, var;
-    const char * bg_rgb;
-    const char * fg_rgb;
+    unsigned int leftSpec, rightSpec, topSpec, bottomSpec;
+    unsigned int width;
+    unsigned int height;
+    unsigned int var;
+    const char * bg;  /* Null if not specified */
+    const char * fg;  /* Null if not specified */
     unsigned int randomseed;
     unsigned int randomseedSpec;
     unsigned int verbose;
 };
 
 
+
 static void
 parseCommandLine(int argc, const char ** argv,
                  struct CmdlineInfo * const cmdlineP) {
 
+    unsigned int widthSpec, heightSpec, bgSpec, fgSpec, varSpec;
+
     optEntry * option_def;
         /* Instructions to OptParseOptions2 on how to parse our options.    */
     optStruct3 opt;
 
     unsigned int option_def_index;
 
-    MALLOCARRAY(option_def, 100);
+    MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENTRY */
-    OPTENT3(0, "width",       OPT_UINT,   &cmdlineP->width,   NULL, 0);
-    OPTENT3(0, "height",      OPT_UINT,   &cmdlineP->height,  NULL, 0);
-    OPTENT3(0, "left",        OPT_UINT,   &cmdlineP->left,    NULL, 0);
-    OPTENT3(0, "right",       OPT_UINT,   &cmdlineP->right,   NULL, 0);
-    OPTENT3(0, "top",         OPT_UINT,   &cmdlineP->top,     NULL, 0);
-    OPTENT3(0, "bottom",      OPT_UINT,   &cmdlineP->bottom,  NULL, 0);
-    OPTENT3(0, "bg",          OPT_STRING, &cmdlineP->bg_rgb,  NULL, 0);
-    OPTENT3(0, "fg",          OPT_STRING, &cmdlineP->fg_rgb,  NULL, 0);
-    OPTENT3(0, "var",         OPT_UINT,   &cmdlineP->var,     NULL, 0);
+    OPTENT3(0, "width",       OPT_UINT,   &cmdlineP->width,
+            &widthSpec, 0);
+    OPTENT3(0, "height",      OPT_UINT,   &cmdlineP->height,
+            &heightSpec, 0);
+    OPTENT3(0, "left",        OPT_UINT,   &cmdlineP->left,
+            &cmdlineP->leftSpec, 0);
+    OPTENT3(0, "right",       OPT_UINT,   &cmdlineP->right,
+            &cmdlineP->rightSpec, 0);
+    OPTENT3(0, "top",         OPT_UINT,   &cmdlineP->top,
+            &cmdlineP->topSpec, 0);
+    OPTENT3(0, "bottom",      OPT_UINT,   &cmdlineP->bottom,
+            &cmdlineP->bottomSpec, 0);
+    OPTENT3(0, "bg",          OPT_STRING, &cmdlineP->bg,
+            &bgSpec, 0);
+    OPTENT3(0, "fg",          OPT_STRING, &cmdlineP->fg,
+            &fgSpec, 0);
+    OPTENT3(0, "var",         OPT_UINT,   &cmdlineP->var,
+            &varSpec, 0);
     OPTENT3(0, "randomseed",  OPT_UINT,   &cmdlineP->randomseed,
             &cmdlineP->randomseedSpec, 0);
     OPTENT3(0, "init",        OPT_UINT,   &cmdlineP->randomseed,
             &cmdlineP->randomseedSpec, 0);
-    OPTENT3(0, "verbose",     OPT_FLAG,   NULL, &cmdlineP->verbose, 0);
-
-    /* Set the defaults */
-    cmdlineP->width = 100;
-    cmdlineP->height = 100;
-    cmdlineP->left = cmdlineP->right = cmdlineP->top = cmdlineP->bottom = -1;
-    cmdlineP->bg_rgb = NULL;
-    cmdlineP->fg_rgb = NULL;
-    cmdlineP->var = 10;
+    OPTENT3(0, "verbose",     OPT_FLAG,   NULL,
+            &cmdlineP->verbose, 0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
@@ -79,6 +86,17 @@ parseCommandLine(int argc, const char ** argv,
 
     pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
 
+    if (!widthSpec)
+        cmdlineP->width = 100;
+    if (!heightSpec)
+        cmdlineP->height = 100;
+    if (!bgSpec)
+        cmdlineP->bg = NULL;
+    if (!fgSpec)
+        cmdlineP->fg = NULL;
+    if (!varSpec)
+        cmdlineP->var = 10;
+
     if (argc-1 != 0)
         pm_error("There are no arguments.  You specified %d.", argc-1);
 
@@ -88,239 +106,340 @@ parseCommandLine(int argc, const char ** argv,
 
 
 static void
-procLeft(int          const r1,
-         int          const r2,
-         int          const c1,
-         int          const c2, 
-         unsigned int const var) {
+reportParameters(struct CmdlineInfo const cmdline,
+                 pixel              const bgcolor,
+                 pixel              const fgcolor) {
+
+    pm_message("width is %d, height is %d, variance is %d.",
+               cmdline.width, cmdline.height, cmdline.var);
+    if (cmdline.leftSpec)
+        pm_message("ragged left border is required");
+    if (cmdline.rightSpec)
+        pm_message("ragged right border is required");
+    if (cmdline.topSpec)
+        pm_message("ragged top border is required");
+    if (cmdline.bottomSpec)
+        pm_message("ragged bottom border is required");
+    pm_message("background is %s",
+               ppm_colorname(&bgcolor, PPM_MAXMAXVAL, 1));
+    pm_message("foreground is %s",
+               ppm_colorname(&fgcolor, PPM_MAXMAXVAL, 1));
+    if (cmdline.randomseedSpec)
+        pm_message("pm_rand() initialized with seed %u",
+                   cmdline.randomseed);
+}
+
+
+
+static void
+makeAllForegroundColor(pixel **     const pixels,
+                       unsigned int const rows,
+                       unsigned int const cols,
+                       pixel        const fgcolor) {
 
-    int cm, rm, c;
+    pixval const r = PPM_GETR(fgcolor);
+    pixval const g = PPM_GETG(fgcolor);
+    pixval const b = PPM_GETB(fgcolor);
 
-    if (r1 + 1 == r2)  return;
-    rm = (r1 + r2) >> 1;
-    cm = (c1 + c2) >> 1;
-    cm += (int)floor(((float)rand() / RAND_MAX - 0.5) * var + 0.5);
+    unsigned int row;
 
-    for (c = 0; c < cm; c++)
-        PPM_ASSIGN(PIX[rm][c], BG_RED, BG_GREEN, BG_BLUE);
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
 
-    procLeft(r1, rm, c1, cm, var);
-    procLeft(rm, r2, cm, c2, var);
+        for (col = 0; col < cols; ++col)
+            PPM_ASSIGN(pixels[row][col], r, g, b);
+    }
 }
 
 
 
 static void
-procRight(int          const r1,
-          int          const r2,
-          int          const c1,
-          int          const c2,
-          unsigned int const width,
-          unsigned int const var) {
+procLeft(pixel **           const pixels,
+         int                const r1,
+         int                const r2,
+         int                const c1,
+         int                const c2,
+         unsigned int       const var,
+         pixel              const bgcolor,
+         struct pm_randSt * const randStP) {
+
+    if (r1 + 1 != r2) {
+        int const rm = (r1 + r2) >> 1;
+        int const cm = ((c1 + c2) >> 1) +
+            (int)floor(((float)pm_rand(randStP) / RAND_MAX - 0.5) * var + 0.5);
+
+        int c;
+
+        for (c = 0; c < cm; c++)
+            pixels[rm][c] = bgcolor;
+
+        procLeft(pixels, r1, rm, c1, cm, var, bgcolor, randStP);
+        procLeft(pixels, rm, r2, cm, c2, var, bgcolor, randStP);
+    }
+}
 
-    int cm, rm, c;
 
-    if (r1 + 1 == r2)  return;
-    rm = (r1 + r2) >> 1;
-    cm = (c1 + c2) >> 1;
-    cm += (int)floor(((float)rand() / RAND_MAX - 0.5) * var + 0.5);
 
-    for (c = cm; c < width; c++)
-        PPM_ASSIGN(PIX[rm][c], BG_RED, BG_GREEN, BG_BLUE);
+static void
+procRight(pixel **           const pixels,
+          int                const r1,
+          int                const r2,
+          int                const c1,
+          int                const c2,
+          unsigned int       const width,
+          unsigned int       const var,
+          pixel              const bgcolor,
+          struct pm_randSt * const randStP) {
+
+    if (r1 + 1 != r2) {
+        int const rm = (r1 + r2) >> 1;
+        int const cm = ((c1 + c2) >> 1) +
+            (int)floor(((float)pm_rand(randStP) / RAND_MAX - 0.5) * var + 0.5);
+
+        int c;
+
+        for (c = cm; c < width; c++)
+            pixels[rm][c] = bgcolor;
+
+        procRight(pixels, r1, rm, c1, cm, width, var, bgcolor, randStP);
+        procRight(pixels, rm, r2, cm, c2, width, var, bgcolor, randStP);
+    }
+}
+
 
-    procRight(r1, rm, c1, cm, width, var);
-    procRight(rm, r2, cm, c2, width, var);
+
+static void
+procTop(pixel **           const pixels,
+        int                const c1,
+        int                const c2,
+        int                const r1,
+        int                const r2,
+        unsigned int       const var,
+        pixel              const bgcolor,
+        struct pm_randSt * const randStP) {
+
+    if (c1 + 1 != c2) {
+        int const cm = (c1 + c2) >> 1;
+        int const rm = ((r1 + r2) >> 1) +
+            (int)floor(((float)pm_rand(randStP) / RAND_MAX - 0.5) * var + 0.5);
+
+        int r;
+
+        for (r = 0; r < rm; r++)
+            pixels[r][cm] = bgcolor;
+
+        procTop(pixels, c1, cm, r1, rm, var, bgcolor, randStP);
+        procTop(pixels, cm, c2, rm, r2, var, bgcolor, randStP);
+    }
 }
 
 
 
 static void
-procTop(int          const c1,
-        int          const c2,
-        int          const r1,
-        int          const r2,
-        unsigned int const var) {
+procBottom(pixel **           const pixels,
+           int                const c1,
+           int                const c2,
+           int                const r1,
+           int                const r2,
+           unsigned int       const height,
+           unsigned int       const var,
+           pixel              const bgcolor,
+           struct pm_randSt * const randStP) {
+
+    if (c1 + 1 != c2) {
+        int const cm = (c1 + c2) >> 1;
+        int const rm = ((r1 + r2) >> 1) +
+            (int)floor(((float)pm_rand(randStP) / RAND_MAX - 0.5) * var + 0.5);
+
+        int r;
+
+        for (r = rm; r < height; ++r)
+            pixels[r][cm] = bgcolor;
+
+        procBottom(pixels, c1, cm, r1, rm, height, var, bgcolor, randStP);
+        procBottom(pixels, cm, c2, rm, r2, height, var, bgcolor, randStP);
+    }
+}
 
-    int rm, cm, r;
 
-    if (c1 + 1 == c2)  return;
-    cm = (c1 + c2) >> 1;
-    rm = (r1 + r2) >> 1;
-    rm += (int)floor(((float)rand() / RAND_MAX - 0.5) * var + 0.5);
 
-    for (r = 0; r < rm; r++)
-        PPM_ASSIGN(PIX[r][cm], BG_RED, BG_GREEN, BG_BLUE);
+static void
+makeRaggedLeftBorder(pixel **           const pixels,
+                     unsigned int       const rows,
+                     unsigned int       const cols,
+                     bool               const leftSpec,
+                     unsigned int       const left,
+                     unsigned int       const var,
+                     pixel              const bgcolor,
+                     struct pm_randSt * const randStP) {
+
+    if (leftSpec) {
+        int const leftC1 = left;
+        int const leftC2 = left;
+        int const leftR1 = 0;
+        int const leftR2 = rows - 1;
+
+        unsigned int col;
+
+        for (col = 0; col < leftC1; ++col)
+            pixels[leftR1][col] = bgcolor;
+        for (col = 0; col < leftC2; ++col)
+            pixels[leftR2][col] = bgcolor;
 
-    procTop(c1, cm, r1, rm, var);
-    procTop(cm, c2, rm, r2, var);
+        procLeft(pixels, leftR1, leftR2, leftC1, leftC2, var,
+                 bgcolor, randStP);
+    }
 }
 
 
 
 static void
-procBottom(int          const c1,
-           int          const c2,
-           int          const r1,
-           int          const r2,
-           unsigned int const height,
-           unsigned int const var) {
-
-    int rm, cm, r;
+makeRaggedRightBorder(pixel **           const pixels,
+                      unsigned int       const rows,
+                      unsigned int       const cols,
+                      bool               const rightSpec,
+                      unsigned int       const right,
+                      unsigned int       const width,
+                      unsigned int       const var,
+                      pixel              const bgcolor,
+                      struct pm_randSt * const randStP) {
+
+    if (rightSpec) {
+        int const rightC1 = cols - right - 1;
+        int const rightC2 = cols - right - 1;
+        int const rightR1 = 0;
+        int const rightR2 = rows - 1;
 
-    if (c1 + 1 == c2)  return;
-    cm = (c1 + c2) >> 1;
-    rm = (r1 + r2) >> 1;
-    rm += (int)floor(((float)rand() / RAND_MAX - 0.5) * var + 0.5);
+        unsigned int col;
 
-    for (r = rm; r < height; r++)
-        PPM_ASSIGN(PIX[r][cm], BG_RED, BG_GREEN, BG_BLUE);
+        for (col = rightC1; col < cols; ++col)
+            pixels[rightR1][col] = bgcolor;
+        for (col = rightC2; col < cols; ++col)
+            pixels[rightR2][col] = bgcolor;
 
-    procBottom(c1, cm, r1, rm, height, var);
-    procBottom(cm, c2, rm, r2, height, var);
+        procRight(pixels, rightR1, rightR2, rightC1, rightC2, width, var,
+                  bgcolor, randStP);
+    }
 }
 
 
 
-int
-main(int argc, const char * argv[]) {
+static void
+makeRaggedTopBorder(pixel **           const pixels,
+                    unsigned int       const rows,
+                    unsigned int       const cols,
+                    bool               const topSpec,
+                    unsigned int       const top,
+                    unsigned int       const var,
+                    pixel              const bgcolor,
+                    struct pm_randSt * const randStP) {
+
+    if (topSpec) {
+        unsigned int const topR1 = top;
+        unsigned int const topR2 = top;
+        unsigned int const topC1 = 0;
+        unsigned int const topC2 = cols - 1;
 
-    struct CmdlineInfo cmdline;
-    pixel bgcolor, fgcolor;
-    pixval fg_red, fg_green, fg_blue;
-    int rows, cols, row;
-    int left, right, top, bottom;
+        unsigned int row;
 
-    pm_proginit(&argc, argv);
+        for (row = 0; row < topR1; ++row)
+            pixels[row][topC1] = bgcolor;
+        for (row = 0; row < topR2; ++row)
+            pixels[row][topC2] = bgcolor;
 
-    parseCommandLine(argc, argv, &cmdline);
+        procTop(pixels, topC1, topC2, topR1, topR2, var, bgcolor, randStP);
+    }
+}
 
-    srand(cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed());
 
-    cols = cmdline.width;
-    rows = cmdline.height;
-    left = cmdline.left;
-    right = cmdline.right;
-    top = cmdline.top;
-    bottom = cmdline.bottom;
 
-    if (cmdline.bg_rgb)
-        bgcolor = ppm_parsecolor(cmdline.bg_rgb, PPM_MAXMAXVAL);
-    else
-        PPM_ASSIGN(bgcolor, 0, 0, 0);
-    BG_RED = PPM_GETR(bgcolor);
-    BG_GREEN = PPM_GETG(bgcolor);
-    BG_BLUE = PPM_GETB(bgcolor);
+static void
+makeRaggedBottomBorder(pixel **            const pixels,
+                       unsigned int        const rows,
+                       unsigned int        const cols,
+                       bool                const bottomSpec,
+                       unsigned int        const bottom,
+                       unsigned int        const height,
+                       unsigned int        const var,
+                       pixel               const bgcolor,
+                       struct pm_randSt *  const randStP) {
+
+    if (bottomSpec) {
+        unsigned int const bottomR1 = rows - bottom - 1;
+        unsigned int const bottomR2 = rows - bottom - 1;
+        unsigned int const bottomC1 = 0;
+        unsigned int const bottomC2 = cols - 1;
 
-    if (cmdline.fg_rgb)
-        fgcolor = ppm_parsecolor(cmdline.fg_rgb, PPM_MAXMAXVAL);
-    else
-        PPM_ASSIGN(fgcolor, PPM_MAXMAXVAL, PPM_MAXMAXVAL, PPM_MAXMAXVAL);
-    fg_red = PPM_GETR(fgcolor);
-    fg_green = PPM_GETG(fgcolor);
-    fg_blue = PPM_GETB(fgcolor);
-
-    if (cmdline.verbose) {
-        pm_message("width is %d, height is %d, variance is %d.", 
-                   cols, rows, cmdline.var);
-        if (left >= 0)
-            pm_message("ragged left border is required");
-        if (right >= 0)
-            pm_message("ragged right border is required");
-        if (top >= 0)
-            pm_message("ragged top border is required");
-        if (bottom >= 0)
-            pm_message("ragged bottom border is required");
-        pm_message("background is %s",
-                   ppm_colorname(&bgcolor, PPM_MAXMAXVAL, 1));
-        pm_message("foreground is %s",
-                   ppm_colorname(&fgcolor, PPM_MAXMAXVAL, 1));
-        if (cmdline.randomseedSpec)
-            pm_message("srand() initialized with seed %u", cmdline.randomseed);
-    }
+        unsigned int row;
 
-    /* Allocate memory for the whole pixmap */
-    PIX = ppm_allocarray(cols, rows);
+        for (row = bottomR1; row < rows; ++row)
+            pixels[row][bottomC1] = bgcolor;
+        for (row = bottomR2; row < rows; ++row)
+            pixels[row][bottomC2] = bgcolor;
 
-    /* First, set all pixel to foreground color */
-    for (row = 0; row < rows; row++) {
-        unsigned int col;
-        for (col = 0; col < cols; ++col)
-            PPM_ASSIGN(PIX[row][col], fg_red, fg_green, fg_blue);
+        procBottom(pixels, bottomC1, bottomC2, bottomR1, bottomR2,
+                   height, var, bgcolor, randStP);
     }
-    /* Make a ragged left border */
-    if (left >= 0) {
-        int const left_c1 = left;
-        int const left_c2 = left;
-        int const left_r1 = 0;
-        int const left_r2 = rows - 1;
+}
 
-        unsigned int col;
 
-        for (col = 0; col < left_c1; ++col)
-            PPM_ASSIGN(PIX[left_r1][col], BG_RED, BG_GREEN, BG_BLUE);
-        for (col = 0; col < left_c2; ++col)
-            PPM_ASSIGN(PIX[left_r2][col], BG_RED, BG_GREEN, BG_BLUE);
 
-        procLeft(left_r1, left_r2, left_c1, left_c2, cmdline.var);
-    }
+int
+main(int argc, const char ** const argv) {
 
-    /* Make a ragged right border */
-    if (right >= 0) {
-        int const right_c1 = cols - right - 1;
-        int const right_c2 = cols - right - 1;
-        int const right_r1 = 0;
-        int const right_r2 = rows - 1;
+    struct CmdlineInfo cmdline;
+    pixel bgcolor, fgcolor;
+    struct pm_randSt randSt;
+    static pixel** pixels;
 
-        unsigned int col;
+    pm_proginit(&argc, argv);
 
-        for (col = right_c1; col < cols; col++)
-            PPM_ASSIGN(PIX[right_r1][col], BG_RED, BG_GREEN, BG_BLUE);
-        for (col = right_c2; col < cols; col++)
-            PPM_ASSIGN(PIX[right_r2][col], BG_RED, BG_GREEN, BG_BLUE);
+    parseCommandLine(argc, argv, &cmdline);
 
-        procRight(right_r1, right_r2, right_c1, right_c2, 
-                   cmdline.width, cmdline.var);
-    }
+    pm_randinit(&randSt);
+    pm_srand(&randSt,
+             cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed());
 
-    /* Make a ragged top border */
-    if (top >= 0) {
-        int const top_r1 = top;
-        int const top_r2 = top;
-        int const top_c1 = 0;
-        int const top_c2 = cols - 1;
+    if (cmdline.bg)
+        bgcolor = ppm_parsecolor(cmdline.bg, PPM_MAXMAXVAL);
+    else
+        PPM_ASSIGN(bgcolor, 0, 0, 0);
 
-        unsigned int row;
+    if (cmdline.fg)
+        fgcolor = ppm_parsecolor(cmdline.fg, PPM_MAXMAXVAL);
+    else
+        PPM_ASSIGN(fgcolor, PPM_MAXMAXVAL, PPM_MAXMAXVAL, PPM_MAXMAXVAL);
 
-        for (row = 0; row < top_r1; ++row)
-            PPM_ASSIGN(PIX[row][top_c1], BG_RED, BG_GREEN, BG_BLUE);
-        for (row = 0; row < top_r2; ++row)
-            PPM_ASSIGN(PIX[row][top_c2], BG_RED, BG_GREEN, BG_BLUE);
+    if (cmdline.verbose)
+        reportParameters(cmdline, bgcolor, fgcolor);
 
-        procTop(top_c1, top_c2, top_r1, top_r2, cmdline.var);
-    }
+    pixels = ppm_allocarray(cmdline.width, cmdline.height);
 
-    /* Make a ragged bottom border */
-    if (bottom >= 0) {
-        int const bottom_r1 = rows - bottom - 1;
-        int const bottom_r2 = rows - bottom - 1;
-        int const bottom_c1 = 0;
-        int const bottom_c2 = cols - 1;
+    makeAllForegroundColor(pixels, cmdline.height, cmdline.width, fgcolor);
 
-        unsigned int row;
+    makeRaggedLeftBorder(pixels, cmdline.height, cmdline.width,
+                         cmdline.leftSpec, cmdline.left,
+                         cmdline.var, bgcolor, &randSt);
 
-        for (row = bottom_r1; row < rows; ++row)
-            PPM_ASSIGN(PIX[row][bottom_c1], BG_RED, BG_GREEN, BG_BLUE);
-        for (row = bottom_r2; row < rows; ++row)
-            PPM_ASSIGN(PIX[row][bottom_c2], BG_RED, BG_GREEN, BG_BLUE);
+    makeRaggedRightBorder(pixels, cmdline.height, cmdline.width,
+                          cmdline.rightSpec, cmdline.right,
+                          cmdline.width, cmdline.var, bgcolor, &randSt);
 
-        procBottom(bottom_c1, bottom_c2, bottom_r1, bottom_r2, 
-                   cmdline.height, cmdline.var);
-    }
+    makeRaggedTopBorder(pixels, cmdline.height, cmdline.width,
+                        cmdline.topSpec, cmdline.top,
+                        cmdline.var, bgcolor, &randSt);
+
+    makeRaggedBottomBorder(pixels, cmdline.height, cmdline.width,
+                           cmdline.bottomSpec, cmdline.bottom,
+                           cmdline.height, cmdline.var, bgcolor, &randSt);
+
+    pm_randterm(&randSt);
 
     /* Write pixmap */
-    ppm_writeppm(stdout, PIX, cols, rows, PPM_MAXMAXVAL, 0);
+    ppm_writeppm(stdout, pixels, cmdline.width, cmdline.height,
+                 PPM_MAXMAXVAL, 0);
 
-    ppm_freearray(PIX, rows);
+    ppm_freearray(pixels, cmdline.height);
 
     pm_close(stdout);
 
@@ -328,4 +447,3 @@ main(int argc, const char * argv[]) {
 }
 
 
-
diff --git a/lib/Makefile b/lib/Makefile
index bc758df4..5040e40f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -33,7 +33,6 @@ LIBOBJECTS = libpm.o pmfileio.o fileio.o colorname.o \
 	libpgm1.o libpgm2.o \
 	libppm1.o libppm2.o libppmcmap.o libppmcolor.o libppmfuzzy.o \
 	libppmd.o ppmdfont.o standardppmdfont.o path.o \
-	libppmfloyd.o \
 	libpnm1.o libpnm2.o libpnm3.o \
 	libpam.o libpamread.o libpamwrite.o \
 	libpamn.o libpammap.o libpamcolor.o \
@@ -48,6 +47,10 @@ LIBOBJECTS_X = \
   util/matrix.o \
   util/nsleep.o \
   util/nstring.o \
+  util/rand.o \
+  util/randsysrand.o \
+  util/randsysrandom.o \
+  util/randmersenne.o \
   util/runlength.o \
   util/shhopt.o \
   util/token.o \
@@ -59,7 +62,7 @@ MANUALS5 = pbm pgm ppm pnm pam
 INTERFACE_HEADERS = colorname.h \
 	pam.h pamdraw.h pammap.h pbm.h pbmfont.h pbmfontdata.h \
 	pgm.h pm.h pm_gamma.h pm_system.h pnm.h \
-	ppm.h ppmcmap.h ppmdfont.h ppmdraw.h ppmfloyd.h \
+	ppm.h ppmcmap.h ppmdfont.h ppmdraw.h \
 	util/mallocvar.h util/runlength.h util/shhopt.h \
 
 DATAFILES = rgb.txt
@@ -96,8 +99,30 @@ libpbm3.o: CFLAGS_TARGET+=$(CFLAGS_SSE)
 $(LIBOBJECTS): %.o: %.c importinc
 	$(CC) -c $(INCLUDES) $(CFLAGS_ALL) -o $@ $<
 
-MAJ = 11
-MIN = $(NETPBM_MINOR_RELEASE)
+# The major number increases when there is a non-backward-compatible change
+# to the library at the binary level, meaning any client of the library needs
+# to keep using the old library until it has been recompiled for the new
+# library.  We try very hard never to lose backward compatibility at the
+# source level, which would mean the client source code has to be modified
+# before it can use the new library.
+#
+# The major number might seem like it corresponds to the major version number
+# of Netpbm, but it does not.  It is independent.
+#
+# Adding functions is backward compatible, so does not require a major number
+# change.
+#
+# The minor number must always increase within a major number.
+#
+# It is convenient to have the minor number equal to the minor version number
+# of Netpbm, but when we changed the Netpbm major version number from 10 to 11
+# just to keep the minor version number 2 digits, we had to continue
+# increasing the library minor number, so we went to 100 + minor version
+# number.  If we ever increase the major number to 12, we can go back to using
+# the minor version number for the library minor number.
+
+MAJ := 11
+$(eval MIN:=$(shell echo $$((100+$(NETPBM_MINOR_RELEASE)))))
 
 SONAME = libnetpbm.$(NETPBMLIBSUFFIX).$(MAJ)
 
diff --git a/lib/fileio.h b/lib/fileio.h
index 586c8265..2a0efbbc 100644
--- a/lib/fileio.h
+++ b/lib/fileio.h
@@ -13,12 +13,12 @@ unsigned int
 pm_getuint(FILE * const file);
 
 unsigned int
-pm_getraw(FILE *       const file, 
+pm_getraw(FILE *       const file,
           unsigned int const bytes);
 
 void
-pm_putraw(FILE *       const file, 
-          unsigned int const value, 
+pm_putraw(FILE *       const file,
+          unsigned int const value,
           unsigned int const bytes);
 
 #endif
diff --git a/lib/libpam.c b/lib/libpam.c
index a8f140b3..a01dd596 100644
--- a/lib/libpam.c
+++ b/lib/libpam.c
@@ -90,7 +90,12 @@ validateComputableSize(struct pam * const pamP) {
    the size of a tuple row, in bytes, can be represented by an 'int'.
 
    Another common operation is adding 1 or 2 to the highest row, column,
-   or plane number in the image, so we make sure that's possible.
+   or plane number in the image, so we make sure that's possible.  And in
+   bitmap images, rounding up to multiple of 8 is common, so we provide for
+   that too.
+
+   Note that it's still the programmer's responsibility to ensure that his
+   code, using values known to have been validated here, cannot overflow.
 -----------------------------------------------------------------------------*/
     if (pamP->width == 0)
         pm_error("Width is zero.  Image must be at least one pixel wide");
@@ -111,10 +116,10 @@ validateComputableSize(struct pam * const pamP) {
 
         if (depth > INT_MAX - 2)
             pm_error("image depth (%u) too large to be processed", depth);
-        if (pamP->width > INT_MAX - 2)
+        if (pamP->width > INT_MAX - 10)
             pm_error("image width (%u) too large to be processed",
                      pamP->width);
-        if (pamP->height > INT_MAX - 2)
+        if (pamP->height > INT_MAX - 10)
             pm_error("image height (%u) too large to be processed",
                      pamP->height);
     }
@@ -211,6 +216,24 @@ pnm_createBlackTuple(const struct pam * const pamP,
 
 
 
+void
+pnm_createWhiteTuple(const struct pam * const pamP,
+                     tuple *            const whiteTupleP) {
+/*----------------------------------------------------------------------------
+   Create a "white" tuple.  By that we mean a tuple all of whose elements are
+   the maxval.  If it's an RGB, grayscale, or b&w pixel, that means it's
+   white.
+-----------------------------------------------------------------------------*/
+    unsigned int i;
+
+    *whiteTupleP = pnm_allocpamtuple(pamP);
+
+    for (i = 0; i < pamP->depth; ++i)
+        (*whiteTupleP)[i] = pamP->maxval;
+}
+
+
+
 static tuple *
 allocPamRow(const struct pam * const pamP) {
 /*----------------------------------------------------------------------------
@@ -405,9 +428,9 @@ pnm_setpamrow(const struct pam * const pamP,
               tuple *            const tuplerow,
               sample             const value) {
 
-    int col;
+    unsigned int col;
     for (col = 0; col < pamP->width; ++col) {
-        int plane;
+        unsigned int plane;
         for (plane = 0; plane < pamP->depth; ++plane)
             tuplerow[col][plane] = value;
     }
@@ -416,46 +439,72 @@ pnm_setpamrow(const struct pam * const pamP,
 
 
 
+static void
+setSeekableAndRasterPos(struct pam * const pamP) {
+
+    if (pamP->size >= PAM_STRUCT_SIZE(is_seekable))
+        pamP->is_seekable = pm_is_seekable(pamP->file);
+
+    if (pamP->size >= PAM_STRUCT_SIZE(raster_pos)) {
+        if (pamP->is_seekable)
+            pm_tell2(pamP->file, &pamP->raster_pos, sizeof(pamP->raster_pos));
+    }
+}
+
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstringop-truncation"
+
 #define MAX_LABEL_LENGTH 8
 #define MAX_VALUE_LENGTH 255
 
 static void
-parseHeaderLine(const char buffer[],
-                char label[MAX_LABEL_LENGTH+1],
-                char value[MAX_VALUE_LENGTH+1]) {
-
-    int buffer_curs;
+parseHeaderLine(const char * const buffer,
+                char *       const label,
+                char *       const value) {
+/*----------------------------------------------------------------------------
+   We truncate the label to MAX_LABEL_LENGTH and the value to
+   MAX_VALUE_LENGTH.  There must be at least that much space (plus space
+   for a terminating NUL) at 'label' and 'value', respectively.
+-----------------------------------------------------------------------------*/
+    unsigned int bufferCurs;
 
-    buffer_curs = 0;
     /* Skip initial white space */
-    while (ISSPACE(buffer[buffer_curs])) buffer_curs++;
+    for (bufferCurs = 0; ISSPACE(buffer[bufferCurs]); ++bufferCurs) {}
 
     {
         /* Read off label, put as much as will fit into label[] */
-        int label_curs;
-        label_curs = 0;
-        while (!ISSPACE(buffer[buffer_curs]) && buffer[buffer_curs] != '\0') {
-            if (label_curs < MAX_LABEL_LENGTH)
-                label[label_curs++] = buffer[buffer_curs];
-            buffer_curs++;
+        unsigned int labelCurs;
+
+        for (labelCurs = 0;
+             !ISSPACE(buffer[bufferCurs]) && buffer[bufferCurs] != '\0';
+             ++bufferCurs) {
+            if (labelCurs < MAX_LABEL_LENGTH)
+                label[labelCurs++] = buffer[bufferCurs];
         }
-        label[label_curs] = '\0';  /* null terminate it */
+        label[labelCurs] = '\0';  /* null terminate it */
     }
 
     /* Skip white space between label and value */
-    while (ISSPACE(buffer[buffer_curs])) buffer_curs++;
+    while (ISSPACE(buffer[bufferCurs]))
+        ++bufferCurs;
 
-    /* copy value into value[] */
-    strncpy(value, buffer+buffer_curs, MAX_VALUE_LENGTH+1);
+    /* copy value into value[], truncating as necessary */
+    strncpy(value, buffer+bufferCurs, MAX_VALUE_LENGTH);
+    value[MAX_VALUE_LENGTH] = '\0';
 
     {
         /* Remove trailing white space from value[] */
-        int value_curs;
-        value_curs = strlen(value)-1;
-        while (value_curs >= 0 && ISSPACE(value[value_curs]))
-            value[value_curs--] = '\0';
+        unsigned int valueCurs;
+
+        for (valueCurs = strlen(value);
+             valueCurs > 0 && ISSPACE(value[valueCurs-1]);
+             --valueCurs);
+
+        value[valueCurs] = '\0';
     }
 }
+#pragma GCC diagnostic pop
 
 
 
@@ -936,6 +985,8 @@ pnm_readpaminit(FILE *       const file,
     pamP->plainformat = FALSE;
         /* See below for complex explanation of why this is FALSE. */
 
+    setSeekableAndRasterPos(pamP);
+
     interpretTupleType(pamP);
 
     validateComputableSize(pamP);
@@ -1044,8 +1095,6 @@ pnm_writepaminit(struct pam * const pamP) {
 
     interpretTupleType(pamP);
 
-    pamP->len = MIN(pamP->size, PAM_STRUCT_SIZE(opacity_plane));
-
     switch (PAM_FORMAT_TYPE(pamP->format)) {
     case PAM_TYPE:
         /* See explanation below of why we ignore 'pm_plain_output' here. */
@@ -1104,6 +1153,10 @@ pnm_writepaminit(struct pam * const pamP) {
         pm_error("Invalid format passed to pnm_writepaminit(): %d",
                  pamP->format);
     }
+
+    setSeekableAndRasterPos(pamP);
+
+    pamP->len = MIN(pamP->size, PAM_STRUCT_SIZE(raster_pos));
 }
 
 
@@ -1385,6 +1438,66 @@ pnm_backgroundtuple(struct pam *  const pamP,
 
 
 
+tuple
+pnm_backgroundtuplerow(const struct pam * const pamP,
+                       tuple            * const tuplerow) {
+/*-----------------------------------------------------------------------------
+  Guess a good background color for an image that contains row 'tuplerow'
+  (probably top or bottom edge), described by *pamP.
+
+  This function was copied from libpnm3.c's pnm_backgroundxelrow() and
+  modified to use tuples instead of xels.
+-----------------------------------------------------------------------------*/
+    tuple bgtuple;
+
+    bgtuple = pnm_allocpamtuple(pamP);
+
+    assert(pamP->width > 0);
+
+    if (pamP->width == 1)
+        pnm_assigntuple(pamP, bgtuple, tuplerow[0]);
+    else {
+        tuple const l = tuplerow[0];
+        tuple const r = tuplerow[pamP->width-1];
+
+        if (pnm_tupleequal(pamP, l, r)) {
+            /* Both corners are same color, so that's the background color,
+               without any extra computation.
+            */
+            pnm_assigntuple(pamP, bgtuple, l);
+        } else {
+            /* Corners are different */
+
+            if (pamP->depth == 1 && pamP->maxval == 1) {
+                /* It's black and white, with one corner black, the other
+                   white.  We consider whichever color is most prevalent in
+                   the row the background color.
+                */
+                unsigned int col;
+                unsigned int blackCt;
+
+                for (col = 0, blackCt = 0; col < pamP->width; ++col) {
+                    if (tuplerow[col] == 0)
+                        ++blackCt;
+                }
+                if (blackCt > pamP->width / 2)
+                    bgtuple[0] = 0;
+                else
+                    bgtuple[0] = pamP->maxval;
+            } else {
+                /* Use the cartesian mean of the two corner colors */
+                unsigned int plane;
+
+                for (plane = 0; plane < pamP->depth; ++plane)
+                    bgtuple[plane] = (l[plane] + r[plane])/2;
+            }
+        }
+    }
+    return bgtuple;
+}
+
+
+
 /*=============================================================================
    pm_system() Standard Input feeder and Standard Output accepter functions.
 =============================================================================*/
@@ -1424,3 +1537,6 @@ pm_accept_to_pamtuples(int    const pipeToSuckFd,
 
     pm_close(inpamP->file);
 }
+
+
+
diff --git a/lib/libpamcolor.c b/lib/libpamcolor.c
index 39ff793b..cc68fe1a 100644
--- a/lib/libpamcolor.c
+++ b/lib/libpamcolor.c
@@ -177,15 +177,15 @@ parseInteger(const char * const colorname,
 
     if (r > maxval)
         pm_error("Red value in color specification '%s' is %u, "
-                 "whcih is invalid because the specified maxval is %u",
+                 "which is invalid because the specified maxval is %u",
                  colorname, r, maxval);
     if (g > maxval)
         pm_error("Green value in color specification '%s' is %u, "
-                 "whcih is invalid because the specified maxval is %u",
+                 "which is invalid because the specified maxval is %u",
                  colorname, g, maxval);
     if (b > maxval)
         pm_error("Blue value in color specification '%s' is %u, "
-                 "whcih is invalid because the specified maxval is %u",
+                 "which is invalid because the specified maxval is %u",
                  colorname, b, maxval);
 
     color[PAM_RED_PLANE] = (float)r/maxval;
diff --git a/lib/libpamd.c b/lib/libpamd.c
index 952150b4..2b9eb693 100644
--- a/lib/libpamd.c
+++ b/lib/libpamd.c
@@ -1,4 +1,4 @@
-/* 
+/*
 **
 ** This library module contains the pamdraw routines.
 **
@@ -12,7 +12,7 @@
 ** copyright notice and this permission notice appear in supporting
 ** documentation.  This software is provided "as is" without express or
 ** implied warranty.
-** 
+**
 ** The character drawing routines are by John Walker
 ** Copyright (C) 1994 by John Walker, kelvin@fourmilab.ch
 */
@@ -89,7 +89,7 @@ pointIsWithinBounds(pamd_point   const p,
     return (p.x >= 0 && p.x < cols && p.y >= 0 && p.y < rows);
 }
 
-        
+
 
 static pamd_point
 vectorSum(pamd_point const a,
@@ -106,7 +106,7 @@ static long int const DDA_SCALE = 8192;
 /*
   Several factors govern the limit of x, y coordination values.
 
-  The limit must be representable as (signed) int for coordinates to 
+  The limit must be representable as (signed) int for coordinates to
   be carried in struct penpos (immediately above).
 
   The following calculation, done with long ints, must not overflow:
@@ -116,7 +116,7 @@ static long int const DDA_SCALE = 8192;
   dy = (y1 - y0) * DDA_SCALE / abs(x1 - x0);
 
   Overflow conditions for pamd_text are rather complicated, for commands
-  come from an external PPMD font file.  See comments below.  
+  come from an external PPMD font file.  See comments below.
 */
 
 
@@ -145,11 +145,11 @@ pamd_validatePoint(pamd_point const p) {
 static void
 drawPoint(pamd_drawproc       drawproc,
           const void *  const clientdata,
-          tuple **      const tuples, 
-          int           const cols, 
-          int           const rows, 
-          int           const depth, 
-          sample        const maxval, 
+          tuple **      const tuples,
+          int           const cols,
+          int           const rows,
+          int           const depth,
+          sample        const maxval,
           pamd_point    const p) {
 /*----------------------------------------------------------------------------
    Draw a single point, assuming that it is within the bounds of the
@@ -171,16 +171,16 @@ drawPoint(pamd_drawproc       drawproc,
 
 
 void
-pamd_point_drawproc(tuple **     const tuples, 
-                    unsigned int const cols, 
-                    unsigned int const rows, 
-                    unsigned int const depth, 
-                    sample       const maxval, 
+pamd_point_drawproc(tuple **     const tuples,
+                    unsigned int const cols,
+                    unsigned int const rows,
+                    unsigned int const depth,
+                    sample       const maxval,
                     pamd_point   const p,
                     const void * const clientdata) {
 
     unsigned int i;
-    
+
     if ((p.x >= 0) && (p.x < cols) && (p.y >= 0) && (p.y < rows))
         for (i = 0; i < depth; ++i)
             tuples[p.y][p.x][i] = (sample) *((tuple *) clientdata + i);
@@ -216,15 +216,15 @@ findRectangleIntersection(struct rectangle   const rect1,
 
 
 void
-pamd_filledrectangle(tuple **      const tuples, 
-                     int           const cols, 
-                     int           const rows, 
-                     int           const depth, 
-                     sample        const maxval, 
-                     int           const left, 
-                     int           const top, 
-                     int           const width, 
-                     int           const height, 
+pamd_filledrectangle(tuple **      const tuples,
+                     int           const cols,
+                     int           const rows,
+                     int           const depth,
+                     sample        const maxval,
+                     int           const left,
+                     int           const top,
+                     int           const width,
+                     int           const height,
                      pamd_drawproc       drawProc,
                      const void *  const clientdata) {
 
@@ -390,16 +390,16 @@ clipEnd1(pamd_point   const p0,
    at 0.
 -----------------------------------------------------------------------------*/
     pamd_point c1;
-        /* The current clipped location of p1; we clip it multile times
+        /* The current clipped location of p1; we clip it multiple times
            to get the final location.
         */
     /* p0 is in the frame: */
     assert(p0.x >= 0 && p0.x < cols);
     assert(p0.y >= 0 && p0.y < rows);
-    
+
     /* Clip End 1 of the line horizontally */
     c1 = p1;  /* initial value */
-    
+
     if (c1.x < 0) {
         /* We know the line isn't vertical, since End 0 is in the frame
            and End 1 is left of frame.
@@ -413,7 +413,7 @@ clipEnd1(pamd_point   const p0,
         c1.y = c1.y + (p0.y - c1.y) * (cols - 1 - c1.x) / (p0.x - c1.x);
         c1.x = cols - 1;
     }
-    
+
     /* Clip End 1 of the line vertically */
     if (c1.y < 0) {
         /* We know the line isn't horizontal, since End 0 is in the frame
@@ -477,11 +477,11 @@ clipLine(pamd_point   const p0,
 static void
 drawShallowLine(pamd_drawproc       drawProc,
                 const void *  const clientdata,
-                tuple **      const tuples, 
-                int           const cols, 
-                int           const rows, 
-                int           const depth, 
-                sample        const maxval, 
+                tuple **      const tuples,
+                int           const cols,
+                int           const rows,
+                int           const depth,
+                sample        const maxval,
                 pamd_point    const p0,
                 pamd_point    const p1) {
 /*----------------------------------------------------------------------------
@@ -526,11 +526,11 @@ drawShallowLine(pamd_drawproc       drawProc,
 static void
 drawSteepLine(pamd_drawproc       drawProc,
               const void *  const clientdata,
-              tuple **      const tuples, 
-              int           const cols, 
-              int           const rows, 
+              tuple **      const tuples,
+              int           const cols,
+              int           const rows,
               int           const depth,
-              sample        const maxval, 
+              sample        const maxval,
               pamd_point    const p0,
               pamd_point    const p1) {
 /*----------------------------------------------------------------------------
@@ -574,11 +574,11 @@ drawSteepLine(pamd_drawproc       drawProc,
 
 
 void
-pamd_line(tuple **      const tuples, 
-          int           const cols, 
-          int           const rows, 
-          int           const depth, 
-          sample        const maxval, 
+pamd_line(tuple **      const tuples,
+          int           const cols,
+          int           const rows,
+          int           const depth,
+          sample        const maxval,
           pamd_point    const p0,
           pamd_point    const p1,
           pamd_drawproc       drawProc,
@@ -639,11 +639,11 @@ distanceFromLine(pamd_point const p,
 
 
 void
-pamd_spline3(tuple **      const tuples, 
-             int           const cols, 
-             int           const rows, 
-             int           const depth, 
-             sample        const maxval, 
+pamd_spline3(tuple **      const tuples,
+             int           const cols,
+             int           const rows,
+             int           const depth,
+             sample        const maxval,
              pamd_point    const p0,
              pamd_point    const ctl,
              pamd_point    const p1,
@@ -679,11 +679,11 @@ pamd_spline3(tuple **      const tuples,
 
 
 void
-pamd_polyspline(tuple **      const tuples, 
-                unsigned int  const cols, 
-                unsigned int  const rows, 
-                unsigned int  const depth, 
-                sample        const maxval, 
+pamd_polyspline(tuple **      const tuples,
+                unsigned int  const cols,
+                unsigned int  const rows,
+                unsigned int  const depth,
+                sample        const maxval,
                 pamd_point    const p0,
                 unsigned int  const nc,
                 pamd_point *  const c,
@@ -692,7 +692,7 @@ pamd_polyspline(tuple **      const tuples,
                 const void *  const clientdata) {
 
     pamd_point p;
-    
+
     unsigned int i;
 
     assert(nc > 0);
@@ -713,11 +713,11 @@ pamd_polyspline(tuple **      const tuples,
 
 
 void
-pamd_spline4(tuple **      const tuples, 
-             unsigned int  const cols, 
-             unsigned int  const rows, 
-             unsigned int  const depth, 
-             sample        const maxval, 
+pamd_spline4(tuple **      const tuples,
+             unsigned int  const cols,
+             unsigned int  const rows,
+             unsigned int  const depth,
+             sample        const maxval,
              pamd_point    const endPt0,
              pamd_point    const endPt1,
              pamd_point    const ctlPt0,
@@ -739,13 +739,13 @@ pamd_spline4(tuple **      const tuples,
 
 
 void
-pamd_circle(tuple **      const tuples, 
-            unsigned int  const cols, 
-            unsigned int  const rows, 
-            unsigned int  const depth, 
-            sample        const maxval, 
+pamd_circle(tuple **      const tuples,
+            unsigned int  const cols,
+            unsigned int  const rows,
+            unsigned int  const depth,
+            sample        const maxval,
             pamd_point    const center,
-            unsigned int  const radius, 
+            unsigned int  const radius,
             pamd_drawproc       drawProc,
             const void *  const clientData) {
 /*----------------------------------------------------------------------------
@@ -755,7 +755,7 @@ pamd_circle(tuple **      const tuples,
   it might maintain state that is affected by imaginary points outside
   the image.
 
-  Initial point is 3 o'clock. 
+  Initial point is 3 o'clock.
 -----------------------------------------------------------------------------*/
     if (radius >= DDA_SCALE)
         pm_error("Error drawing circle.  Radius %d is too large.", radius);
@@ -869,11 +869,11 @@ pamd_fill_create(void) {
     stateP->curedge = 0;
 
     fillObjP->stateP = stateP;
-    
+
     /* Turn off line clipping. */
     /* UGGH! We must eliminate this global variable */
     oldclip = pamd_setlineclip(0);
-    
+
     return fillObjP;
 }
 
@@ -969,11 +969,11 @@ continueSegment(struct fillState * const stateP,
 */
 
 void
-pamd_fill_drawproc(tuple **     const tuples, 
-                   unsigned int const cols, 
-                   unsigned int const rows, 
-                   unsigned int const depth, 
-                   sample       const maxval, 
+pamd_fill_drawproc(tuple **     const tuples,
+                   unsigned int const cols,
+                   unsigned int const rows,
+                   unsigned int const depth,
+                   sample       const maxval,
                    pamd_point   const p,
                    const void * const clientdata) {
 
@@ -1029,7 +1029,7 @@ yxCompare(const void * const c1Arg,
     pamd_point const p2 = c2P->point;
 
     int retval;
-    
+
     if (p1.y > p2.y)
         retval = 1;
     else if (p1.y < p2.y)
@@ -1047,15 +1047,15 @@ yxCompare(const void * const c1Arg,
 
 
 void
-pamd_fill(tuple **         const tuples, 
-          int              const cols, 
-          int              const rows, 
-          int              const depth, 
-          sample           const maxval, 
+pamd_fill(tuple **         const tuples,
+          int              const cols,
+          int              const rows,
+          int              const depth,
+          sample           const maxval,
           struct fillobj * const fillObjP,
           pamd_drawproc          drawProc,
           const void *     const clientdata) {
-    
+
     struct fillState * const fh = fillObjP->stateP;
 
     int pedge;
@@ -1222,7 +1222,7 @@ icos(int const deg) {
   times the cosine
 -----------------------------------------------------------------------------*/
     return isin(deg + 90);
-}  
+}
 
 
 
@@ -1294,7 +1294,7 @@ textPosFromFontPos(pamd_point   const fontPos,
         /* Position relative to the top left of the whole text box,
            assuming the text box is horizontal and has font scale.
         */
-    
+
     pamd_point const ps = makePoint((pl.x * (int)height) / Scalef,
                                     (pl.y * (int)height) / Scalef);
          /* Same as above, but with the text box its actual size */
@@ -1344,7 +1344,7 @@ drawGlyph(const struct ppmd_glyph * const glyphP,
   text box, in the coordinate system of the canvas.  'rotcos' and 'rotsin'
   tell how that text box is rotated with respect to the horizontal on the
   canvas.
-  
+
   'height' is the height in canvas tuples of a glyph.  This is a scale factor
   to convert font coordinates to canvas coordinates.
 -----------------------------------------------------------------------------*/
@@ -1384,7 +1384,7 @@ drawGlyph(const struct ppmd_glyph * const glyphP,
                                                     glyphOrigin,
                                                     height,
                                                     rotcos, rotsin);
-                                                    
+
             pamd_line(tuples, cols, rows, depth, maxval, p, n,
                       drawProc, clientdata);
 
@@ -1407,15 +1407,15 @@ drawGlyph(const struct ppmd_glyph * const glyphP,
 
 
 void
-pamd_text(tuple**       const tuples, 
-          int           const cols, 
-          int           const rows, 
-          int           const depth, 
-          sample        const maxval, 
+pamd_text(tuple**       const tuples,
+          int           const cols,
+          int           const rows,
+          int           const depth,
+          sample        const maxval,
           pamd_point    const pos,
-          int           const height, 
-          int           const angle, 
-          const char *  const sArg, 
+          int           const height,
+          int           const angle,
+          const char *  const sArg,
           pamd_drawproc       drawProc,
           const void *  const clientdata) {
 /*----------------------------------------------------------------------------
@@ -1451,7 +1451,7 @@ pamd_text(tuple**       const tuples,
 
             unsigned int cursorAdvance;
 
-            pamd_validatePoint(p); 
+            pamd_validatePoint(p);
 
             drawGlyph(glyphP, p, tuples, cols, rows, depth, maxval,
                       height, pos, rotcos, rotsin,
@@ -1471,12 +1471,12 @@ pamd_text(tuple**       const tuples,
 static pamd_drawproc extetnsDrawproc;
 #endif
 
-static void 
-extentsDrawproc(tuple**      const tuples, 
-                unsigned int const cols, 
+static void
+extentsDrawproc(tuple**      const tuples,
+                unsigned int const cols,
                 unsigned int const rows,
                 unsigned int const depth,
-                sample       const maxval, 
+                sample       const maxval,
                 pamd_point   const p,
                 const void * const clientdata) {
 /*----------------------------------------------------------------------------
@@ -1492,12 +1492,12 @@ extentsDrawproc(tuple**      const tuples,
 
 
 void
-pamd_text_box(int          const height, 
-              int          const angle, 
-              const char * const s, 
-              int *        const leftP, 
-              int *        const topP, 
-              int *        const rightP, 
+pamd_text_box(int          const height,
+              int          const angle,
+              const char * const s,
+              int *        const leftP,
+              int *        const topP,
+              int *        const rightP,
               int *        const bottomP) {
 /*----------------------------------------------------------------------------
   Calculate extents rectangle for a given piece of text.  For most
@@ -1511,10 +1511,10 @@ pamd_text_box(int          const height,
     extbottom = -32767;
 
     pamd_text(NULL, 32767, 32767, 255, 255, makePoint(1000, 1000),
-              height, angle, s, 
+              height, angle, s,
               extentsDrawproc, NULL);
 
-    *leftP   = extleft   - 1000; 
+    *leftP   = extleft   - 1000;
     *topP    = exttop    - 1000;
     *rightP  = extright  - 1000;
     *bottomP = extbottom - 1000;
diff --git a/lib/libpammap.c b/lib/libpammap.c
index 22224913..569156fe 100644
--- a/lib/libpammap.c
+++ b/lib/libpammap.c
@@ -64,7 +64,7 @@ pnm_createtuplehash(void) {
         pm_error("Out of memory allocating tuple hash of size %u",
                  HASH_SIZE);
 
-    for (i = 0; i < HASH_SIZE; ++i) 
+    for (i = 0; i < HASH_SIZE; ++i)
         retval[i] = NULL;
 
     return retval;
@@ -82,13 +82,13 @@ pnm_destroytuplehash(tuplehash const tuplehash) {
     for (i = 0; i < HASH_SIZE; ++i) {
         struct tupleint_list_item * p;
         struct tupleint_list_item * next;
-        
+
         /* Walk this chain, freeing each element */
         for (p = tuplehash[i]; p; p = next) {
             next = p->next;
 
             free(p);
-        }            
+        }
     }
 
     /* Free the table of chains */
@@ -98,18 +98,18 @@ pnm_destroytuplehash(tuplehash const tuplehash) {
 
 
 
-static struct tupleint_list_item * 
+static struct tupleint_list_item *
 allocTupleIntListItem(struct pam * const pamP) {
 
 
-    /* This is complicated by the fact that the last element of a 
+    /* This is complicated by the fact that the last element of a
        tupleint_list_item is of variable length, because the last element
-       of _it_ is of variable length 
+       of _it_ is of variable length
     */
     struct tupleint_list_item * retval;
 
-    unsigned int const size = 
-        sizeof(*retval) - sizeof(retval->tupleint.tuple) 
+    unsigned int const size =
+        sizeof(*retval) - sizeof(retval->tupleint.tuple)
         + pamP->depth * sizeof(sample);
 
     retval = (struct tupleint_list_item *) malloc(size);
@@ -121,7 +121,7 @@ allocTupleIntListItem(struct pam * const pamP) {
 
 void
 pnm_addtotuplehash(struct pam *   const pamP,
-                   tuplehash      const tuplehash, 
+                   tuplehash      const tuplehash,
                    tuple          const tupletoadd,
                    int            const value,
                    int *          const fitsP) {
@@ -138,7 +138,7 @@ pnm_addtotuplehash(struct pam *   const pamP,
         *fitsP = FALSE;
     else {
         unsigned int const hashvalue = pnm_hashtuple(pamP, tupletoadd);
-    
+
         *fitsP = TRUE;
 
         pnm_assigntuple(pamP, listItemP->tupleint.tuple, tupletoadd);
@@ -151,10 +151,10 @@ pnm_addtotuplehash(struct pam *   const pamP,
 
 
 void
-pnm_lookuptuple(struct pam *    const pamP, 
-                const tuplehash       tuplehash, 
-                const tuple           searchval, 
-                int *           const foundP, 
+pnm_lookuptuple(struct pam *    const pamP,
+                const tuplehash       tuplehash,
+                const tuple           searchval,
+                int *           const foundP,
                 int *           const retvalP) {
 /*----------------------------------------------------------------------------
    Return as *revtvalP the index of the tuple value 'searchval' in the
@@ -183,18 +183,18 @@ pnm_lookuptuple(struct pam *    const pamP,
 
 
 static void
-addColorOccurrenceToHash(tuple          const color, 
+addColorOccurrenceToHash(tuple          const color,
                          tuplehash      const tuplefreqhash,
                          struct pam *   const pamP,
                          unsigned int   const maxsize,
                          unsigned int * const sizeP,
                          bool *         const fullP) {
-               
+
     unsigned int const hashvalue = pnm_hashtuple(pamP, color);
-            
+
     struct tupleint_list_item *p;
 
-    for (p = tuplefreqhash[hashvalue]; 
+    for (p = tuplefreqhash[hashvalue];
          p && !pnm_tupleequal(pamP, p->tupleint.tuple, color);
          p = p->next);
 
@@ -205,7 +205,7 @@ addColorOccurrenceToHash(tuple          const color,
     } else {
         /* It's not in the hash yet, so add it (if allowed) */
         ++(*sizeP);
-        if (maxsize > 0 && *sizeP > maxsize) 
+        if (maxsize > 0 && *sizeP > maxsize)
             *fullP = TRUE;
         else {
             *fullP = FALSE;
@@ -228,7 +228,7 @@ pnm_addtuplefreqoccurrence(struct pam *   const pamP,
                            tuplehash      const tuplefreqhash,
                            int *          const firstOccurrenceP) {
 /*----------------------------------------------------------------------------
-  Tally one more occurence of the tuple value 'value' to the tuple frequencey
+  Tally one more occurrence of the tuple value 'value' to the tuple frequency
   hash 'tuplefreqhash', adding the tuple to the hash if it isn't there
   already.
 
@@ -238,10 +238,10 @@ pnm_addtuplefreqoccurrence(struct pam *   const pamP,
   program.
 -----------------------------------------------------------------------------*/
     unsigned int const hashvalue = pnm_hashtuple(pamP, value);
-            
+
     struct tupleint_list_item * p;
 
-    for (p = tuplefreqhash[hashvalue]; 
+    for (p = tuplefreqhash[hashvalue];
          p && !pnm_tupleequal(pamP, p->tupleint.tuple, value);
          p = p->next);
 
@@ -270,8 +270,8 @@ pnm_addtuplefreqoccurrence(struct pam *   const pamP,
 
 static void
 computehashrecoverable(struct pam *   const pamP,
-                       tuple **       const tupleArray, 
-                       unsigned int   const maxsize, 
+                       tuple **       const tupleArray,
+                       unsigned int   const maxsize,
                        unsigned int   const newDepth,
                        sample         const newMaxval,
                        unsigned int * const sizeP,
@@ -295,20 +295,20 @@ computehashrecoverable(struct pam *   const pamP,
 
     *tuplefreqhashP = pnm_createtuplehash();
     *sizeP = 0;   /* initial value */
-    
+
     *rowbufferP = pnm_allocpamrow(pamP);
-    
+
     *colorP = pnm_allocpamtuple(pamP);
-    
+
     full = FALSE;  /* initial value */
-    
+
     /* Go through the entire raster, building a hash table of
-       tuple values. 
+       tuple values.
     */
     for (row = 0; row < pamP->height && !full; ++row) {
         unsigned int col;
         const tuple * tuplerow;  /* The row of tuples we are processing */
-        
+
         if (tupleArray)
             tuplerow = tupleArray[row];
         else {
@@ -335,8 +335,8 @@ computehashrecoverable(struct pam *   const pamP,
 
 static tuplehash
 computetuplefreqhash(struct pam *   const pamP,
-                     tuple **       const tupleArray, 
-                     unsigned int   const maxsize, 
+                     tuple **       const tupleArray,
+                     unsigned int   const maxsize,
                      unsigned int   const newDepth,
                      sample         const newMaxval,
                      unsigned int * const sizeP) {
@@ -350,18 +350,18 @@ computetuplefreqhash(struct pam *   const pamP,
 
   2) an open PAM file, positioned to the raster.  In this case,
      'tupleArray' is NULL.  *pamP contains the file descriptor.
-  
-     We return with the file still open and its position undefined.  
+
+     We return with the file still open and its position undefined.
 
   In either case, *pamP contains parameters of the tuple array.
 
   Return the number of unique tuple values found as *sizeP.
 
-  However, if the number of unique tuple values is greater than 'maxsize', 
+  However, if the number of unique tuple values is greater than 'maxsize',
   return a null return value and *sizeP undefined.
 
   The tuple values that index the hash have depth 'newDepth'.  We look at
-  only the first 'newDepth' planes of the input.  Caler must ensure that
+  only the first 'newDepth' planes of the input.  Caller must ensure that
   the input has at least that many planes.
 
   The tuple values that index the hash are scaled to a new maxval of
@@ -374,18 +374,18 @@ computetuplefreqhash(struct pam *   const pamP,
         /* Buffer for a row read from the input file; undefined (but still
            allocated) if input is not from a file.
         */
-    tuple color;  
+    tuple color;
         /* The color currently being added, scaled to the new maxval */
     jmp_buf jmpbuf;
     jmp_buf * origJmpbufP;
-    
+
     /* Initialize to "none" for purposes of error recovery */
     tuplefreqhash = NULL;
     rowbuffer = NULL;
     color = NULL;
 
     if (setjmp(jmpbuf) != 0) {
-        if (color) 
+        if (color)
             pnm_freepamtuple(color);
         if (rowbuffer)
             pnm_freepamrow(rowbuffer);
@@ -413,24 +413,24 @@ pnm_computetuplefreqhash(struct pam *   const pamP,
    Compute the tuple frequency hash for the tuple array tupleArray[][].
 -----------------------------------------------------------------------------*/
     return computetuplefreqhash(pamP, tupleArray, maxsize,
-                                pamP->depth, pamP->maxval, 
+                                pamP->depth, pamP->maxval,
                                 sizeP);
 }
 
 
 
 static void
-alloctupletable(const struct pam * const pamP, 
+alloctupletable(const struct pam * const pamP,
                 unsigned int       const size,
                 tupletable *       const tupletableP,
                 const char **      const errorP) {
-    
+
     if (UINT_MAX / sizeof(struct tupleint) < size)
         pm_asprintf(errorP, "size %u is too big for arithmetic", size);
     else {
         unsigned int const mainTableSize = size * sizeof(struct tupleint *);
-        unsigned int const tupleIntSize = 
-            sizeof(struct tupleint) - sizeof(sample) 
+        unsigned int const tupleIntSize =
+            sizeof(struct tupleint) - sizeof(sample)
             + pamP->depth * sizeof(sample);
 
         /* To save the enormous amount of time it could take to allocate
@@ -442,7 +442,7 @@ alloctupletable(const struct pam * const pamP,
         else {
             unsigned int const allocSize = mainTableSize + size * tupleIntSize;
             void * pool;
-    
+
             pool = malloc(allocSize);
 
             if (!pool)
@@ -469,7 +469,7 @@ alloctupletable(const struct pam * const pamP,
 
 
 tupletable
-pnm_alloctupletable(const struct pam * const pamP, 
+pnm_alloctupletable(const struct pam * const pamP,
                     unsigned int       const size) {
 
     tupletable retval;
@@ -491,8 +491,8 @@ void
 pnm_freetupletable(const struct pam * const pamP,
                    tupletable         const tupletable) {
 
-    /* Note that the address 'tupletable' is, to the operating system, 
-       the address of a larger block of memory that contains not only 
+    /* Note that the address 'tupletable' is, to the operating system,
+       the address of a larger block of memory that contains not only
        tupletable, but all the samples to which it points (e.g.
        tupletable[0].tuple[0])
     */
@@ -574,7 +574,7 @@ pnm_tuplehashtotable(const struct pam * const pamP,
 
 
 tuplehash
-pnm_computetupletablehash(struct pam * const pamP, 
+pnm_computetupletablehash(struct pam * const pamP,
                           tupletable   const tupletable,
                           unsigned int const tupletableSize) {
 /*----------------------------------------------------------------------------
@@ -591,12 +591,12 @@ pnm_computetupletablehash(struct pam * const pamP,
     tuplehash tupletablehash;
     unsigned int i;
     int fits;
-    
+
     tupletablehash = pnm_createtuplehash();
 
     fits = TRUE;  /* initial assumption */
     for (i = 0; i < tupletableSize && fits; ++i) {
-        pnm_addtotuplehash(pamP, tupletablehash, 
+        pnm_addtotuplehash(pamP, tupletablehash,
                            tupletable[i]->tuple, i, &fits);
     }
     if (!fits) {
@@ -658,7 +658,7 @@ pnm_computetuplefreqtable3(struct pam *   const pamP,
                  "argument (%u) greater than input depth (%u)",
                  newDepth, pamP->depth);
 
-    tuplefreqhash = computetuplefreqhash(pamP, tupleArray, maxsize, 
+    tuplefreqhash = computetuplefreqhash(pamP, tupleArray, maxsize,
                                          newDepth, newMaxval, &uniqueCount);
     if (tuplefreqhash == NULL)
         tuplefreqtable = NULL;
@@ -704,8 +704,8 @@ pnm_computetuplefreqtable(struct pam *   const pamP,
 
 
 char*
-pam_colorname(struct pam *         const pamP, 
-              tuple                const color, 
+pam_colorname(struct pam *         const pamP,
+              tuple                const color,
               enum colornameFormat const format) {
 
     unsigned int r, g, b;
@@ -726,9 +726,9 @@ pam_colorname(struct pam *         const pamP,
         while (!done) {
             struct colorfile_entry const ce = pm_colorget(f);
             if (ce.colorname) {
-                unsigned int const this_diff = 
-                    abs((int)r - (int)ce.r) + 
-                    abs((int)g - (int)ce.g) + 
+                unsigned int const this_diff =
+                    abs((int)r - (int)ce.r) +
+                    abs((int)g - (int)ce.g) +
                     abs((int)b - (int)ce.b);
 
                 if (this_diff < best_diff) {
@@ -739,7 +739,7 @@ pam_colorname(struct pam *         const pamP,
                 done = TRUE;
         }
         fclose(f);
-        if (best_diff != 32767 && 
+        if (best_diff != 32767 &&
             (best_diff == 0 || format == PAM_COLORNAME_ENGLISH))
             return colorname;
     }
diff --git a/lib/libpamwrite.c b/lib/libpamwrite.c
index 29ddeaa2..0e1ff469 100644
--- a/lib/libpamwrite.c
+++ b/lib/libpamwrite.c
@@ -13,7 +13,7 @@
    offset stuff.
 */
 #define _FILE_OFFSET_BITS 64
-#define _LARGE_FILES  
+#define _LARGE_FILES
 
 #include <string.h>
 #include <stdio.h>
@@ -28,8 +28,8 @@
 
 
 static __inline__ unsigned int
-samplesPerPlainLine(sample       const maxval, 
-                    unsigned int const depth, 
+samplesPerPlainLine(sample       const maxval,
+                    unsigned int const depth,
                     unsigned int const lineLength) {
 /*----------------------------------------------------------------------------
    Return the minimum number of samples that should go in a line
@@ -61,7 +61,7 @@ writePamPlainPbmRow(const struct pam *  const pamP,
     unsigned int const samplesPerLine = 70;
 
     for (col = 0; col < pamP->width; ++col)
-        fprintf(pamP->file,  
+        fprintf(pamP->file,
                 ((col+1) % samplesPerLine == 0 || col == pamP->width-1)
                     ? "%1u\n" : "%1u",
                 tuplerow[col][0] == PAM_PBM_BLACK ? PBM_BLACK : PBM_WHITE);
@@ -71,15 +71,15 @@ writePamPlainPbmRow(const struct pam *  const pamP,
 
 static void
 writePamPlainRow(const struct pam *  const pamP,
-                    const tuple *       const tuplerow) {
+                 const tuple *       const tuplerow) {
 
-    int const samplesPerLine = 
+    int const samplesPerLine =
         samplesPerPlainLine(pamP->maxval, pamP->depth, 79);
 
     int col;
     unsigned int samplesInCurrentLine;
         /* number of samples written from start of line  */
-    
+
     samplesInCurrentLine = 0;
 
     for (col = 0; col < pamP->width; ++col) {
@@ -92,7 +92,7 @@ writePamPlainRow(const struct pam *  const pamP,
             if (samplesInCurrentLine >= samplesPerLine) {
                 fprintf(pamP->file, "\n");
                 samplesInCurrentLine = 0;
-            }            
+            }
         }
     }
     fprintf(pamP->file, "\n");
@@ -101,18 +101,26 @@ writePamPlainRow(const struct pam *  const pamP,
 
 
 static void
-formatPbmRow(const struct pam * const pamP,
-             const tuple *      const tuplerow,
-             unsigned char *    const outbuf,
-             unsigned int *     const rowSizeP) {
+formatPbm(const struct pam * const pamP,
+          const tuple *      const tuplerow,
+          unsigned char *    const outbuf,
+          unsigned int       const nTuple,
+          unsigned int *     const rowSizeP) {
+/*----------------------------------------------------------------------------
+   Create the image of 'nTuple' consecutive tuples of a row in the raster of a
+   raw format PBM image.
 
+   Put the image at *outbuf; put the number of bytes of it at *rowSizeP.
+-----------------------------------------------------------------------------*/
     unsigned char accum;
     int col;
-    
+
+    assert(nTuple <= pamP->width);
+
     accum = 0;  /* initial value */
-    
-    for (col=0; col < pamP->width; ++col) {
-        accum |= 
+
+    for (col=0; col < nTuple; ++col) {
+        accum |=
             (tuplerow[col][0] == PAM_PBM_BLACK ? PBM_BLACK : PBM_WHITE)
                 << (7-col%8);
         if (col%8 == 7) {
@@ -120,12 +128,12 @@ formatPbmRow(const struct pam * const pamP,
                 accum = 0;
         }
     }
-    if (pamP->width % 8 != 0) {
-        unsigned int const lastByteIndex = pamP->width/8;
+    if (nTuple % 8 != 0) {
+        unsigned int const lastByteIndex = nTuple/8;
         outbuf[lastByteIndex] = accum;
         *rowSizeP = lastByteIndex + 1;
     } else
-        *rowSizeP = pamP->width/8;
+        *rowSizeP = nTuple/8;
 }
 
 
@@ -138,7 +146,7 @@ formatPbmRow(const struct pam * const pamP,
 */
 
 static __inline__ void
-sampleToBytes2(unsigned char       buf[2], 
+sampleToBytes2(unsigned char       buf[2],
                sample        const sampleval) {
 
     buf[0] = (sampleval >> 8) & 0xff;
@@ -148,7 +156,7 @@ sampleToBytes2(unsigned char       buf[2],
 
 
 static __inline__ void
-sampleToBytes3(unsigned char       buf[3], 
+sampleToBytes3(unsigned char       buf[3],
                sample        const sampleval) {
 
     buf[0] = (sampleval >> 16) & 0xff;
@@ -159,7 +167,7 @@ sampleToBytes3(unsigned char       buf[3],
 
 
 static __inline__ void
-sampleToBytes4(unsigned char       buf[4], 
+sampleToBytes4(unsigned char       buf[4],
                sample        const sampleval) {
 
     buf[0] = (sampleval >> 24 ) & 0xff;
@@ -171,36 +179,40 @@ sampleToBytes4(unsigned char       buf[4],
 
 
 static __inline__ void
-format1BpsRow(const struct pam * const pamP,
-              const tuple *      const tuplerow,
-              unsigned char *    const outbuf,
-              unsigned int *     const rowSizeP) {
+format1Bps(const struct pam * const pamP,
+           const tuple *      const tuplerow,
+           unsigned char *    const outbuf,
+           unsigned int       const nTuple,
+           unsigned int *     const rowSizeP) {
 /*----------------------------------------------------------------------------
-   Create the image of a row in the raster of a raw format Netpbm
-   image that has one byte per sample (ergo not PBM).
+   Create the image of 'nTuple' consecutive tuples of a row in the raster of a
+   raw format Netpbm image that has one byte per sample (ergo not PBM).
 
    Put the image at *outbuf; put the number of bytes of it at *rowSizeP.
 -----------------------------------------------------------------------------*/
     int col;
     unsigned int bufferCursor;
 
+    assert(nTuple <= pamP->width);
+
     bufferCursor = 0;  /* initial value */
-    
-    for (col = 0; col < pamP->width; ++col) {
+
+    for (col = 0; col < nTuple; ++col) {
         unsigned int plane;
         for (plane=0; plane < pamP->depth; ++plane)
             outbuf[bufferCursor++] = (unsigned char)tuplerow[col][plane];
     }
-    *rowSizeP = pamP->width * 1 * pamP->depth;
+    *rowSizeP = nTuple * 1 * pamP->depth;
 }
 
 
 
 static __inline__ void
-format2BpsRow(const struct pam * const pamP,
-              const tuple *      const tuplerow,
-              unsigned char *    const outbuf,
-              unsigned int *     const rowSizeP) {
+format2Bps(const struct pam * const pamP,
+           const tuple *      const tuplerow,
+           unsigned char *    const outbuf,
+           unsigned int       const nTuple,
+           unsigned int *     const rowSizeP) {
 /*----------------------------------------------------------------------------
   Analogous to format1BpsRow().
 -----------------------------------------------------------------------------*/
@@ -209,24 +221,27 @@ format2BpsRow(const struct pam * const pamP,
     int col;
     unsigned int bufferCursor;
 
+    assert(nTuple <= pamP->width);
+
     bufferCursor = 0;  /* initial value */
-    
-    for (col=0; col < pamP->width; ++col) {
+
+    for (col=0; col < nTuple; ++col) {
         unsigned int plane;
         for (plane = 0; plane < pamP->depth; ++plane)
             sampleToBytes2(ob[bufferCursor++], tuplerow[col][plane]);
     }
 
-    *rowSizeP = pamP->width * 2 * pamP->depth;
+    *rowSizeP = nTuple * 2 * pamP->depth;
 }
 
 
 
 static __inline__ void
-format3BpsRow(const struct pam * const pamP,
-              const tuple *      const tuplerow,
-              unsigned char *    const outbuf,
-              unsigned int *     const rowSizeP) {
+format3Bps(const struct pam * const pamP,
+           const tuple *      const tuplerow,
+           unsigned char *    const outbuf,
+           unsigned int       const nTuple,
+           unsigned int *     const rowSizeP) {
 /*----------------------------------------------------------------------------
   Analogous to format1BpsRow().
 -----------------------------------------------------------------------------*/
@@ -235,24 +250,27 @@ format3BpsRow(const struct pam * const pamP,
     int col;
     unsigned int bufferCursor;
 
+    assert(nTuple <= pamP->width);
+
     bufferCursor = 0;  /* initial value */
-    
-    for (col=0; col < pamP->width; ++col) {
+
+    for (col=0; col < nTuple; ++col) {
         unsigned int plane;
         for (plane = 0; plane < pamP->depth; ++plane)
             sampleToBytes3(ob[bufferCursor++], tuplerow[col][plane]);
     }
 
-    *rowSizeP = pamP->width * 3 * pamP->depth;
+    *rowSizeP = nTuple * 3 * pamP->depth;
 }
 
 
 
 static __inline__ void
-format4BpsRow(const struct pam * const pamP,
-              const tuple *      const tuplerow,
-              unsigned char *    const outbuf,
-              unsigned int *     const rowSizeP) {
+format4Bps(const struct pam * const pamP,
+           const tuple *      const tuplerow,
+           unsigned char *    const outbuf,
+           unsigned int       const nTuple,
+           unsigned int *     const rowSizeP) {
 /*----------------------------------------------------------------------------
   Analogous to format1BpsRow().
 -----------------------------------------------------------------------------*/
@@ -261,41 +279,49 @@ format4BpsRow(const struct pam * const pamP,
     int col;
     unsigned int bufferCursor;
 
+    assert(nTuple <= pamP->width);
+
     bufferCursor = 0;  /* initial value */
-    
-    for (col=0; col < pamP->width; ++col) {
+
+    for (col=0; col < nTuple; ++col) {
         unsigned int plane;
         for (plane = 0; plane < pamP->depth; ++plane)
             sampleToBytes4(ob[bufferCursor++], tuplerow[col][plane]);
     }
 
-    *rowSizeP = pamP->width * 4 * pamP->depth;
+    *rowSizeP = nTuple * 4 * pamP->depth;
 }
 
 
 
 void
-pnm_formatpamrow(const struct pam * const pamP,
-                 const tuple *      const tuplerow,
-                 unsigned char *    const outbuf,
-                 unsigned int *     const rowSizeP) {
-/*----------------------------------------------------------------------------
-   Create the image of a row in the raster of a raw (not plain) format
-   Netpbm image, as described by *pamP and tuplerow[].  Put the image
-   at *outbuf.
+pnm_formatpamtuples(const struct pam * const pamP,
+                    const tuple *      const tuplerow,
+                    unsigned char *    const outbuf,
+                    unsigned int       const nTuple,
+                    unsigned int *     const rowSizeP) {
+/*----------------------------------------------------------------------------   Create the image of 'nTuple' consecutive tuples of a row in the raster of a
+   raw (not plain) format Netpbm image, as described by *pamP and tuplerow[].
+   Put the image at *outbuf.
 
    'outbuf' must be the address of space allocated with pnm_allocrowimage().
-   
-   We return as *rowSizeP the number of bytes in the row image.
+
+   We return as *rowSizeP the number of bytes in the image.
 -----------------------------------------------------------------------------*/
+    if (nTuple > pamP->width) {
+        pm_error("pnm_formatpamtuples called to write more tuples (%u) "
+                 "than the width of a row (%u)",
+                 nTuple, pamP->width);
+    }
+
     if (PAM_FORMAT_TYPE(pamP->format) == PBM_TYPE)
-        formatPbmRow(pamP, tuplerow, outbuf, rowSizeP);
+        formatPbm(pamP, tuplerow, outbuf, nTuple, rowSizeP);
     else {
         switch(pamP->bytes_per_sample){
-        case 1: format1BpsRow(pamP, tuplerow, outbuf, rowSizeP); break;
-        case 2: format2BpsRow(pamP, tuplerow, outbuf, rowSizeP); break;
-        case 3: format3BpsRow(pamP, tuplerow, outbuf, rowSizeP); break;
-        case 4: format4BpsRow(pamP, tuplerow, outbuf, rowSizeP); break;
+        case 1: format1Bps(pamP, tuplerow, outbuf, nTuple, rowSizeP); break;
+        case 2: format2Bps(pamP, tuplerow, outbuf, nTuple, rowSizeP); break;
+        case 3: format3Bps(pamP, tuplerow, outbuf, nTuple, rowSizeP); break;
+        case 4: format4Bps(pamP, tuplerow, outbuf, nTuple, rowSizeP); break;
         default:
             pm_error("invalid bytes per sample passed to "
                      "pnm_formatpamrow(): %u",  pamP->bytes_per_sample);
@@ -305,12 +331,25 @@ pnm_formatpamrow(const struct pam * const pamP,
 
 
 
+void
+pnm_formatpamrow(const struct pam * const pamP,
+                 const tuple *      const tuplerow,
+                 unsigned char *    const outbuf,
+                 unsigned int *     const rowSizeP) {
+/*----------------------------------------------------------------------------
+  Same as 'pnm_formatpamtuples', except formats an entire row.
+-----------------------------------------------------------------------------*/
+    pnm_formatpamtuples(pamP, tuplerow, outbuf, pamP->width, rowSizeP);
+}
+
+
+
 static void
 writePamRawRow(const struct pam * const pamP,
                const tuple *      const tuplerow,
                unsigned int       const count) {
 /*----------------------------------------------------------------------------
-   Write mutiple ('count') copies of the same row ('tuplerow') to the file,
+   Write multiple ('count') copies of the same row ('tuplerow') to the file,
    in raw (not plain) format.
 -----------------------------------------------------------------------------*/
     jmp_buf jmpbuf;
@@ -330,10 +369,10 @@ writePamRawRow(const struct pam * const pamP,
         unsigned int i;
 
         pm_setjmpbufsave(&jmpbuf, &origJmpbufP);
-        
+
         for (i = 0; i < count; ++i) {
             size_t bytesWritten;
-            
+
             bytesWritten = fwrite(outbuf, 1, rowImageSize, pamP->file);
             if (bytesWritten != rowImageSize)
                 pm_error("fwrite() failed to write an image row to the file.  "
@@ -346,16 +385,16 @@ writePamRawRow(const struct pam * const pamP,
 
 
 
-void 
-pnm_writepamrow(const struct pam * const pamP, 
+void
+pnm_writepamrow(const struct pam * const pamP,
                 const tuple *      const tuplerow) {
 
-    /* For speed, we don't check any of the inputs for consistency 
+    /* For speed, we don't check any of the inputs for consistency
        here (unless it's necessary to avoid crashing).  Any consistency
-       checking should have been done by a prior call to 
+       checking should have been done by a prior call to
        pnm_writepaminit().
     */
-    
+
     if (pamP->format == PAM_FORMAT || !(pm_plain_output || pamP->plainformat))
         writePamRawRow(pamP, tuplerow, 1);
     else {
@@ -371,7 +410,7 @@ pnm_writepamrow(const struct pam * const pamP,
             assert(false);
             break;
         default:
-            pm_error("Invalid 'format' value %u in pam structure", 
+            pm_error("Invalid 'format' value %u in pam structure",
                      pamP->format);
         }
     }
@@ -380,11 +419,11 @@ pnm_writepamrow(const struct pam * const pamP,
 
 
 void
-pnm_writepamrowmult(const struct pam * const pamP, 
+pnm_writepamrowmult(const struct pam * const pamP,
                     const tuple *      const tuplerow,
                     unsigned int       const count) {
 /*----------------------------------------------------------------------------
-   Write mutiple ('count') copies of the same row ('tuplerow') to the file.
+   Write multiple ('count') copies of the same row ('tuplerow') to the file.
 -----------------------------------------------------------------------------*/
    if (pm_plain_output || pamP->plainformat) {
        unsigned int i;
@@ -397,14 +436,84 @@ pnm_writepamrowmult(const struct pam * const pamP,
 
 
 
-void 
-pnm_writepam(struct pam * const pamP, 
+void
+pnm_writepamrowpart(const struct pam * const pamP,
+                    const tuple *      const tuplerow,
+                    unsigned int       const firstRow,
+                    unsigned int       const firstCol,
+                    unsigned int       const rowCt,
+                    unsigned int       const colCt) {
+/*----------------------------------------------------------------------------
+   Write part of multiple consecutive rows to the file.
+
+   For each of 'rowCt' consecutive rows starting at 'firstRow', write the
+   'colCt' columns starting at 'firstCol'.  The tuples to write are those in
+   'tuplerow', starting at the beginning of 'tuplerow'.
+
+   Fail if the file is not seekable (or not known to be seekable) or the
+   output format is not raw (i.e. is plain) or the output format is PBM.
+-----------------------------------------------------------------------------*/
+    unsigned int const bytesPerTuple = pamP->depth * pamP->bytes_per_sample;
+
+    jmp_buf jmpbuf;
+    jmp_buf * origJmpbufP;
+    unsigned int tupleImageSize;
+    unsigned char * outbuf;  /* malloc'ed */
+
+    if (pamP->len < PAM_STRUCT_SIZE(raster_pos) || !pamP->raster_pos)
+        pm_error("pnm_writepamrowpart called on nonseekable file");
+
+    if (PAM_FORMAT_TYPE(pamP->format) == PBM_TYPE)
+        pm_error("pnm_witepamrowpart called for PBM image");
+
+    if (pm_plain_output || pamP->plainformat)
+        pm_error("pnm_writepamrowpart called for plain format image");
+
+    outbuf = pnm_allocrowimage(pamP);
+
+    pnm_formatpamtuples(pamP, tuplerow, outbuf, colCt, &tupleImageSize);
+
+    if (setjmp(jmpbuf) != 0) {
+        pnm_freerowimage(outbuf);
+        pm_setjmpbuf(origJmpbufP);
+        pm_longjmp();
+    } else {
+        unsigned int row;
+
+        pm_setjmpbufsave(&jmpbuf, &origJmpbufP);
+
+        for (row = firstRow; row < firstRow + rowCt; ++row) {
+            pm_filepos const firstTuplePos =
+                pamP->raster_pos +
+                (row * pamP->width + firstCol) * bytesPerTuple;
+            size_t bytesWritten;
+
+            pm_seek2(pamP->file, &firstTuplePos, sizeof(firstTuplePos));
+
+            bytesWritten = fwrite(outbuf, 1, tupleImageSize, pamP->file);
+
+            if (bytesWritten != tupleImageSize)
+                pm_error("fwrite() failed to write %u image tuples "
+                         "to the file.  errno=%d (%s)",
+                         colCt, errno, strerror(errno));
+        }
+        pm_setjmpbuf(origJmpbufP);
+    }
+    pnm_freerowimage(outbuf);
+}
+
+
+
+void
+pnm_writepam(struct pam * const pamP,
              tuple **     const tuplearray) {
 
     int row;
 
     pnm_writepaminit(pamP);
-    
-    for (row = 0; row < pamP->height; ++row) 
+
+    for (row = 0; row < pamP->height; ++row)
         pnm_writepamrow(pamP, tuplearray[row]);
 }
+
+
diff --git a/lib/libpbm2.c b/lib/libpbm2.c
index a611bec5..2a2e2aac 100644
--- a/lib/libpbm2.c
+++ b/lib/libpbm2.c
@@ -69,8 +69,8 @@ validateComputableSize(unsigned int const cols,
    you expect.  That failed expectation can be disastrous if you use
    it to allocate memory.
 
-   A common operation is adding 1 or 2 to the highest row or
-   column number in the image, so we make sure that's possible.
+   See comments at 'validateComputableSize' in libpam.c for details on
+   the purpose of these validations.
 -----------------------------------------------------------------------------*/
     if (cols > INT_MAX - 10)
         pm_error("image width (%u) too large to be processed", cols);
diff --git a/lib/libpbm3.c b/lib/libpbm3.c
index 0144abe2..456d3986 100644
--- a/lib/libpbm3.c
+++ b/lib/libpbm3.c
@@ -389,7 +389,7 @@ pbm_writepbmrow_bitoffset(FILE *          const fileP,
     unsigned char * const window = &packedBits[offset/8];
         /* Area of packed row buffer from which we take the image data.
            Aligned to nearest byte boundary to the left, so the first
-           few bits might be irrelvant.
+           few bits might be irrelevant.
 
            Also our work buffer, in which we shift bits and from which we
            ultimately write the bits to the file.
diff --git a/lib/libpbmfont0.c b/lib/libpbmfont0.c
index 503c7ee7..abfd18d2 100644
--- a/lib/libpbmfont0.c
+++ b/lib/libpbmfont0.c
@@ -27,7 +27,6 @@
 #include "pbmfont.h"
 #include "pbmfontdata.h"
 
-
 struct font *
 pbm_defaultfont(const char * const name) {
 /*----------------------------------------------------------------------------
@@ -77,11 +76,12 @@ pbm_defaultfont2(const char * const requestedFontName) {
 
 
 static void
-selectFontType(const    char * const filename,
-               PM_WCHAR        const maxmaxglyph,
-               unsigned int    const isWide,
-               struct font  ** const fontPP,
-               struct font2 ** const font2PP) {
+selectFontType(const    char *            const filename,
+               PM_WCHAR                   const maxmaxglyph,
+               unsigned int               const isWide,
+               struct font  **            const fontPP,
+               struct font2 **            const font2PP,
+               const struct pm_selector * const selectorP) {
 
     FILE * fileP;
     struct font  * fontP  = NULL; /* initial value */
@@ -106,7 +106,7 @@ selectFontType(const    char * const filename,
 
     } else if (!strncmp(line, "STARTFONT", 9)) {
         if (isWide == TRUE)
-            font2P = pbm_loadbdffont2(filename, maxmaxglyph);
+            font2P = pbm_loadbdffont2select(filename, maxmaxglyph, selectorP);
         else
             fontP = pbm_loadbdffont(filename);
         if (fontP == NULL && font2P == NULL)
@@ -128,25 +128,49 @@ selectFontType(const    char * const filename,
 
 
 struct font *
-pbm_loadfont(const    char * const filename) {
-
+pbm_loadfont(const char * const filename) {
+/*----------------------------------------------------------------------------
+   Load font file named 'filename'.
+   Font file may be either a PBM sheet or BDF.
+   Supports 8 bit codepoints.
+-----------------------------------------------------------------------------*/
     struct font  * fontP;
     struct font2 * font2P;
 
-    selectFontType(filename, PM_FONT_MAXGLYPH, FALSE, &fontP, &font2P);
+    selectFontType(filename, PM_FONT_MAXGLYPH, FALSE, &fontP, &font2P, NULL);
     return fontP;
 }
 
 
 
 struct font2 *
-pbm_loadfont2(const    char * const filename,
-              PM_WCHAR        const maxmaxglyph) {
+pbm_loadfont2(const char * const filename,
+              PM_WCHAR     const maxmaxglyph) {
+/*----------------------------------------------------------------------------
+   Load font file named 'filename'.
+   Font file may be either a PBM sheet or BDF.
+   Supports codepoints above 256.
+-----------------------------------------------------------------------------*/
+    struct font  * fontP;
+    struct font2 * font2P;
+
+    selectFontType(filename, maxmaxglyph, TRUE, &fontP, &font2P, NULL);
+    return font2P;
+}
 
+
+struct font2 *
+pbm_loadfont2select(const  char *              const filename,
+                    PM_WCHAR                   const maxmaxglyph,
+                    const struct pm_selector * const selectorP) {
+/*----------------------------------------------------------------------------
+   Same as pbm_loadfont2(), but load only glyphs indicated by *selectorP
+-----------------------------------------------------------------------------*/
     struct font  * fontP;
     struct font2 * font2P;
 
-    selectFontType(filename, maxmaxglyph, TRUE, &fontP, &font2P);
+    selectFontType(filename, maxmaxglyph, TRUE, &fontP, &font2P, selectorP);
+
     return font2P;
 }
 
@@ -173,7 +197,7 @@ pbm_createbdffont2_base(struct font2 ** const font2PP,
     /*  Caller should overwrite following fields as necessary */
     font2P->oldfont = NULL;
     font2P->fcols = font2P->frows = 0;
-    font2P->selector = NULL;
+    font2P->selectorP = NULL;
     font2P->default_char = 0;
     font2P->default_char_defined = FALSE;
     font2P->total_chars = font2P->chars = 0;
@@ -187,23 +211,32 @@ pbm_createbdffont2_base(struct font2 ** const font2PP,
 
 
 static void
-destroyGlyphData(struct glyph ** const glyph,
-                 PM_WCHAR        const maxglyph) {
+destroyGlyphData(struct glyph **            const glyph,
+                 PM_WCHAR                   const maxglyph,
+                 const struct pm_selector * const selectorP) {
 /*----------------------------------------------------------------------------
   Free glyph objects and bitmap objects.
 
   This does not work when an object is "shared" through multiple pointers
   referencing an identical address and thus pointing to a common glyph
   or bitmap object.
+
+  If 'selectorP' is NULL, free all glyph and bitmap objects in the range
+  0 ... maxglyph.  If not, free only the objects which the selector
+  indicates as present.
 -----------------------------------------------------------------------------*/
 
+    PM_WCHAR const min = (selectorP != NULL) ? selectorP->min : 0;
+    PM_WCHAR const max =
+        (selectorP != NULL) ? MIN(selectorP->max, maxglyph) : maxglyph;
+
     PM_WCHAR i;
 
-    for(i = 0; i <= maxglyph; ++i) {
-        if (glyph[i]!=NULL) {
+    for (i = min; i <= max; ++i) {
+        if (pm_selector_is_marked(selectorP, i) && glyph[i]) {
             free((void *) (glyph[i]->bmap));
             free(glyph[i]);
-      }
+        }
     }
 }
 
@@ -214,17 +247,16 @@ pbm_destroybdffont2_base(struct font2 * const font2P) {
   Free font2 structure, but not the glyph data
 ---------------------------------------------------------------------------- */
 
-    free(font2P->selector);
-
     pm_strfree(font2P->name);
+
     pm_strfree(font2P->charset_string);
+
     free(font2P->glyph);
 
-    if (font2P->oldfont !=NULL)
+    if (font2P->oldfont)
        pbm_freearray(font2P->oldfont, font2P->frows);
 
-    free((void *)font2P);
-
+    free(font2P);
 }
 
 
@@ -239,7 +271,7 @@ pbm_destroybdffont2(struct font2 * const font2P) {
 ---------------------------------------------------------------------------- */
 
     if (font2P->load_fn != FIXED_DATA) {
-        destroyGlyphData(font2P->glyph, font2P->maxglyph);
+        destroyGlyphData(font2P->glyph, font2P->maxglyph, font2P->selectorP);
         pbm_destroybdffont2_base(font2P);
     }
 }
@@ -254,7 +286,7 @@ pbm_destroybdffont(struct font * const fontP) {
   For freeing a structure created by pbm_loadbdffont() or pbm_loadpbmfont().
 ---------------------------------------------------------------------------- */
 
-    destroyGlyphData(fontP->glyph, PM_FONT_MAXGLYPH);
+    destroyGlyphData(fontP->glyph, PM_FONT_MAXGLYPH, NULL);
 
     if (fontP->oldfont !=NULL)
        pbm_freearray(fontP->oldfont, fontP->frows);
@@ -326,8 +358,7 @@ pbm_expandbdffont(const struct font * const fontP) {
     font2P->bit_format = PBM_FORMAT;
     font2P->total_chars = font2P->chars = nCharacters;
     font2P->load_fn = CONVERTED_TYPE1_FONT;
-    /* Caller should be overwrite the above to a more descriptive
-       value */
+    /* Caller should overwrite the above to a more descriptive value */
     return font2P;
 }
 
diff --git a/lib/libpbmfont1.c b/lib/libpbmfont1.c
index 2d269da7..a76d0e6b 100644
--- a/lib/libpbmfont1.c
+++ b/lib/libpbmfont1.c
@@ -47,7 +47,7 @@
   The characters in the border you see are irrelevant except for
   character size compuations.  The 12 x 8 array in the center is
   the font.  The top left character there belongs to code point
-  0, and the code points increase in standard reading order, so
+  32, and the code points increase in standard reading order, so
   the bottom right character is code point 127.  You can't define
   code points < 32 or > 127 with this font format.
 
@@ -184,13 +184,13 @@ computeCharacterSize(const bit **   const font,
 
 
 
-struct font*
+struct font *
 pbm_dissectfont(const bit ** const fontsheet,
                 unsigned int const frows,
                 unsigned int const fcols) {
 /*----------------------------------------------------------------------------
-  Dissect PBM sheet font data, create a font structre,
-  load bitmap data into it.
+  Dissect PBM sheet font data, create a font structure, load bitmap data into
+  it.
 
   Return value is a pointer to the newly created font structure
 
@@ -205,7 +205,7 @@ pbm_dissectfont(const bit ** const fontsheet,
   just a matter of filling in all the coordinates.
 
   Struct font has fields 'oldfont', 'fcols', 'frows' for backward
-  compability.  If there is any need to load data stored in this format
+  compatibility.  If there is any need to load data stored in this format
   feed the above three, in order, as arguments to this function:
 
     pbm_dissectfont(oldfont, fcols, frows);
@@ -222,56 +222,61 @@ pbm_dissectfont(const bit ** const fontsheet,
     unsigned int charWidth, charHeight;
         /* Maximum dimensions of glyph itself, inside its cell */
 
-    int row, col, ch, r, c, i;
-    struct font * fn;
+    unsigned int row, col;
+    int ch;
+    unsigned int i;
+    struct font * fontP;
 
     computeCharacterSize(fontsheet, fcols, frows,
                          &cellWidth, &cellHeight, &charWidth, &charHeight);
 
     /* Now convert to a general font */
 
-    MALLOCVAR(fn);
-    if (fn == NULL)
+    MALLOCVAR(fontP);
+    if (fontP == NULL)
         pm_error("out of memory allocating font structure");
 
-    fn->maxwidth  = charWidth;
-    fn->maxheight = charHeight;
-    fn->x = fn->y = 0;
+    fontP->maxwidth  = charWidth;
+    fontP->maxheight = charHeight;
+    fontP->x = fontP->y = 0;
 
-    fn->oldfont = fontsheet;
-    fn->frows = frows;
-    fn->fcols = fcols;
+    fontP->oldfont = fontsheet;
+    fontP->frows = frows;
+    fontP->fcols = fcols;
 
     /* Now fill in the 0,0 coords. */
     row = cellHeight * 2;
     col = cellWidth  * 2;
 
     /* Load individual glyphs */
-    for ( ch = 0; ch < nCharsInFont; ++ch ) {
+    for (ch = 0; ch < nCharsInFont; ++ch) {
         /* Allocate memory separately for each glyph.
            pbm_loadbdffont2() does this in exactly the same manner.
          */
-        struct glyph * const glyph =
+        struct glyph * const glyphP =
              (struct glyph *) malloc (sizeof (struct glyph));
-        char * const bmap = (char*) malloc(fn->maxwidth * fn->maxheight);
+        char * const bmap = (char*) malloc(fontP->maxwidth * fontP->maxheight);
 
-        if ( bmap == NULL || glyph == NULL )
-            pm_error( "out of memory allocating glyph data" );
+        unsigned int r;
 
-        glyph->width  = fn->maxwidth;
-        glyph->height = fn->maxheight;
-        glyph->x = glyph->y = 0;
-        glyph->xadd = cellWidth;
+        if (bmap == NULL || glyphP == NULL)
+            pm_error( "out of memory allocating glyph data" );
 
-        for ( r = 0; r < glyph->height; ++r )
-            for ( c = 0; c < glyph->width; ++c )
-                bmap[r * glyph->width + c] = fontsheet[row + r][col + c];
+        glyphP->width  = fontP->maxwidth;
+        glyphP->height = fontP->maxheight;
+        glyphP->x = glyphP->y = 0;
+        glyphP->xadd = cellWidth;
 
-        glyph->bmap = bmap;
-        fn->glyph[firstCodePoint + ch] = glyph;
+        for (r = 0; r < glyphP->height; ++r) {
+            unsigned int c;
+            for (c = 0; c < glyphP->width; ++c)
+                bmap[r * glyphP->width + c] = fontsheet[row + r][col + c];
+        }
+        glyphP->bmap = bmap;
+        fontP->glyph[firstCodePoint + ch] = glyphP;
 
         col += cellWidth;
-        if ( col >= cellWidth * 14 ) {
+        if (col >= cellWidth * 14) {
             col = cellWidth * 2;
             row += cellHeight;
         }
@@ -279,12 +284,12 @@ pbm_dissectfont(const bit ** const fontsheet,
 
     /* Initialize all remaining character positions to "undefined." */
     for (i = 0; i < firstCodePoint; ++i)
-        fn->glyph[i] = NULL;
+        fontP->glyph[i] = NULL;
 
     for (i = firstCodePoint + nCharsInFont; i <= PM_FONT_MAXGLYPH; ++i)
-        fn->glyph[i] = NULL;
+        fontP->glyph[i] = NULL;
 
-    return fn;
+    return fontP;
 }
 
 
diff --git a/lib/libpbmfont2.c b/lib/libpbmfont2.c
index b354e91b..7c0415c1 100644
--- a/lib/libpbmfont2.c
+++ b/lib/libpbmfont2.c
@@ -33,6 +33,211 @@
 #include "pbm.h"
 
 /*----------------------------------------------------------------------------
+  Font selector routines
+
+  The selector is a device consisting of a bitmap, min value, max value and
+  count.  It is used here to specify necessary fonts and record what entries
+  are valid in the glyph array.
+
+  This device may be used for other purposes.  In that case the code should
+  be put into an independent source file in the lib/util subdirectory.
+-----------------------------------------------------------------------------*/
+
+static void
+allocRecord(struct pm_selector * const selectorP,
+            unsigned int         const max) {
+
+    unsigned int const size = (max + 8) / 8;
+
+    MALLOCARRAY(selectorP->localRecord, size);
+
+    if (!selectorP->localRecord)
+        pm_error("Failed to allocate %u bytes of memory for font selector "
+                 "bitmap", size);
+
+    selectorP->record = selectorP->localRecord;
+}
+
+
+
+void
+pm_selector_create(unsigned int          const max,
+                   struct pm_selector ** const selectorPP) {
+
+    struct pm_selector * selectorP;
+
+    MALLOCVAR_NOFAIL(selectorP);
+
+    allocRecord(selectorP, max);
+
+    {
+        unsigned int byteIndex;
+        for (byteIndex = 0; byteIndex <= max/8; ++byteIndex)
+            selectorP->localRecord[byteIndex]= 0x00;
+    }
+
+    selectorP->maxmax = selectorP->min = max;
+    selectorP->max = 0;
+    selectorP->count = 0;
+
+    *selectorPP = selectorP;
+}
+
+
+
+void
+pm_selector_create_fixed(const unsigned char * const record,
+                         unsigned int          const min,
+                         unsigned int          const max,
+                         unsigned int          const count,
+                         struct pm_selector ** const selectorPP) {
+
+    struct pm_selector * selectorP;
+
+    MALLOCVAR_NOFAIL(selectorP);
+
+    selectorP->localRecord = NULL;
+    selectorP->record      = record;
+    selectorP->min         = min;
+    selectorP->max         = max;
+    selectorP->maxmax      = max;
+    selectorP->count       = count;
+
+    *selectorPP = selectorP;
+}
+
+
+
+void
+pm_selector_destroy(struct pm_selector * const selectorP) {
+
+    if (selectorP->localRecord)
+        free(selectorP->localRecord);
+
+    free(selectorP);
+}
+
+
+
+void
+pm_selector_copy(unsigned int               const max,
+                 const struct pm_selector * const srcSelectorP,
+                 struct pm_selector      ** const destSelectorPP) {
+
+    /* Create a new selector and copy into it the content of another */
+
+    struct pm_selector * destSelectorP;
+
+    if (max < srcSelectorP->max)
+        pm_error("internal error: attempt to copy a selector as "
+                 "another with a smaller max value %u -> %u",
+                 srcSelectorP->max, max);
+
+    MALLOCVAR_NOFAIL(destSelectorP);
+
+    destSelectorP->maxmax     = max;
+    destSelectorP->max        = srcSelectorP->max;
+    destSelectorP->min        = srcSelectorP->min;
+    destSelectorP->count      = srcSelectorP->count;
+
+    allocRecord(destSelectorP, max);
+
+    {
+        unsigned int const minByteIndex = srcSelectorP->min / 8;
+        unsigned int const maxByteIndex = srcSelectorP->max / 8;
+        unsigned int const maxmaxByteIndex = max / 8;
+
+        unsigned int byteIndex;
+
+        for (byteIndex = 0 ; byteIndex < minByteIndex; ++byteIndex)
+            destSelectorP->localRecord[byteIndex] = 0x00;
+        for (byteIndex = maxByteIndex + 1 ; byteIndex <= maxmaxByteIndex;
+             ++byteIndex)
+            destSelectorP->localRecord[byteIndex] = 0x00;
+        for (byteIndex = minByteIndex; byteIndex <= maxByteIndex; ++byteIndex)
+            destSelectorP->localRecord[byteIndex] =
+                srcSelectorP->record[byteIndex];
+    }
+
+    *destSelectorPP = destSelectorP;
+}
+
+
+
+void
+pm_selector_mark(struct pm_selector * const selectorP,
+                 unsigned int         const index) {
+/*----------------------------------------------------------------------------
+   Mark index 'index'.
+-----------------------------------------------------------------------------*/
+    unsigned int  byteIndex = index / 8;
+    unsigned int  bitIndex  = index % 8;
+    unsigned char mask = (0x01 <<7) >> bitIndex;
+
+    /* set bit on to indicate presence of this index */
+
+    if (!selectorP->localRecord)
+        pm_error("INTERNAL ERROR: attempt to mark in a fixed pm_selector");
+
+    if ((selectorP->localRecord[byteIndex] & mask) == 0x00) {
+        /* if bit is not already set */
+
+        selectorP->localRecord[byteIndex] |= mask;
+        ++selectorP->count;  /* increment count */
+
+        /* reset min and max */
+        if (selectorP->min > index)
+            selectorP->min = index;
+        if (selectorP->max < index)
+            selectorP->max = index;
+    }
+}
+
+
+
+/* There is no function for erasing a marked bit */
+
+
+
+int  /* boolean */
+pm_selector_is_marked(const struct pm_selector * const selectorP,
+                      unsigned int               const index) {
+/*----------------------------------------------------------------------------
+  Index 'index' is marked.
+-----------------------------------------------------------------------------*/
+    bool retval;
+
+    if (selectorP) {
+        unsigned int  const byteIndex = index / 8;
+        unsigned int  const bitIndex  = index % 8;
+        unsigned char const mask = (0x01 <<7) >> bitIndex;
+
+        if ( index < selectorP->min || index > selectorP->max)
+            retval = false;
+        else if ((selectorP->record[byteIndex] & mask) != 0x00)
+            retval = true;
+        else
+            retval = false;
+    } else {
+        /* All entries are set to "exist" */
+        retval = true;
+    }
+    return retval ? 1 : 0;
+}
+
+
+
+unsigned int
+pm_selector_marked_ct(const struct pm_selector * const selectorP) {
+/*----------------------------------------------------------------------------
+   Number of indices that are marked.
+-----------------------------------------------------------------------------*/
+    return selectorP->count;
+}
+
+
+
+/*----------------------------------------------------------------------------
   Routines for loading a BDF font file
 -----------------------------------------------------------------------------*/
 
@@ -110,14 +315,13 @@ tokenize(char *         const s,
 
     while (*p) {
         if (!ISGRAPH(*p)) {
-            if(!ISSPACE(*p)) {
-              /* Control chars excluding 09 - 0d (space), 80-ff */
-            pm_message("Warning: non-ASCII character '%x' in "
-                       "BDF font file", *p);
+            if (!ISSPACE(*p)) {
+                /* Control chars excluding 09 - 0d (space), 80-ff */
+                pm_message("Warning: non-ASCII character '%x' in "
+                           "BDF font file", *p);
             }
             *p++ = '\0';
-        }
-        else {
+        } else {
             words[n++] = p;
             if (n >= wordsSz - 1)
                 break;
@@ -193,6 +397,7 @@ parseBitmapRow(const char *    const hex,
                         glyphWidth, hex);
         else {
             char const hdig = *p++;
+
             unsigned int hdigValue;
 
             if (hdig >= '0' && hdig <= '9')
@@ -315,7 +520,7 @@ static void
 validateWordCount(Readline *    const readlineP,
                   unsigned int  const nWords) {
 
-    if( readlineP->wordCt != nWords )
+    if (readlineP->wordCt != nWords)
         pm_error("Wrong number of arguments in '%s' line in BDF font file",
                  readlineP->arg[0]);
 
@@ -334,7 +539,6 @@ readExpectedStatement(Readline *    const readlineP,
   beginning of the line is that, e.g. "STARTFONT").  Check for the number
   of words: 'nWords'.  If either condition is not met, fail the program.
 -----------------------------------------------------------------------------*/
-
     bool eof;
 
     readline_read(readlineP, &eof);
@@ -354,21 +558,22 @@ readExpectedStatement(Readline *    const readlineP,
 static void
 skipCharacter(Readline * const readlineP) {
 /*----------------------------------------------------------------------------
-  In the BDF font file being read by readline object *readlineP, skip through
-  the end of the character we are presently in.
+  In the BDF font file being read by readline object *readlineP, skip
+  through to the end of the data for the character we are presently in.
+
+  At entry the stream must be positioned at the end of the ENCODING line.
 -----------------------------------------------------------------------------*/
-    bool endChar;
+    char * rc;
+    do {
+        rc = fgets(readlineP->line, MAXBDFLINE+1, readlineP->ifP);
+        readlineP->line[7] = '\0';
 
-    endChar = FALSE;
+    } while (rc != NULL && !streq(readlineP->line, "ENDCHAR"));
+
+    if (rc == NULL)
+        pm_error("End of file in the middle of a character (before "
+                 "ENDCHAR) in BDF font file.");
 
-    while (!endChar) {
-        bool eof;
-        readline_read(readlineP, &eof);
-        if (eof)
-            pm_error("End of file in the middle of a character (before "
-                     "ENDCHAR) in BDF font file.");
-        endChar = streq(readlineP->arg[0], "ENDCHAR");
-    }
 }
 
 
@@ -425,16 +630,21 @@ interpEncoding(const char **  const arg,
     bool badCodepoint;
     unsigned int codepoint;
 
+    gotCodepoint = false;  /* initial value */
+
     if (wordToInt(arg[1]) >= 0) {
         codepoint = wordToInt(arg[1]);
         gotCodepoint = true;
     } else {
-      if (wordToInt(arg[1]) == -1 && arg[2] != NULL) {
-            codepoint = wordToInt(arg[2]);
-            gotCodepoint = true;
-        } else
-            gotCodepoint = false;
+        if (wordToInt(arg[1]) == -1 && arg[2] != NULL) {
+            int const codepoint0 = wordToInt(arg[2]);
+            if (codepoint0 >= 0) {
+                codepoint = codepoint0;
+                gotCodepoint = true;
+            }
+        }
     }
+
     if (gotCodepoint) {
         if (codepoint > maxmaxglyph)
             badCodepoint = true;
@@ -455,8 +665,9 @@ readEncoding(Readline *     const readlineP,
              bool *         const badCodepointP,
              PM_WCHAR       const maxmaxglyph) {
 
+    const char * const expected = "ENCODING";
+
     bool eof;
-    const char * expected = "ENCODING";
 
     readline_read(readlineP, &eof);
 
@@ -465,7 +676,7 @@ readEncoding(Readline *     const readlineP,
     else if (!streq(readlineP->arg[0], expected))
         pm_error("Statement of type '%s' where '%s' expected in BDF font file",
                  readlineP->arg[0], expected);
-    else if(readlineP->wordCt != 2 &&  readlineP->wordCt != 3)
+    else if (readlineP->wordCt != 2 &&  readlineP->wordCt != 3)
         pm_error("Wrong number of arguments in '%s' line in BDF font file",
                  readlineP->arg[0]);
 
@@ -538,112 +749,148 @@ validateGlyphLimits(const struct font2 * const font2P,
 
 
 static void
-processChars(Readline *     const readlineP,
-             struct font2 * const font2P) {
-/*----------------------------------------------------------------------------
-   Process the CHARS block in a BDF font file, assuming the file is positioned
-   just after the CHARS line.  Read the rest of the block and apply its
-   contents to *font2P.
------------------------------------------------------------------------------*/
-    unsigned int const nCharacters = wordToInt(readlineP->arg[1]);
-
-    unsigned int nCharsDone;
-    unsigned int nCharsValid;
-
-    for (nCharsDone = 0, nCharsValid = 0;
-         nCharsDone < nCharacters; ) {
+readStartchar(Readline * const readlineP,
+              const char ** charNameP) {
 
+        const char * charName;
         bool eof;
 
         readline_read(readlineP, &eof);
         if (eof)
             pm_error("End of file after CHARS reading BDF font file");
 
-        if (streq(readlineP->arg[0], "COMMENT")) {
+        while (streq(readlineP->arg[0], "COMMENT")) {
+            readline_read(readlineP, &eof);
+            if (eof)
+                 pm_error("End of file after CHARS reading BDF font file");
             /* ignore */
-        } else if (!streq(readlineP->arg[0], "STARTCHAR"))
+        }
+
+        if (!streq(readlineP->arg[0], "STARTCHAR"))
             pm_error("%s detected where \'STARTCHAR\' expected "
                      "in BDF font file", readlineP->arg[0] );
-        else {
-            const char * charName;
-
-            struct glyph * glyphP;
-            unsigned int codepoint;
-            bool badCodepoint;
-
-            if (readlineP->wordCt < 2)
-                pm_error("Wrong number of arguments in STARTCHAR line "
-                         "in BDF font file");
+        else if (readlineP->wordCt < 2)
+            pm_error("Wrong number of arguments in STARTCHAR line "
+                      "in BDF font file");
             /* Character name may contain spaces: there may be more than
                three words in the line.
              */
+        else
             charName = pm_strdup(readlineP->arg[1]);
 
-            assert(streq(readlineP->arg[0], "STARTCHAR"));
+        *charNameP = charName;
+}
 
-            MALLOCVAR(glyphP);
 
-            if (glyphP == NULL)
-                pm_error("no memory for font glyph for '%s' character",
-                         charName);
 
-            readEncoding(readlineP, &codepoint, &badCodepoint,
-                         font2P->maxmaxglyph);
+static void
+readGlyph(Readline * const readlineP,
+          const char * const charName,
+          const struct font2 * const font2P,
+          struct glyph ** const glyphPP) {
+
+    struct glyph * glyphP;
+
+    MALLOCVAR(glyphP);
+    if (glyphP == NULL)
+        pm_error("no memory for font glyph for '%s' character",
+             charName);
 
-            if (badCodepoint)
-                skipCharacter(readlineP);
-            else {
-                if (codepoint < font2P->maxglyph) {
-                    if (font2P->glyph[codepoint] != NULL)
-                        pm_error("Multiple definition of code point %u "
-                                 "in BDF font file", (unsigned int) codepoint);
-                    else
-                        pm_message("Reverse order detected in BDF file. "
-                                   "Code point %u defined after %u",
-                                    (unsigned int) codepoint,
-                                    (unsigned int) font2P->maxglyph);
-                } else {
-                    /* Initialize all characters in the gap to nonexistent */
-                    unsigned int i;
-                    unsigned int const oldMaxglyph = font2P->maxglyph;
-                    unsigned int const newMaxglyph = codepoint;
+    readExpectedStatement(readlineP, "SWIDTH", 3);
+
+    readExpectedStatement(readlineP, "DWIDTH", 3);
+    glyphP->xadd = wordToInt(readlineP->arg[1]);
+
+    readExpectedStatement(readlineP, "BBX", 5);
+    glyphP->width  = wordToInt(readlineP->arg[1]);
+    glyphP->height = wordToInt(readlineP->arg[2]);
+    glyphP->x      = wordToInt(readlineP->arg[3]);
+    glyphP->y      = wordToInt(readlineP->arg[4]);
+
+    validateGlyphLimits(font2P, glyphP, charName);
+
+    createBmap(glyphP->width, glyphP->height, readlineP, charName,
+               &glyphP->bmap);
+
+    *glyphPP = glyphP;
+}
+
+
+
+static void
+processChars(Readline *     const readlineP,
+             struct font2 * const font2P) {
+/*----------------------------------------------------------------------------
+   Process the CHARS block in a BDF font file, assuming the file is positioned
+   just after the CHARS line.  Read the rest of the block and apply its
+   contents to *font2P.
+-----------------------------------------------------------------------------*/
+    unsigned int const nCharacters = wordToInt(readlineP->arg[1]);
+    unsigned int const nCharsWanted = (font2P->selectorP != NULL) ?
+        font2P->selectorP->count : nCharacters;
 
-                    for (i = oldMaxglyph + 1; i < newMaxglyph; ++i)
-                        font2P->glyph[i] = NULL;
+    unsigned int nCharsEncountered;
+    unsigned int nCharsLoaded;
 
-                    font2P->maxglyph = newMaxglyph;
-                    }
+    for (nCharsEncountered = 0, nCharsLoaded = 0;
+         nCharsEncountered < nCharacters && nCharsLoaded < nCharsWanted;
+         ++nCharsEncountered ) {
 
-                readExpectedStatement(readlineP, "SWIDTH", 3);
+        const char * charName;
+        unsigned int codepoint;
+        bool badCodepoint;
 
-                readExpectedStatement(readlineP, "DWIDTH", 3);
-                glyphP->xadd = wordToInt(readlineP->arg[1]);
+        readStartchar(readlineP, &charName);
 
-                readExpectedStatement(readlineP, "BBX", 5);
-                glyphP->width  = wordToInt(readlineP->arg[1]);
-                glyphP->height = wordToInt(readlineP->arg[2]);
-                glyphP->x      = wordToInt(readlineP->arg[3]);
-                glyphP->y      = wordToInt(readlineP->arg[4]);
+        readEncoding(readlineP, &codepoint, &badCodepoint,
+                         font2P->maxmaxglyph);
 
-                validateGlyphLimits(font2P, glyphP, charName);
+        if ( badCodepoint ) {
+            skipCharacter(readlineP);
+            pm_strfree (charName);
+            }
+        else if (!pm_selector_is_marked(font2P->selectorP, codepoint) ) {
+            skipCharacter(readlineP);
+            pm_strfree (charName);
+            font2P->maxglyph = codepoint;
+            }
+        else {
+            if (codepoint < font2P->maxglyph) {
+                if (font2P->glyph[codepoint] != NULL )
+                       pm_error("Multiple definition of code point %u "
+                                "in BDF font file", (unsigned int) codepoint);
+                else
+                       pm_message("Reverse order detected in BDF file. "
+                                  "Code point %u defined after %u",
+                                   (unsigned int) codepoint,
+                                   (unsigned int) font2P->maxglyph);
+            }
 
-                createBmap(glyphP->width, glyphP->height, readlineP, charName,
-                           &glyphP->bmap);
+            {
+            struct glyph * glyphP;
 
-                readExpectedStatement(readlineP, "ENDCHAR", 1);
+            readGlyph(readlineP, charName, font2P, &glyphP);
+            readExpectedStatement(readlineP, "ENDCHAR", 1);
 
-                assert(codepoint <= font2P->maxmaxglyph);
-                /* Ensured by readEncoding() */
+            assert(codepoint <= font2P->maxmaxglyph);
+            /* Ensured by readEncoding() */
 
-                font2P->glyph[codepoint] = glyphP;
-                pm_strfree(charName);
+            font2P->glyph[codepoint] = glyphP;
+            pm_strfree(charName);
 
-                ++nCharsValid;
+            font2P->maxglyph = codepoint;
+            ++nCharsLoaded;
             }
-            ++nCharsDone;
         }
     }
-    font2P->chars = nCharsValid;
+
+    /* Note that BDF file may have reached end before the largest entry
+       in selector was checked.  */
+    /*
+    if (font2P->selectorP->max > font2P->maxglyph)
+       font2P->maxglyph = font2P->selectorP->max;
+    */
+    font2P->chars       = nCharsLoaded;
     font2P->total_chars = nCharacters;
 }
 
@@ -718,7 +965,6 @@ loadCharsetString(const char *  const registry,
 
 
 
-
 static unsigned int const maxTokenLen = 60;
 
 
@@ -904,6 +1150,9 @@ processBdfFontLine(Readline     * const readlineP,
       else {
         validateWordCount(readlineP, 2);  /* CHARS n */
         processChars(readlineP, font2P);
+        if (font2P->selectorP != NULL &&
+            font2P->selectorP->count == font2P->chars)
+               *endOfFontP = true;
       }
     } else {
         /* ignore */
@@ -913,9 +1162,38 @@ processBdfFontLine(Readline     * const readlineP,
 
 
 
+static void
+initializeGlyphArray(struct font2 * const font2P,
+                     unsigned int   const maxmaxglyph) {
+/*----------------------------------------------------------------------------
+  Initialize glyph array based on entries in selector.
+  Note that only valid codepoints are set to NULL.
+  Entries for unused glyphs are left untouched.
+-----------------------------------------------------------------------------*/
+    const struct pm_selector * const selectorP = font2P->selectorP;
+    unsigned int const min = (selectorP == NULL) ? 0 : selectorP->min;
+    unsigned int const max =
+        (selectorP == NULL) ? font2P->maxglyph : selectorP->max;
+
+    unsigned int codepoint;
+
+    for (codepoint = min; codepoint <= max ; ++codepoint)
+        if (pm_selector_is_marked(selectorP, codepoint) == true)
+             font2P->glyph[codepoint] = NULL;
+
+    font2P->glyph[L' '] = NULL;
+        /* Clear the slot for space character.
+           It may not be defined in the font, but the program may try
+           to use space as a substitute char
+        */
+}
+
+
+
 struct font2 *
-pbm_loadbdffont2(const char * const filename,
-                 PM_WCHAR     const maxmaxglyph) {
+pbm_loadbdffont2select(const char *               const filename,
+                       PM_WCHAR                   const maxmaxglyph,
+                       const struct pm_selector * const selectorP) {
 /*----------------------------------------------------------------------------
    Read a BDF font file "filename" as a 'font2' structure.  A 'font2'
    structure is more expressive than a 'font' structure, most notably in that
@@ -925,8 +1203,10 @@ pbm_loadbdffont2(const char * const filename,
 
    The returned object is in new malloc'ed storage, in many pieces.
    When done with, destroy with pbm_destroybdffont2().
------------------------------------------------------------------------------*/
 
+   The returned object refers to *selectorP, so that must continue to exist
+   until you call pbm_destroybdffont2().
+-----------------------------------------------------------------------------*/
     FILE *         ifP;
     Readline       readline;
     struct font2 * font2P;
@@ -943,8 +1223,14 @@ pbm_loadbdffont2(const char * const filename,
 
     font2P->maxglyph = 0;
         /* Initial value.  Increases as new characters are loaded */
-    font2P->glyph[0] = NULL;
-        /* Initial value.  Overwrite later if codepoint 0 is defined. */
+
+    if (font2P->selectorP == NULL) {
+        PM_WCHAR i;
+
+        for (i = 0; i <= maxmaxglyph; ++i)
+            font2P->glyph[i] = NULL;
+            /* Initial value.  Overwrite later if codepoint i is defined. */
+    }
 
     font2P->maxmaxglyph = maxmaxglyph;
 
@@ -955,6 +1241,9 @@ pbm_loadbdffont2(const char * const filename,
     font2P->chars = font2P->total_chars = 0;
     font2P->default_char = 0;
     font2P->default_char_defined = FALSE;
+    font2P->selectorP = (struct pm_selector * const) selectorP;
+
+    initializeGlyphArray(font2P, maxmaxglyph);
 
     readExpectedStatement(&readline, "STARTFONT", 2);
 
@@ -970,9 +1259,13 @@ pbm_loadbdffont2(const char * const filename,
     }
     fclose(ifP);
 
-    if(font2P->chars == 0)
+    if (font2P->total_chars == 0)
         pm_error("No glyphs found in BDF font file "
                  "in codepoint range 0 - %u", (unsigned int) maxmaxglyph);
+    if (font2P->chars == 0)
+        pm_error("Not any requested glyphs found in BDF font file "
+                 "in codepoint range 0 - %u", (unsigned int) maxmaxglyph);
+
 
     REALLOCARRAY(font2P->glyph, font2P->maxglyph + 1);
 
@@ -986,10 +1279,21 @@ pbm_loadbdffont2(const char * const filename,
 }
 
 
+
+struct font2 *
+pbm_loadbdffont2(const char * const filename,
+                 PM_WCHAR     const maxmaxglyph) {
+
+    return pbm_loadbdffont2select(filename, maxmaxglyph, NULL);
+}
+
+
+
 static struct font *
 font2ToFont(const struct font2 * const font2P) {
-            struct font  * fontP;
-            unsigned int   codePoint;
+
+    struct font  * fontP;
+    unsigned int   codePoint;
 
     MALLOCVAR(fontP);
     if (fontP == NULL)
@@ -1001,18 +1305,10 @@ font2ToFont(const struct font2 * const font2P) {
     fontP->x = font2P->x;
     fontP->y = font2P->y;
 
-    for (codePoint = 0; codePoint <= font2P->maxglyph; ++codePoint)
-        fontP->glyph[codePoint] = font2P->glyph[codePoint];
-
-    /* font2P->maxglyph is typically 255 (PM_FONT_MAXGLYPH) or larger.
-       But in some rare cases it is smaller.
-       If an ASCII-only font is read, it will be 126 or 127.
-
-       Set remaining codepoints up to PM_FONT_MAXGLYPH, if any, to NULL
-    */
-
-    for ( ; codePoint <= PM_FONT_MAXGLYPH; ++codePoint)
-        fontP->glyph[codePoint] = NULL;
+    for (codePoint = 0; codePoint <= PM_FONT_MAXGLYPH; ++codePoint)
+        fontP->glyph[codePoint] =
+             pm_selector_is_marked(font2P->selectorP, codePoint) ?
+             font2P->glyph[codePoint] : NULL;
 
     /* Give values to legacy fields */
     fontP->oldfont = font2P->oldfont;
diff --git a/lib/libpm.c b/lib/libpm.c
index 47a2f498..78d941fa 100644
--- a/lib/libpm.c
+++ b/lib/libpm.c
@@ -368,7 +368,7 @@ pm_freearray(char ** const rowIndex,
 /* Case-insensitive keyword matcher. */
 
 int
-pm_keymatch(const char *       const strarg,
+pm_keymatch(const char * const strarg,
             const char * const keywordarg,
             int          const minchars) {
     int len;
@@ -770,10 +770,10 @@ extractAfterLastSlash(const char * const fullPath,
     slashPos = strrchr(fullPath, '/');
 
     if (slashPos == NULL) {
-        strncpy(retval, fullPath, retvalSize);
+        strncpy(retval, fullPath, retvalSize-1);
         retval[retvalSize-1] = '\0';
     } else {
-        strncpy(retval, slashPos +1, retvalSize);
+        strncpy(retval, slashPos + 1, retvalSize-1);
         retval[retvalSize-1] = '\0';
     }
 }
@@ -844,6 +844,9 @@ pm_parse_width(const char * const arg) {
    Return the image width represented by the decimal ASCIIZ string
    'arg'.  Fail if it doesn't validly represent a width or represents
    a width that can't be conveniently used in computation.
+
+   See comments at 'validateComputableSize' in libpam.c for details on
+   the purpose of these validations.
 -----------------------------------------------------------------------------*/
     unsigned int width;
     const char * error;
diff --git a/lib/libpnm2.c b/lib/libpnm2.c
index fa4bb8be..6fec91e9 100644
--- a/lib/libpnm2.c
+++ b/lib/libpnm2.c
@@ -23,11 +23,11 @@
 
 
 void
-pnm_writepnminit(FILE * const fileP, 
-                 int    const cols, 
-                 int    const rows, 
-                 xelval const maxval, 
-                 int    const format, 
+pnm_writepnminit(FILE * const fileP,
+                 int    const cols,
+                 int    const rows,
+                 xelval const maxval,
+                 int    const format,
                  int    const forceplain) {
 
     bool const plainFormat = forceplain || pm_plain_output;
@@ -47,7 +47,7 @@ pnm_writepnminit(FILE * const fileP,
 
     default:
         pm_error("invalid format argument received by pnm_writepnminit(): %d"
-                 "PNM_FORMAT_TYPE(format) must be %d, %d, or %d", 
+                 "PNM_FORMAT_TYPE(format) must be %d, %d, or %d",
                  format, PBM_TYPE, PGM_TYPE, PPM_TYPE);
     }
 }
@@ -55,19 +55,19 @@ pnm_writepnminit(FILE * const fileP,
 
 
 static void
-writepgmrow(FILE *       const fileP, 
-            const xel *  const xelrow, 
-            unsigned int const cols, 
-            xelval       const maxval, 
-            int          const format, 
+writepgmrow(FILE *       const fileP,
+            const xel *  const xelrow,
+            unsigned int const cols,
+            xelval       const maxval,
+            int          const format,
             bool         const plainFormat) {
-    
+
     jmp_buf jmpbuf;
     jmp_buf * origJmpbufP;
     gray * grayrow;
-    
+
     grayrow = pgm_allocrow(cols);
-    
+
     if (setjmp(jmpbuf) != 0) {
         pgm_freerow(grayrow);
         pm_setjmpbuf(origJmpbufP);
@@ -76,10 +76,10 @@ writepgmrow(FILE *       const fileP,
         unsigned int col;
 
         pm_setjmpbufsave(&jmpbuf, &origJmpbufP);
-        
+
         for (col = 0; col < cols; ++col)
             grayrow[col] = PNM_GET1(xelrow[col]);
-    
+
         pgm_writepgmrow(fileP, grayrow, cols, (gray) maxval, plainFormat);
 
         pm_setjmpbuf(origJmpbufP);
@@ -100,7 +100,7 @@ writepbmrow(FILE *       const fileP,
     bit * bitrow;
 
     bitrow = pbm_allocrow(cols);
-    
+
     if (setjmp(jmpbuf) != 0) {
         pbm_freerow(bitrow);
         pm_setjmpbuf(origJmpbufP);
@@ -112,29 +112,29 @@ writepbmrow(FILE *       const fileP,
 
         for (col = 0; col < cols; ++col)
             bitrow[col] = PNM_GET1(xelrow[col]) == 0 ? PBM_BLACK : PBM_WHITE;
-    
+
         pbm_writepbmrow(fileP, bitrow, cols, plainFormat);
 
         pm_setjmpbuf(origJmpbufP);
     }
     pbm_freerow(bitrow);
-}    
+}
 
 
 
 void
-pnm_writepnmrow(FILE *      const fileP, 
-                const xel * const xelrow, 
-                int         const cols, 
-                xelval      const maxval, 
-                int         const format, 
+pnm_writepnmrow(FILE *      const fileP,
+                const xel * const xelrow,
+                int         const cols,
+                xelval      const maxval,
+                int         const format,
                 int         const forceplain) {
 
     bool const plainFormat = forceplain || pm_plain_output;
-    
+
     switch (PNM_FORMAT_TYPE(format)) {
     case PPM_TYPE:
-        ppm_writeppmrow(fileP, (pixel*) xelrow, cols, (pixval) maxval, 
+        ppm_writeppmrow(fileP, (pixel*) xelrow, cols, (pixval) maxval,
                         plainFormat);
         break;
 
@@ -145,10 +145,10 @@ pnm_writepnmrow(FILE *      const fileP,
     case PBM_TYPE:
         writepbmrow(fileP, xelrow, cols, plainFormat);
         break;
-    
+
     default:
         pm_error("invalid format argument received by pnm_writepnmrow(): %d"
-                 "PNM_FORMAT_TYPE(format) must be %d, %d, or %d", 
+                 "PNM_FORMAT_TYPE(format) must be %d, %d, or %d",
                  format, PBM_TYPE, PGM_TYPE, PPM_TYPE);
     }
 }
@@ -167,7 +167,10 @@ pnm_writepnm(FILE * const fileP,
     unsigned int row;
 
     pnm_writepnminit(fileP, cols, rows, maxval, format, forceplain);
-    
+
     for (row = 0; row < rows; ++row)
         pnm_writepnmrow(fileP, xels[row], cols, maxval, format, forceplain);
 }
+
+
+
diff --git a/lib/libpnm3.c b/lib/libpnm3.c
index 3970c734..ba408bd1 100644
--- a/lib/libpnm3.c
+++ b/lib/libpnm3.c
@@ -106,10 +106,14 @@ pnm_backgroundxelrow(xel *  const xelrow,
                      int    const cols,
                      xelval const maxval,
                      int    const format) {
+/*----------------------------------------------------------------------------
+   Guess a good background color for an image that contains row 'xelrow'
+   (probably top or bottom edge).
 
+   'cols', 'maxval', and 'format' describe 'xelrow'.
+-----------------------------------------------------------------------------*/
     xel bgxel, l, r;
 
-    /* Guess a good background value. */
     l = xelrow[0];
     r = xelrow[cols-1];
 
diff --git a/lib/libppmcmap.c b/lib/libppmcmap.c
index f78d0516..0f6439ae 100644
--- a/lib/libppmcmap.c
+++ b/lib/libppmcmap.c
@@ -34,8 +34,8 @@ ppm_hashpixel(pixel const p) {
 
 
 colorhist_vector
-ppm_computecolorhist( pixel ** const pixels, 
-                      const int cols, const int rows, const int maxcolors, 
+ppm_computecolorhist( pixel ** const pixels,
+                      const int cols, const int rows, const int maxcolors,
                       int * const colorsP ) {
 /*----------------------------------------------------------------------------
    Compute a color histogram for the image described by 'pixels',
@@ -45,7 +45,7 @@ ppm_computecolorhist( pixel ** const pixels,
 
    If 'maxcolors' is zero, make the output have 5 spare slots at the end
    for expansion.
-   
+
    If 'maxcolors' is nonzero, make the output have 'maxcolors' slots in
    it, and if there are more colors than that in the image, don't return
    anything except a NULL pointer.
@@ -66,29 +66,36 @@ ppm_computecolorhist( pixel ** const pixels,
 
 
 colorhist_vector
-ppm_computecolorhist2(FILE * const ifp,
-                      const int cols, const int rows, 
-                      const pixval maxval, const int format, 
-                      const int maxcolors, int * const colorsP ) {
+ppm_computecolorhist2(FILE * const ifP,
+                      int    const cols,
+                      int    const rows,
+                      pixval const maxval,
+                      int    const format,
+                      int    const maxcolorCt,
+                      int *  const colorCtP ) {
 
-    colorhash_table cht;
-    colorhist_vector chv;
+    colorhist_vector retval;
+    colorhash_table  cht;
 
-    cht = ppm_computecolorhash2(ifp, cols, rows, maxval, format, 
-                                maxcolors, colorsP);
+    cht = ppm_computecolorhash2(ifP, cols, rows, maxval, format,
+                                maxcolorCt, colorCtP);
     if (cht ==NULL)
-        return NULL;
-    chv = ppm_colorhashtocolorhist(cht, maxcolors);
-    ppm_freecolorhash(cht);
-    return chv;
+        retval = NULL;
+    else {
+        retval = ppm_colorhashtocolorhist(cht, maxcolorCt);
+
+        ppm_freecolorhash(cht);
+    }
+
+    return retval;
 }
 
 
 
 void
-ppm_addtocolorhist( colorhist_vector chv, 
-                    int * const colorsP, const int maxcolors, 
-                    const pixel * const colorP, 
+ppm_addtocolorhist( colorhist_vector chv,
+                    int * const colorsP, const int maxcolors,
+                    const pixel * const colorP,
                     const int value, const int position ) {
     int i, j;
 
@@ -149,16 +156,16 @@ ppm_alloccolorhash(void)  {
 
 
 static void
-readppmrow(FILE *        const fileP, 
-           pixel *       const pixelrow, 
-           int           const cols, 
-           pixval        const maxval, 
+readppmrow(FILE *        const fileP,
+           pixel *       const pixelrow,
+           int           const cols,
+           pixval        const maxval,
            int           const format,
            const char ** const errorP) {
 
     jmp_buf jmpbuf;
     jmp_buf * origJmpbufP;
-    
+
     if (setjmp(jmpbuf) != 0) {
         pm_setjmpbuf(origJmpbufP);
         pm_asprintf(errorP, "Failed to read row of image.");
@@ -168,7 +175,7 @@ readppmrow(FILE *        const fileP,
         ppm_readppmrow(fileP, pixelrow, cols, maxval, format);
 
         *errorP = NULL; /* Would have longjmped if anything went wrong */
-                
+
         pm_setjmpbuf(origJmpbufP);
     }
 }
@@ -213,15 +220,15 @@ buildHashTable(FILE *          const ifP,
         if (ifP) {
             readppmrow(ifP, rowbuffer, cols, maxval, format, errorP);
             pixelrow = rowbuffer;
-        } else 
+        } else
             pixelrow = pixels[row];
 
         for (col = 0; col < cols && !*tooManyColorsP && !*errorP; ++col) {
             const pixel apixel = pixelrow[col];
             const int hash = ppm_hashpixel(apixel);
-            colorhist_list chl; 
+            colorhist_list chl;
 
-            for (chl = cht[hash]; 
+            for (chl = cht[hash];
                  chl && !PPM_EQUAL(chl->ch.color, apixel);
                  chl = chl->next);
 
@@ -251,9 +258,9 @@ buildHashTable(FILE *          const ifP,
 
 
 static void
-computecolorhash(pixel **          const pixels, 
+computecolorhash(pixel **          const pixels,
                  unsigned int      const cols,
-                 unsigned int      const rows, 
+                 unsigned int      const rows,
                  unsigned int      const maxcolors,
                  int *             const nColorsP,
                  FILE *            const ifP,
@@ -271,8 +278,8 @@ computecolorhash(pixel **          const pixels,
       'pixels' is NULL and 'ifP' is non-NULL.  ifP is the stream
       descriptor for the input file, and 'maxval' and 'format' are
       parameters of the image data in it.
-      
-      We return with the file still open and its position undefined.  
+
+      We return with the file still open and its position undefined.
 
    In either case, the image is 'cols' by 'rows'.
 
@@ -288,7 +295,7 @@ computecolorhash(pixel **          const pixels,
         */
 
     MALLOCARRAY(rowbuffer, cols);
-        
+
     if (rowbuffer == NULL)
         pm_asprintf(errorP, "Unable to allocate %u-column row buffer.", cols);
     else {
@@ -303,7 +310,7 @@ computecolorhash(pixel **          const pixels,
             buildHashTable(ifP, pixels, cols, rows, maxval, format, maxcolors,
                            cht, rowbuffer,
                            nColorsP, &tooManyColors, errorP);
-                
+
             if (tooManyColors) {
                 ppm_freecolorhash(cht);
                 *chtP = NULL;
@@ -320,16 +327,16 @@ computecolorhash(pixel **          const pixels,
 
 
 colorhash_table
-ppm_computecolorhash(pixel ** const pixels, 
+ppm_computecolorhash(pixel ** const pixels,
                      int      const cols,
-                     int      const rows, 
+                     int      const rows,
                      int      const maxcolors,
                      int *    const colorsP) {
 
     colorhash_table cht;
     const char * error;
 
-    computecolorhash(pixels, cols, rows, maxcolors, colorsP, 
+    computecolorhash(pixels, cols, rows, maxcolors, colorsP,
                      NULL, 0, 0, &cht, &error);
 
     if (error) {
@@ -345,9 +352,9 @@ ppm_computecolorhash(pixel ** const pixels,
 colorhash_table
 ppm_computecolorhash2(FILE * const ifP,
                       int    const cols,
-                      int    const rows, 
+                      int    const rows,
                       pixval const maxval,
-                      int    const format, 
+                      int    const format,
                       int    const maxcolors,
                       int *  const colorsP ) {
 
@@ -368,8 +375,8 @@ ppm_computecolorhash2(FILE * const ifP,
 
 
 int
-ppm_addtocolorhash(colorhash_table const cht, 
-                   const pixel *   const colorP, 
+ppm_addtocolorhash(colorhash_table const cht,
+                   const pixel *   const colorP,
                    int             const value) {
 /*----------------------------------------------------------------------------
    Add color *colorP to the color hash 'cht' with associated value 'value'.
@@ -397,7 +404,7 @@ ppm_addtocolorhash(colorhash_table const cht,
 
 
 void
-ppm_delfromcolorhash(colorhash_table const cht, 
+ppm_delfromcolorhash(colorhash_table const cht,
                      const pixel *   const colorP) {
 /*----------------------------------------------------------------------------
    Delete the color *colorP from the colorhahs 'cht', if it's there.
@@ -433,7 +440,7 @@ colorHashSize(colorhash_table const cht) {
     nColors = 0;
     for (i = 0; i < HASH_SIZE; ++i) {
         colorhist_list chl;
-        for (chl = cht[i]; chl; chl = chl->next) 
+        for (chl = cht[i]; chl; chl = chl->next)
             ++nColors;
     }
     return nColors;
@@ -445,8 +452,8 @@ colorhist_vector
 ppm_colorhashtocolorhist(colorhash_table const cht, int const maxcolors) {
 
     colorhist_vector chv;
-    colorhist_list chl;
-    unsigned int chvSize;
+    colorhist_list   chl;
+    unsigned int     chvSize;
 
     if (maxcolors == 0)
         /* We leave space for 5 more colors so caller can add in special
@@ -457,7 +464,7 @@ ppm_colorhashtocolorhist(colorhash_table const cht, int const maxcolors) {
         /* Caller is responsible for making sure there are no more
            than 'maxcolors' colors in the colorhash table.  NOTE:
            Before March 2002, the maxcolors == 0 invocation didn't
-           exist.  
+           exist.
         */
         chvSize = maxcolors;
 
@@ -483,7 +490,7 @@ ppm_colorhashtocolorhist(colorhash_table const cht, int const maxcolors) {
 
 
 colorhash_table
-ppm_colorhisttocolorhash(colorhist_vector const chv, 
+ppm_colorhisttocolorhash(colorhist_vector const chv,
                          int              const colors) {
 
     colorhash_table retval;
@@ -499,7 +506,7 @@ ppm_colorhisttocolorhash(colorhist_vector const chv,
         for (i = 0, error = NULL; i < colors && !error; ++i) {
             pixel const color = chv[i].color;
             int const hash = ppm_hashpixel(color);
-            
+
             colorhist_list chl;
 
             for (chl = cht[hash]; chl && !error; chl = chl->next)
@@ -534,7 +541,7 @@ ppm_colorhisttocolorhash(colorhist_vector const chv,
 
 
 int
-ppm_lookupcolor(colorhash_table const cht, 
+ppm_lookupcolor(colorhash_table const cht,
                 const pixel *   const colorP) {
     int hash;
     colorhist_list chl;
@@ -731,7 +738,7 @@ pixelCmp(const void * const a,
 
 void
 ppm_sortcolorrow(pixel * const colorrow,
-                 int     const ncolors, 
+                 int     const ncolors,
                  int (*cmpfunc)(pixel *, pixel *)) {
 
     if (cmpfunc) {
@@ -774,10 +781,10 @@ ppm_addtocolorrow(colorrow, ncolorsP, maxcolors, pixelP)
 
 
 int
-ppm_findclosestcolor(const pixel * const colormap, 
-                     int           const ncolors, 
+ppm_findclosestcolor(const pixel * const colormap,
+                     int           const ncolors,
                      const pixel * const pP) {
-    
+
     /* Search colormap for closest match.       */
 
     int i;
@@ -789,7 +796,7 @@ ppm_findclosestcolor(const pixel * const colormap,
 
     for(i = 0; i < ncolors && bestDist > 0; ++i) {
         unsigned int const dist = PPM_DISTANCE(*pP, colormap[i]);
-        
+
         if (dist < bestDist ) {
             ind = i;
             bestDist = dist;
diff --git a/lib/libppmd.c b/lib/libppmd.c
index a94ff107..e0654c8f 100644
--- a/lib/libppmd.c
+++ b/lib/libppmd.c
@@ -1,4 +1,4 @@
-/* 
+/*
 **
 ** This library module contains the ppmdraw routines.
 **
@@ -10,7 +10,7 @@
 ** copyright notice and this permission notice appear in supporting
 ** documentation.  This software is provided "as is" without express or
 ** implied warranty.
-** 
+**
 ** The character drawing routines are by John Walker
 ** Copyright (C) 1994 by John Walker, kelvin@fourmilab.ch
 */
@@ -85,7 +85,7 @@ pointIsWithinBounds(ppmd_point   const p,
     return (p.x >= 0 && p.x < cols && p.y >= 0 && p.y < rows);
 }
 
-        
+
 
 static ppmd_point
 vectorSum(ppmd_point const a,
@@ -102,7 +102,7 @@ static long int const DDA_SCALE = 8192;
 /*
   Several factors govern the limit of x, y coordination values.
 
-  The limit must be representable as (signed) int for coordinates to 
+  The limit must be representable as (signed) int for coordinates to
   be carried in struct penpos (immediately above).
 
   The following calculation, done with long ints, must not overflow:
@@ -112,7 +112,7 @@ static long int const DDA_SCALE = 8192;
   dy = (y1 - y0) * DDA_SCALE / abs(x1 - x0);
 
   Overflow conditions for ppmd_text are rather complicated, for commands
-  come from an external PPMD font file.  See comments below.  
+  come from an external PPMD font file.  See comments below.
 */
 
 
@@ -141,10 +141,10 @@ ppmd_validatePoint(ppmd_point const p) {
 static void
 drawPoint(ppmd_drawprocp       drawproc,
           const void *   const clientdata,
-          pixel **       const pixels, 
-          int            const cols, 
-          int            const rows, 
-          pixval         const maxval, 
+          pixel **       const pixels,
+          int            const cols,
+          int            const rows,
+          pixval         const maxval,
           ppmd_point     const p) {
 /*----------------------------------------------------------------------------
    Draw a single point, assuming that it is within the bounds of the
@@ -152,7 +152,7 @@ drawPoint(ppmd_drawprocp       drawproc,
 -----------------------------------------------------------------------------*/
     if (drawproc == PPMD_NULLDRAWPROC) {
         const pixel * const pixelP = clientdata;
-        
+
         assert(p.x >= 0); assert(p.x < cols);
         assert(p.y >= 0); assert(p.y < rows);
 
@@ -176,7 +176,7 @@ makeDrawProcXY(ppmd_drawproc * const drawProc,
 
     retval.drawProc   = drawProc;
     retval.clientData = clientData;
-    
+
     return retval;
 }
 
@@ -204,10 +204,10 @@ drawProcPointXY(pixel **     const pixels,
 
 
 void
-ppmd_point_drawprocp(pixel **     const pixels, 
-                     unsigned int const cols, 
-                     unsigned int const rows, 
-                     pixval       const maxval, 
+ppmd_point_drawprocp(pixel **     const pixels,
+                     unsigned int const cols,
+                     unsigned int const rows,
+                     pixval       const maxval,
                      ppmd_point   const p,
                      const void * const clientdata) {
 
@@ -218,16 +218,16 @@ ppmd_point_drawprocp(pixel **     const pixels,
 
 
 void
-ppmd_point_drawproc(pixel**     const pixels, 
-                    int         const cols, 
-                    int         const rows, 
-                    pixval      const maxval, 
-                    int         const x, 
-                    int         const y, 
+ppmd_point_drawproc(pixel**     const pixels,
+                    int         const cols,
+                    int         const rows,
+                    pixval      const maxval,
+                    int         const x,
+                    int         const y,
                     const void* const clientdata) {
 
     ppmd_point p;
-    
+
     p.x = x;
     p.y = y;
 
@@ -264,14 +264,14 @@ findRectangleIntersection(struct rectangle   const rect1,
 
 
 void
-ppmd_filledrectangle(pixel **      const pixels, 
-                     int           const cols, 
-                     int           const rows, 
-                     pixval        const maxval, 
-                     int           const x, 
-                     int           const y, 
-                     int           const width, 
-                     int           const height, 
+ppmd_filledrectangle(pixel **      const pixels,
+                     int           const cols,
+                     int           const rows,
+                     pixval        const maxval,
+                     int           const x,
+                     int           const y,
+                     int           const width,
+                     int           const height,
                      ppmd_drawproc       drawProc,
                      const void *  const clientdata) {
 
@@ -437,16 +437,16 @@ clipEnd1(ppmd_point   const p0,
    at 0.
 -----------------------------------------------------------------------------*/
     ppmd_point c1;
-        /* The current clipped location of p1; we clip it multile times
+        /* The current clipped location of p1; we clip it multiple times
            to get the final location.
         */
     /* p0 is in the frame: */
     assert(p0.x >= 0 && p0.x < cols);
     assert(p0.y >= 0 && p0.y < rows);
-    
+
     /* Clip End 1 of the line horizontally */
     c1 = p1;  /* initial value */
-    
+
     if (c1.x < 0) {
         /* We know the line isn't vertical, since End 0 is in the frame
            and End 1 is left of frame.
@@ -460,7 +460,7 @@ clipEnd1(ppmd_point   const p0,
         c1.y = c1.y + (p0.y - c1.y) * (cols - 1 - c1.x) / (p0.x - c1.x);
         c1.x = cols - 1;
     }
-    
+
     /* Clip End 1 of the line vertically */
     if (c1.y < 0) {
         /* We know the line isn't horizontal, since End 0 is in the frame
@@ -524,10 +524,10 @@ clipLine(ppmd_point   const p0,
 static void
 drawShallowLine(ppmd_drawprocp       drawProc,
                 const void *   const clientdata,
-                pixel **       const pixels, 
-                int            const cols, 
-                int            const rows, 
-                pixval         const maxval, 
+                pixel **       const pixels,
+                int            const cols,
+                int            const rows,
+                pixval         const maxval,
                 ppmd_point     const p0,
                 ppmd_point     const p1) {
 /*----------------------------------------------------------------------------
@@ -571,10 +571,10 @@ drawShallowLine(ppmd_drawprocp       drawProc,
 static void
 drawSteepLine(ppmd_drawprocp       drawProc,
               const void *   const clientdata,
-              pixel **       const pixels, 
-              int            const cols, 
-              int            const rows, 
-              pixval         const maxval, 
+              pixel **       const pixels,
+              int            const cols,
+              int            const rows,
+              pixval         const maxval,
               ppmd_point     const p0,
               ppmd_point     const p1) {
 /*----------------------------------------------------------------------------
@@ -617,10 +617,10 @@ drawSteepLine(ppmd_drawprocp       drawProc,
 
 
 void
-ppmd_linep(pixel **       const pixels, 
-           int            const cols, 
-           int            const rows, 
-           pixval         const maxval, 
+ppmd_linep(pixel **       const pixels,
+           int            const cols,
+           int            const rows,
+           pixval         const maxval,
            ppmd_point     const p0,
            ppmd_point     const p1,
            ppmd_drawprocp       drawProc,
@@ -662,14 +662,14 @@ ppmd_linep(pixel **       const pixels,
 
 
 void
-ppmd_line(pixel **      const pixels, 
-          int           const cols, 
-          int           const rows, 
-          pixval        const maxval, 
-          int           const x0, 
-          int           const y0, 
-          int           const x1, 
-          int           const y1, 
+ppmd_line(pixel **      const pixels,
+          int           const cols,
+          int           const rows,
+          pixval        const maxval,
+          int           const x0,
+          int           const y0,
+          int           const x1,
+          int           const y1,
           ppmd_drawproc       drawProc,
           const void *  const clientData) {
 
@@ -701,10 +701,10 @@ static unsigned int
 
 
 void
-ppmd_spline3p(pixel **       const pixels, 
-              int            const cols, 
-              int            const rows, 
-              pixval         const maxval, 
+ppmd_spline3p(pixel **       const pixels,
+              int            const cols,
+              int            const rows,
+              pixval         const maxval,
               ppmd_point     const p0,
               ppmd_point     const ctl,
               ppmd_point     const p1,
@@ -740,16 +740,16 @@ ppmd_spline3p(pixel **       const pixels,
 
 
 void
-ppmd_spline3(pixel **      const pixels, 
-             int           const cols, 
-             int           const rows, 
-             pixval        const maxval, 
-             int           const x0, 
-             int           const y0, 
-             int           const x1, 
-             int           const y1, 
-             int           const x2, 
-             int           const y2, 
+ppmd_spline3(pixel **      const pixels,
+             int           const cols,
+             int           const rows,
+             pixval        const maxval,
+             int           const x0,
+             int           const y0,
+             int           const x1,
+             int           const y1,
+             int           const x2,
+             int           const y2,
              ppmd_drawproc       drawProc,
              const void *  const clientdata) {
 
@@ -765,10 +765,10 @@ ppmd_spline3(pixel **      const pixels,
 
 
 void
-ppmd_polysplinep(pixel **       const pixels, 
-                 unsigned int   const cols, 
-                 unsigned int   const rows, 
-                 pixval         const maxval, 
+ppmd_polysplinep(pixel **       const pixels,
+                 unsigned int   const cols,
+                 unsigned int   const rows,
+                 pixval         const maxval,
                  ppmd_point     const p0,
                  unsigned int   const nc,
                  ppmd_point *   const c,
@@ -777,7 +777,7 @@ ppmd_polysplinep(pixel **       const pixels,
                  const void *   const clientdata) {
 
     ppmd_point p;
-    
+
     unsigned int i;
 
     assert(nc > 0);
@@ -796,17 +796,17 @@ ppmd_polysplinep(pixel **       const pixels,
 
 
 void
-ppmd_polyspline(pixel **      const pixels, 
-                int           const cols, 
-                int           const rows, 
-                pixval        const maxval, 
-                int           const x0, 
-                int           const y0, 
-                int           const nc, 
-                int *         const xc, 
-                int *         const yc, 
-                int           const x1, 
-                int           const y1, 
+ppmd_polyspline(pixel **      const pixels,
+                int           const cols,
+                int           const rows,
+                pixval        const maxval,
+                int           const x0,
+                int           const y0,
+                int           const nc,
+                int *         const xc,
+                int *         const yc,
+                int           const x1,
+                int           const y1,
                 ppmd_drawproc       drawProc,
                 const void *  const clientdata) {
 
@@ -837,10 +837,10 @@ ppmd_polyspline(pixel **      const pixels,
 
 
 void
-ppmd_spline4p(pixel **       const pixels, 
-              unsigned int   const cols, 
-              unsigned int   const rows, 
-              pixval         const maxval, 
+ppmd_spline4p(pixel **       const pixels,
+              unsigned int   const cols,
+              unsigned int   const rows,
+              pixval         const maxval,
               ppmd_point     const endPt0,
               ppmd_point     const endPt1,
               ppmd_point     const ctlPt0,
@@ -862,12 +862,12 @@ ppmd_spline4p(pixel **       const pixels,
 
 
 void
-ppmd_circlep(pixel **       const pixels, 
-             unsigned int   const cols, 
-             unsigned int   const rows, 
-             pixval         const maxval, 
+ppmd_circlep(pixel **       const pixels,
+             unsigned int   const cols,
+             unsigned int   const rows,
+             pixval         const maxval,
              ppmd_point     const center,
-             unsigned int   const radius, 
+             unsigned int   const radius,
              ppmd_drawprocp       drawProc,
              const void *   const clientData) {
 /*----------------------------------------------------------------------------
@@ -877,7 +877,7 @@ ppmd_circlep(pixel **       const pixels,
   it might maintain state that is affected by imaginary points outside
   the image.
 
-  Initial point is 3 o'clock. 
+  Initial point is 3 o'clock.
 -----------------------------------------------------------------------------*/
     if (radius >= DDA_SCALE)
         pm_error("Error drawing circle.  Radius %d is too large.", radius);
@@ -936,13 +936,13 @@ ppmd_circlep(pixel **       const pixels,
 
 
 void
-ppmd_circle(pixel **      const pixels, 
-            int           const cols, 
-            int           const rows, 
-            pixval        const maxval, 
-            int           const cx, 
-            int           const cy, 
-            int           const radius, 
+ppmd_circle(pixel **      const pixels,
+            int           const cols,
+            int           const rows,
+            pixval        const maxval,
+            int           const cx,
+            int           const cy,
+            int           const radius,
             ppmd_drawproc       drawProc,
             const void *  const clientData) {
 
@@ -1013,11 +1013,11 @@ ppmd_fill_create(void) {
     stateP->curedge = 0;
 
     fillObjP->stateP = stateP;
-    
+
     /* Turn off line clipping. */
     /* UGGH! We must eliminate this global variable */
     oldclip = ppmd_setlineclip(0);
-    
+
     return fillObjP;
 }
 
@@ -1129,10 +1129,10 @@ continueSegment(struct fillState * const stateP,
 */
 
 void
-ppmd_fill_drawprocp(pixel **     const pixels, 
-                    unsigned int const cols, 
-                    unsigned int const rows, 
-                    pixval       const maxval, 
+ppmd_fill_drawprocp(pixel **     const pixels,
+                    unsigned int const cols,
+                    unsigned int const rows,
+                    pixval       const maxval,
                     ppmd_point   const p,
                     const void * const clientdata) {
 
@@ -1174,12 +1174,12 @@ ppmd_fill_drawprocp(pixel **     const pixels,
 
 
 void
-ppmd_fill_drawproc(pixel**      const pixels, 
-                   int          const cols, 
-                   int          const rows, 
-                   pixval       const maxval, 
-                   int          const x, 
-                   int          const y, 
+ppmd_fill_drawproc(pixel**      const pixels,
+                   int          const cols,
+                   int          const rows,
+                   pixval       const maxval,
+                   int          const x,
+                   int          const y,
                    const void * const clientData) {
 
     ppmd_fill_drawprocp(pixels, cols, rows, maxval, makePoint(x, y),
@@ -1204,7 +1204,7 @@ yxCompare(const void * const c1Arg,
     ppmd_point const p2 = c2P->point;
 
     int retval;
-    
+
     if (p1.y > p2.y)
         retval = 1;
     else if (p1.y < p2.y)
@@ -1222,10 +1222,10 @@ yxCompare(const void * const c1Arg,
 
 
 void
-ppmd_fill(pixel **         const pixels, 
-          int              const cols, 
-          int              const rows, 
-          pixval           const maxval, 
+ppmd_fill(pixel **         const pixels,
+          int              const cols,
+          int              const rows,
+          pixval           const maxval,
           struct fillobj * const fillObjP,
           ppmd_drawproc          drawProc,
           const void *     const clientdata) {
@@ -1387,7 +1387,7 @@ static long isin(int deg)
 static long icos(int deg)
 {
     return isin(deg + 90);
-}  
+}
 
 static int
 twosCompByteValue(unsigned char const c) {
@@ -1453,7 +1453,7 @@ textPosFromFontPos(ppmd_point   const fontPos,
         /* Position relative to the top left of the whole text box,
            assuming the text box is horizontal and has font scale.
         */
-    
+
     ppmd_point const ps = makePoint((pl.x * (int)height) / Scalef,
                                     (pl.y * (int)height) / Scalef);
          /* Same as above, but with the text box its actual size */
@@ -1502,7 +1502,7 @@ drawGlyph(const struct ppmd_glyph * const glyphP,
   text box, in the coordinate system of the canvas.  'rotcos' and 'rotsin'
   tell how that text box is rotated with respect to the horizontal on the
   canvas.
-  
+
   'height' is the height in canvas pixels of a glyph.  This is a scale factor
   to convert font coordinates to canvas coordinates.
 -----------------------------------------------------------------------------*/
@@ -1542,7 +1542,7 @@ drawGlyph(const struct ppmd_glyph * const glyphP,
                                                     glyphOrigin,
                                                     height,
                                                     rotcos, rotsin);
-                                                    
+
             ppmd_linep(pixels, cols, rows, maxval, p, n,
                        drawProc, clientdata);
 
@@ -1565,14 +1565,14 @@ drawGlyph(const struct ppmd_glyph * const glyphP,
 
 
 void
-ppmd_textp(pixel**        const pixels, 
-           int            const cols, 
-           int            const rows, 
-           pixval         const maxval, 
+ppmd_textp(pixel**        const pixels,
+           int            const cols,
+           int            const rows,
+           pixval         const maxval,
            ppmd_point     const pos,
-           int            const height, 
-           int            const angle, 
-           const char *   const sArg, 
+           int            const height,
+           int            const angle,
+           const char *   const sArg,
            ppmd_drawprocp       drawProc,
            const void *   const clientdata) {
 /*----------------------------------------------------------------------------
@@ -1608,7 +1608,7 @@ ppmd_textp(pixel**        const pixels,
 
             unsigned int cursorAdvance;
 
-            ppmd_validatePoint(p); 
+            ppmd_validatePoint(p);
 
             drawGlyph(glyphP, p, pixels, cols, rows, maxval,
                       height, pos, rotcos, rotsin,
@@ -1625,15 +1625,15 @@ ppmd_textp(pixel**        const pixels,
 
 
 void
-ppmd_text(pixel**       const pixels, 
-          int           const cols, 
-          int           const rows, 
-          pixval        const maxval, 
-          int           const xpos, 
-          int           const ypos, 
-          int           const height, 
-          int           const angle, 
-          const char *  const sArg, 
+ppmd_text(pixel**       const pixels,
+          int           const cols,
+          int           const rows,
+          pixval        const maxval,
+          int           const xpos,
+          int           const ypos,
+          int           const height,
+          int           const angle,
+          const char *  const sArg,
           ppmd_drawproc       drawProc,
           const void *  const clientData) {
 
@@ -1648,13 +1648,13 @@ ppmd_text(pixel**       const pixels,
 /* EXTENTS_DRAWPROC  --  Drawproc which just accumulates the extents
              rectangle bounding the text. */
 
-static void 
-extents_drawproc (pixel**      const pixels, 
-                  int          const cols, 
+static void
+extents_drawproc (pixel**      const pixels,
+                  int          const cols,
                   int          const rows,
-                  pixval       const maxval, 
-                  int          const x, 
-                  int          const y, 
+                  pixval       const maxval,
+                  int          const x,
+                  int          const y,
                   const void * const clientdata)
 {
     extleft = MIN(extleft, x);
@@ -1673,22 +1673,25 @@ extents_drawproc (pixel**      const pixels,
 */
 
 void
-ppmd_text_box(int const height, 
-              int const angle, 
-              const char * const s, 
-              int * const left, 
-              int * const top, 
-              int * const right, 
+ppmd_text_box(int const height,
+              int const angle,
+              const char * const s,
+              int * const left,
+              int * const top,
+              int * const right,
               int * const bottom)
 {
     extleft = 32767;
     exttop = 32767;
     extright = -32767;
     extbottom = -32767;
-    ppmd_text(NULL, 32767, 32767, 255, 1000, 1000, height, angle, s, 
+    ppmd_text(NULL, 32767, 32767, 255, 1000, 1000, height, angle, s,
               extents_drawproc, NULL);
-    *left = extleft - 1000; 
+    *left = extleft - 1000;
     *top = exttop - 1000;
     *right = extright - 1000;
     *bottom = extbottom - 1000;
 }
+
+
+
diff --git a/lib/libppmfloyd.c b/lib/libppmfloyd.c
deleted file mode 100644
index d2b9c7b1..00000000
--- a/lib/libppmfloyd.c
+++ /dev/null
@@ -1,271 +0,0 @@
-/* 
-These functions were taken from Ingo Wilken's ilbm package by Bryan
-Henderson on 01.03.10.  Because ppmtoilbm and ilbmtoppm are the only
-programs that will use these in the foreseeable future, they remain
-lightly documented and tested. 
-
-But they look like they would be useful in other Netpbm programs that
-do Floyd-Steinberg.
-*/
-
-
-
-/* libfloyd.c - generic Floyd-Steinberg error distribution routines for PBMPlus
-**
-** Copyright (C) 1994 Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.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.
-*/
-
-#include "netpbm/mallocvar.h"
-#include "ppm.h"
-#include "ppmfloyd.h"
-
-
-
-static void
-fs_adjust(ppm_fs_info * const fi, 
-          int           const col) {
-
-    int     const errcol = col+1;
-    pixel * const pP     = &(fi->pixrow[col]);
-    pixval  const maxval = fi->maxval;
-
-    long r, g, b;
-
-    /* Use Floyd-Steinberg errors to adjust actual color. */
-    r = fi->thisrederr  [errcol]; if( r < 0 ) r -= 8; else r += 8; r /= 16;
-    g = fi->thisgreenerr[errcol]; if( g < 0 ) g -= 8; else g += 8; g /= 16;
-    b = fi->thisblueerr [errcol]; if( b < 0 ) b -= 8; else b += 8; b /= 16;
-
-    r += PPM_GETR(*pP); if ( r < 0 ) r = 0; else if ( r > maxval ) r = maxval;
-    g += PPM_GETG(*pP); if ( g < 0 ) g = 0; else if ( g > maxval ) g = maxval;
-    b += PPM_GETB(*pP); if ( b < 0 ) b = 0; else if ( b > maxval ) b = maxval;
-
-    PPM_ASSIGN(*pP, r, g, b);
-    fi->red = r; fi->green = g; fi->blue = b;
-}
-
-
-
-static ppm_fs_info *
-allocateFi(int const cols) {
-
-    ppm_fs_info * fi;
-
-    MALLOCVAR(fi);
-    
-    if (fi != NULL) {
-        MALLOCARRAY(fi->thisrederr  , cols + 2);
-        MALLOCARRAY(fi->thisgreenerr, cols + 2);
-        MALLOCARRAY(fi->thisblueerr , cols + 2);
-        MALLOCARRAY(fi->nextrederr  , cols + 2);
-        MALLOCARRAY(fi->nextgreenerr, cols + 2);
-        MALLOCARRAY(fi->nextblueerr , cols + 2);
-        
-        if (fi->thisrederr   == NULL || 
-            fi->thisgreenerr == NULL || 
-            fi->thisblueerr  == NULL ||
-            fi->nextrederr   == NULL || 
-            fi->nextgreenerr == NULL || 
-            fi->nextblueerr  == NULL)
-            pm_error("out of memory allocating "
-                     "Floyd-Steinberg control structure");
-    } else
-        pm_error("out of memory allocating Floyd-Steinberg control structure");
-
-    return(fi);
-}
-
-
-
-ppm_fs_info *
-ppm_fs_init(unsigned int const cols,
-            pixval       const maxval,
-            unsigned int const flags) {
-
-    ppm_fs_info * fiP;
-    
-    fiP = allocateFi(cols);
-
-    fiP->lefttoright = 1;
-    fiP->cols        = cols;
-    fiP->maxval      = maxval;
-    fiP->flags       = flags;
-
-    if (flags & FS_RANDOMINIT) {
-        unsigned int i;
-        srand(pm_randseed());
-        for (i = 0; i < cols +2; ++i) {
-            /* random errors in [-1..+1] */
-            fiP->thisrederr[i]   = rand() % 32 - 16;
-            fiP->thisgreenerr[i] = rand() % 32 - 16;
-            fiP->thisblueerr[i]  = rand() % 32 - 16;
-        }
-    } else {
-        unsigned int i;
-
-        for (i = 0; i < cols + 2; ++i)
-            fiP->thisrederr[i] = fiP->thisgreenerr[i] = 
-                fiP->thisblueerr[i] = 0;
-    }
-    return fiP;
-}
-
-
-
-void
-ppm_fs_free(fi)
-    ppm_fs_info *fi;
-{
-    if( fi ) {
-        free(fi->thisrederr); free(fi->thisgreenerr); free(fi->thisblueerr);
-        free(fi->nextrederr); free(fi->nextgreenerr); free(fi->nextblueerr);
-        free(fi);
-    }
-}
-
-
-int
-ppm_fs_startrow(fi, pixrow)
-    ppm_fs_info *fi;
-    pixel *pixrow;
-{
-    register int col;
-
-    if( !fi )
-        return 0;
-
-    fi->pixrow = pixrow;
-
-    for( col = 0; col < fi->cols + 2; col++ )
-        fi->nextrederr[col] = fi->nextgreenerr[col] = fi->nextblueerr[col] = 0;
-
-    if( fi->lefttoright ) {
-        fi->col_end = fi->cols;
-        col = 0;
-    }
-    else {
-        fi->col_end = -1;
-        col = fi->cols - 1;
-    }
-    fs_adjust(fi, col);
-    return col;
-}
-
-
-int
-ppm_fs_next(fi, col)
-    ppm_fs_info *fi;
-    int col;
-{
-    if( !fi )
-        ++col;
-    else {
-        if( fi->lefttoright )
-            ++col;
-        else
-            --col;
-        if( col == fi->col_end )
-            col = fi->cols;
-        else
-            fs_adjust(fi, col);
-    }
-    return col;
-}
-
-
-void
-ppm_fs_endrow(fi)
-    ppm_fs_info *fi;
-{
-    long *tmp;
-
-    if( fi ) {
-        tmp = fi->thisrederr;   fi->thisrederr   = fi->nextrederr;   fi->nextrederr   = tmp;
-        tmp = fi->thisgreenerr; fi->thisgreenerr = fi->nextgreenerr; fi->nextgreenerr = tmp;
-        tmp = fi->thisblueerr;  fi->thisblueerr  = fi->nextblueerr;  fi->nextblueerr  = tmp;
-        if( fi->flags & FS_ALTERNATE )
-            fi->lefttoright = !(fi->lefttoright);
-    }
-}
-
-
-void
-ppm_fs_update(fi, col, pP)
-    ppm_fs_info *fi;
-    int col;
-    pixel *pP;
-{
-    if( fi )
-        ppm_fs_update3(fi, col, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP));
-}
-
-
-void
-ppm_fs_update3(ppm_fs_info * const fi, 
-               int           const col, 
-               pixval        const r, 
-               pixval        const g, 
-               pixval        const b) {
-
-    int const errcol = col + 1;
-    long err;
-
-    if (fi) {
-        long const rerr = (long)(fi->red)   - (long)r;
-        long const gerr = (long)(fi->green) - (long)g;
-        long const berr = (long)(fi->blue)  - (long)b;
-    
-        if ( fi->lefttoright ) {
-            long two_err;
-
-            two_err = 2*rerr;
-            err = rerr;     fi->nextrederr[errcol+1] += err;    /* 1/16 */
-            err += two_err; fi->nextrederr[errcol-1] += err;    /* 3/16 */
-            err += two_err; fi->nextrederr[errcol  ] += err;    /* 5/16 */
-            err += two_err; fi->thisrederr[errcol+1] += err;    /* 7/16 */
-
-            two_err = 2*gerr;
-            err = gerr;     fi->nextgreenerr[errcol+1] += err;    /* 1/16 */
-            err += two_err; fi->nextgreenerr[errcol-1] += err;    /* 3/16 */
-            err += two_err; fi->nextgreenerr[errcol  ] += err;    /* 5/16 */
-            err += two_err; fi->thisgreenerr[errcol+1] += err;    /* 7/16 */
-
-            two_err = 2*berr;
-            err = berr;     fi->nextblueerr[errcol+1] += err;    /* 1/16 */
-            err += two_err; fi->nextblueerr[errcol-1] += err;    /* 3/16 */
-            err += two_err; fi->nextblueerr[errcol  ] += err;    /* 5/16 */
-            err += two_err; fi->thisblueerr[errcol+1] += err;    /* 7/16 */
-        }
-        else {
-            long two_err;
-
-            two_err = 2*rerr;
-            err = rerr;     fi->nextrederr[errcol-1] += err;    /* 1/16 */
-            err += two_err; fi->nextrederr[errcol+1] += err;    /* 3/16 */
-            err += two_err; fi->nextrederr[errcol  ] += err;    /* 5/16 */
-            err += two_err; fi->thisrederr[errcol-1] += err;    /* 7/16 */
-
-            two_err = 2*gerr;
-            err = gerr;     fi->nextgreenerr[errcol-1] += err;    /* 1/16 */
-            err += two_err; fi->nextgreenerr[errcol+1] += err;    /* 3/16 */
-            err += two_err; fi->nextgreenerr[errcol  ] += err;    /* 5/16 */
-            err += two_err; fi->thisgreenerr[errcol-1] += err;    /* 7/16 */
-
-            two_err = 2*berr;
-            err = berr;     fi->nextblueerr[errcol-1] += err;    /* 1/16 */
-            err += two_err; fi->nextblueerr[errcol+1] += err;    /* 3/16 */
-            err += two_err; fi->nextblueerr[errcol  ] += err;    /* 5/16 */
-            err += two_err; fi->thisblueerr[errcol-1] += err;    /* 7/16 */
-        }
-    }
-}
-
-
-
diff --git a/lib/libsystem.c b/lib/libsystem.c
index 91caf7e2..30b6b2be 100644
--- a/lib/libsystem.c
+++ b/lib/libsystem.c
@@ -135,8 +135,8 @@ execProgram(const char *  const progName,
 
 
 static void
-createPipeFeeder(void          pipeFeederRtn(int, void *), 
-                 void *  const feederParm, 
+createPipeFeeder(void          pipeFeederRtn(int, void *),
+                 void *  const feederParm,
                  int *   const fdP,
                  pid_t * const pidP) {
 /*----------------------------------------------------------------------------
@@ -150,7 +150,7 @@ createPipeFeeder(void          pipeFeederRtn(int, void *),
     pm_pipe(pipeToFeed);
     rc = fork();
     if (rc < 0) {
-        pm_error("fork() of stdin feeder failed.  errno=%d (%s)", 
+        pm_error("fork() of stdin feeder failed.  errno=%d (%s)",
                  errno, strerror(errno));
     } else if (rc == 0) {
         /* This is the child -- the stdin feeder process */
@@ -200,13 +200,13 @@ spawnProcessor(const char *  const progName,
 
     rc = fork();
     if (rc < 0) {
-        pm_error("fork() of processor process failed.  errno=%d (%s)", 
+        pm_error("fork() of processor process failed.  errno=%d (%s)",
                  errno, strerror(errno));
     } else if (rc == 0) {
         /* The program child */
 
         int stdoutFd;
-        
+
         if (pipeStdout) {
             close(stdoutpipe[0]);
             stdoutFd = stdoutpipe[1];
@@ -240,7 +240,7 @@ signalName(unsigned int const signalClass) {
 /* There are various signal classes that are not universally defined,
    so we make a half-hearted attempt to determine whether they are and
    not try to recognize the ones that aren't.  We do this by testing
-   whether a macro is defind with the signal class name.  That could give
+   whether a macro is defined with the signal class name.  That could give
    a false negative, because the signal class name isn't necessarily
    defined as a macro, but it's a really, really small problem to miss
    one of these signal classes here, so we don't bother with all the work
@@ -342,7 +342,7 @@ pm_termStatusDesc(int const termStatusArg) {
        for a BSD 'union wait' (instead of int) argument to WIFEXITED.  The
        magic involves defining a variable with 'typeof' the argument and
        assigning to that variable.
-       
+
        To work around this, we make sure the argument is not constant.
     */
 
@@ -436,14 +436,14 @@ pm_system2_vp(const char *    const progName,
        program process and the current process and have the program
        write its Standard Output to that pipe.  The current process
        runs 'stdoutAccepter' to read the data from that pipe.
-       
+
        But if 'stdoutFeeder' is NULL, we just tell the program process
        to write to the current process' Standard Output.
 
        So there are two processes when stdinFeeder is NULL and three when
        stdinFeeder is non-null.
     */
-    
+
     int progStdinFd;
         /* File descriptor that the processor program will get as Standard
            Input
@@ -469,9 +469,9 @@ pm_system2_vp(const char *    const progName,
         int progStdoutFd;
 
         /* Make a child process to run the program and pipe back to us its
-           Standard Output 
+           Standard Output
         */
-        spawnProcessor(progName, argArray, progStdinFd, 
+        spawnProcessor(progName, argArray, progStdinFd,
                        &progStdoutFd, &processorPid);
 
         /* Dispose of the stdout from that child */
@@ -493,7 +493,7 @@ pm_system2_vp(const char *    const progName,
 
     waitpid(processorPid, &termStatus, 0);
 
-    if (feederPid) 
+    if (feederPid)
         cleanupFeederProcess(feederPid);
 
     *termStatusP = termStatus;
@@ -530,7 +530,7 @@ pm_system2_lp(const char *    const progName,
          !endOfArgs;
         ) {
         const char * const arg = va_arg(args, const char *);
-        
+
         REALLOCARRAY(argArray, n+1);
 
         argArray[n++] = arg;
@@ -570,7 +570,7 @@ pm_system2(void stdinFeeder(int, void *),
    Return as *termStatusP the termination status of the processor process
    (the one running the program named 'progName').
 -----------------------------------------------------------------------------*/
-    pm_system2_lp("/bin/sh", 
+    pm_system2_lp("/bin/sh",
                   stdinFeeder, feederParm, stdoutAccepter, accepterParm,
                   termStatusP,
                   "sh", "-c", shellCommand, NULL);
@@ -635,7 +635,7 @@ pm_system_lp(const char *    const progName,
          !endOfArgs;
         ) {
         const char * const arg = va_arg(args, const char *);
-        
+
         REALLOCARRAY(argArray, n+1);
 
         argArray[n++] = arg;
@@ -726,15 +726,15 @@ pm_feed_from_memory(int    const pipeToFeedFd,
                     void * const feederParm) {
 
     pm_bufferDesc * const inputBufferP = feederParm;
-    
+
     FILE * const outFileP = fdopen(pipeToFeedFd, "w");
-    
+
     size_t bytesTransferred;
 
     /* The following signals (and normally kills) the process with
        SIGPIPE if the pipe does not take all 'size' bytes.
     */
-    bytesTransferred = 
+    bytesTransferred =
         fwrite(inputBufferP->buffer, 1, inputBufferP->size, outFileP);
 
     if (inputBufferP->bytesTransferredP)
@@ -750,7 +750,7 @@ pm_accept_to_memory(int             const pipetosuckFd,
                     void *          const accepterParm ) {
 
     pm_bufferDesc * const outputBufferP = accepterParm;
-    
+
     FILE * const inFileP = fdopen(pipetosuckFd, "r");
 
     size_t bytesTransferred;
diff --git a/lib/pam.h b/lib/pam.h
index 0055858b..94c85b4e 100644
--- a/lib/pam.h
+++ b/lib/pam.h
@@ -136,6 +136,18 @@ struct pam {
         /* The plane number of the opacity plane;  meaningless if
            'haveOpacity' is false or 'visual' is false.
         */
+    int is_seekable;  /* boolean */
+        /* The file 'file' is seekable -- you can set the position of next
+           reading or writing to anything and any time.
+
+           If libnetpbm cannot tell if it is seekable or not, this is false.
+        */
+    pm_filepos raster_pos;
+        /* The file position of the raster (which is also the end of the
+           header).
+
+           Meaningless if 'is_seekable' is false.
+        */
 };
 
 #define PAM_HAVE_ALLOCATION_DEPTH 1
@@ -220,33 +232,6 @@ struct pamtuples {
 };
 
 
-typedef float * pnm_transformMap;
-    /* This is an array of transform maps.  transform[N] is the
-       array that is the map for Plane N.
-
-       Transform maps define a transformation between PAM sample value
-       to normalized libnetpbm "samplen" value, i.e. what you get back
-       from pnm_readpamrown() or pass to pnm_writepamrown().
-       Typically, it's a gamma transfer function generated by
-       pnm_creategammatransform() or pnm_createungammatransform().
-
-       NULL for any transform means just plain normalization -- divide
-       the PAM sample value by the maxval to get the samplen, multiply
-       samplen by the maxval and round to get PAM sample value.
-
-       NULL for map table, or 'transform' member not present (pam
-       structure is too small to contain it) means ALL transforms
-       are plain normalization.
-
-       Each transform map is an array indexed by a PAM sample
-       value, containing 'float' values.  So it must have 'maxval'
-       entries.  The sample -> samplen tranformation is just the
-       obvious table lookup.  The samplen -> sample transformation is
-       more complicated -- if the samplen value is between map[N]
-       and map[N+1], then the sample value is N.  And only transforms
-       where map[N+1] > map[N] are allowed.
-    */
-
 /* Declarations of library functions. */
 
 /* We don't have a specific PAM function for init and nextimage, because
@@ -320,6 +305,9 @@ pnm_getopacity(const struct pam * const pamP,
 void
 pnm_createBlackTuple(const struct pam * const pamP, tuple * const blackTupleP);
 
+void
+pnm_createWhiteTuple(const struct pam * const pamP, tuple * const whiteTupleP);
+
 tuple
 pnm_allocpamtuple(const struct pam * const pamP);
 
@@ -368,6 +356,12 @@ void
 pnm_writepaminit(struct pam * const pamP);
 
 void
+pnm_formatpamtuples(const struct pam * const pamP,
+                    const tuple *      const tuplerow,
+                    unsigned char *    const outbuf,
+                    unsigned int       const nTuple,
+                    unsigned int *     const rowSizeP);
+void
 pnm_formatpamrow(const struct pam * const pamP,
                  const tuple *      const tuplerow,
                  unsigned char *    const outbuf,
@@ -382,6 +376,14 @@ pnm_writepamrowmult(const struct pam * const pamP,
                     unsigned int       const rptcnt);
 
 void
+pnm_writepamrowpart(const struct pam * const pamP,
+                    const tuple *      const tuplerow,
+                    unsigned int       const firstRow,
+                    unsigned int       const firstCol,
+                    unsigned int       const rowCt,
+                    unsigned int       const colCt);
+
+void
 pnm_writepam(struct pam * const pamP, tuple ** const tuplearray);
 
 void
@@ -438,6 +440,21 @@ void
 pnm_writepamn(struct pam * const pamP,
               tuplen **    const tuplenarray);
 
+typedef samplen * pnm_transformMap;
+    /* This defines a transformation between PAM sample value
+       to normalized libnetpbm "samplen" value, i.e. what you get back
+       from pnm_readpamrown() or pass to pnm_writepamrown().
+       Typically, it's a gamma transfer function generated by
+       pnm_creategammatransform() or pnm_createungammatransform().
+
+       It is an array indexed by a PAM sample value, containing 'float'
+       values.  So it must have 'maxval' entries.  The sample -> samplen
+       transformation is just the obvious table lookup.  The samplen -> sample
+       transformation is more complicated -- if the samplen value is between
+       map[N] and map[N+1], then the sample value is N.  And only transforms
+       where map[N+1] > map[N] are allowed.
+    */
+
 samplen
 pnm_normalized_sample(struct pam * const pamP,
                       sample       const sample);
@@ -576,6 +593,10 @@ tuple
 pnm_backgroundtuple(struct pam *  const pamP,
                     tuple      ** const tuples);
 
+tuple
+pnm_backgroundtuplerow(const struct pam * const pamP,
+                       tuple      *       const tuplerow);
+
 /*----------------------------------------------------------------------------
    These are meant for passing to pm_system() as Standard Input feeder
    and Standard Output accepter.
diff --git a/lib/pammap.h b/lib/pammap.h
index da2e2470..3477b84e 100644
--- a/lib/pammap.h
+++ b/lib/pammap.h
@@ -20,14 +20,14 @@ extern "C" {
 #endif
 
 struct tupleint {
-    /* An ordered pair of a tuple value and an integer, such as you 
+    /* An ordered pair of a tuple value and an integer, such as you
        would find in a tuple table or tuple hash.
 
        Note that this is a variable length structure.
     */
     int value;
-    sample tuple[1];  
-        /* This is actually a variable size array -- its size is the 
+    sample tuple[1];
+        /* This is actually a variable size array -- its size is the
            depth of the tuple in question.  Some compilers do not let us
            declare a variable length array.
         */
@@ -52,20 +52,20 @@ pnm_hashtuple(struct pam * const pamP, tuple const tuple);
 
 void
 pnm_addtotuplehash(struct pam *   const pamP,
-                   tuplehash      const tuplehash, 
+                   tuplehash      const tuplehash,
                    tuple          const tuple,
                    int            const value,
                    int *          const fitsP);
 
 void
 pnm_addtuplefreqoccurrence(struct pam *   const pamP,
-                           tuple          const value, 
+                           tuple          const value,
                            tuplehash      const tuplefreqhash,
                            int *          const firstOccurrenceP);
 
 void
-pnm_lookuptuple(struct pam * const pamP, const tuplehash tuplehash, 
-                const tuple searchval, 
+pnm_lookuptuple(struct pam * const pamP, const tuplehash tuplehash,
+                const tuple searchval,
                 int * const foundP, int * const retvalP);
 
 tupletable
@@ -113,7 +113,7 @@ pnm_computetuplefreqhash(struct pam *   const pamP,
                          unsigned int * const sizeP);
 
 tuplehash
-pnm_computetupletablehash(struct pam * const pamP, 
+pnm_computetupletablehash(struct pam * const pamP,
                           tupletable   const tupletable,
                           unsigned int const tupletableSize);
 
@@ -123,8 +123,8 @@ pnm_tuplehashtotable(const struct pam * const pamP,
                      unsigned int       const maxsize);
 
 char*
-pam_colorname(struct pam *         const pamP, 
-              tuple                const color, 
+pam_colorname(struct pam *         const pamP,
+              tuple                const color,
               enum colornameFormat const format);
 
 #ifdef __cplusplus
diff --git a/lib/pbm.h b/lib/pbm.h
index a29adb48..57ab3812 100644
--- a/lib/pbm.h
+++ b/lib/pbm.h
@@ -47,6 +47,19 @@ pbm_allocrow(unsigned int const cols);
   ((bit**) pm_allocarray(cols, rows, sizeof(bit)))
 #define pbm_freearray(bits, rows) pm_freearray((char**) bits, rows)
 #define pbm_freerow(bitrow) pm_freerow((char*) bitrow)
+
+/* Beware of arithmetic overflows when using pbm_packed_bytes(),
+   pbm_allocrow_packed() and pbm_allocarray_packed().
+
+   When cols is signed int, pbm_packed_bytes(cols + 8) overflows
+   with large values.   Same with pamP->width which is always signed int.
+
+   Function validateComputableSize() called by pbm_readpbminit()
+   provides a margin of 10, but the "+7" uses much of it.
+
+   To prevent overflows, cast cols or pamP->width to unsigned int
+   like this: pbm_packed_bytes((unsigned int) cols +8))
+*/
 #define pbm_packed_bytes(cols) (((cols)+7)/8)
 #define pbm_allocrow_packed(cols) \
     ((unsigned char *) pm_allocrow(pbm_packed_bytes(cols), \
@@ -75,14 +88,14 @@ pbm_readpbmrow(FILE * const file,
                int    const format);
 
 void
-pbm_readpbmrow_packed(FILE *          const file, 
+pbm_readpbmrow_packed(FILE *          const file,
                       unsigned char * const packedBits,
-                      int             const cols, 
+                      int             const cols,
                       int             const format);
 
 void
 pbm_readpbmrow_bitoffset(FILE *          const fileP,
-                         unsigned char * const packedBits, 
+                         unsigned char * const packedBits,
                          int             const cols,
                          int             const format,
                          unsigned int    const offset);
@@ -92,28 +105,28 @@ pbm_cleanrowend_packed(unsigned char * const packedBits,
                        unsigned int    const cols);
 
 void
-pbm_writepbminit(FILE * const fileP, 
-                 int    const cols, 
-                 int    const rows, 
+pbm_writepbminit(FILE * const fileP,
+                 int    const cols,
+                 int    const rows,
                  int    const forceplain);
 
 void
-pbm_writepbm(FILE * const fileP, 
-             bit ** const bits, 
-             int    const cols, 
-             int    const rows, 
+pbm_writepbm(FILE * const fileP,
+             bit ** const bits,
+             int    const cols,
+             int    const rows,
              int    const forceplain);
 
 void
-pbm_writepbmrow(FILE *      const fileP, 
-                const bit * const bitrow, 
-                int         const cols, 
+pbm_writepbmrow(FILE *      const fileP,
+                const bit * const bitrow,
+                int         const cols,
                 int         const forceplain);
 
 void
-pbm_writepbmrow_packed(FILE *                const fileP, 
+pbm_writepbmrow_packed(FILE *                const fileP,
                        const unsigned char * const packed_bits,
-                       int                   const cols, 
+                       int                   const cols,
                        int                   const forceplain);
 
 void
@@ -124,7 +137,7 @@ pbm_writepbmrow_bitoffset(FILE *          const ifP,
                           unsigned int    const offset);
 
 void
-pbm_check(FILE * file, const enum pm_check_type check_type, 
+pbm_check(FILE * file, const enum pm_check_type check_type,
           const int format, const int cols, const int rows,
           enum pm_check_code * const retval_p);
 
diff --git a/lib/pbmfont.h b/lib/pbmfont.h
index c8b3934b..6adbe814 100644
--- a/lib/pbmfont.h
+++ b/lib/pbmfont.h
@@ -115,12 +115,12 @@ struct glyph {
 
 struct font {
     /* This describes a combination of font and character set.  Given
-       an code point in the range 0..255, this structure describes the
+       a code point in the range 0..255, this structure describes the
        glyph for that character.
     */
     unsigned int maxwidth, maxheight;
     int x;
-        /* The minimum value of glyph.font.  The left edge of the glyph
+        /* The minimum value of glyph.x .  The left edge of the glyph
            in the glyph set which advances furthest to the left. */
     int y;
         /* Amount of white space that should be added between lines of
@@ -137,10 +137,29 @@ struct font {
 };
 
 
+
+struct pm_selector {
+    unsigned int min;     /* smallest index requested */
+    unsigned int max;     /* largest index requested  */
+    unsigned int maxmax;  /* largest index possible  */
+    unsigned int count;   /* number bits set to 1 in 'record' */
+    const unsigned char * record;
+        /* Bit array 0: absent 1: existent size calculated from maxmax
+           This is for reading only; not updating.
+           Might be 'localRecord'; might be fixed object elsewhere.
+        */
+    unsigned char * localRecord;
+        /* Updateable record optionally pointed to by 'record'.
+           Null if none.  Malloc'ed storage we own otherwise.
+        */
+};
+
+
+
 struct font2 {
     /* Font structure for expanded character set.
-       Code points in the range 0...maxmaxglyph are loaded.
-       Loaded code point is in the range 0..maxglyph .
+       Code points in the range 0...maxmaxglyph may be loaded.
+       Actually loaded code point is in the range 0..maxglyph .
      */
 
     /* 'size' and 'len' are necessary in order to provide forward and
@@ -159,7 +178,7 @@ struct font2 {
     int maxwidth, maxheight;
 
     int x;
-         /* The minimum value of glyph.font.  The left edge of the glyph in
+         /* The minimum value of glyph.x .  The left edge of the glyph in
             the glyph set which advances furthest to the left.
          */
     int y;
@@ -177,14 +196,12 @@ struct font2 {
          */
 
     PM_WCHAR maxglyph;
-        /* max code point for glyphs, including vacant slots max value of
-           above i
+        /* max code point for glyphs, including vacant slots
+           max value of above i
         */
 
-    void * selector;
-        /* Reserved
-
-           Bit array or structure indicating which code points to load.
+    struct pm_selector * selectorP;
+        /* Structure with bit array indicating which code points to load.
 
            When NULL, all available code points up to maxmaxglyph, inclusive
            are loaded.
@@ -206,14 +223,15 @@ struct font2 {
         */
 
     unsigned int bit_format;
-        /* PBM_FORMAT:   glyph data: 1 byte per pixel (like P1, but not ASCII)
-           RPBM_FORMAT:  glyph data: 1 bit per pixel
+        /* PBM_FORMAT:  glyph data: 1 byte per pixel (like P1, but not ASCII)
+           RPBM_FORMAT: glyph data: 1 bit per pixel
            Currently only PBM_FORMAT is possible
         */
 
     unsigned int total_chars;
-        /* Number of glyphs defined in font file, as stated in the CHARS line
-           of the BDF file PBM sheet font.  Always 96
+        /* Number of glyphs defined in font file.
+           BDF file: as stated in the CHARS line.
+           PBM sheet font: always 96.
         */
 
     unsigned int chars;
@@ -237,7 +255,7 @@ struct font2 {
 
     PM_WCHAR default_char;
         /* Code index of what to show when there is no glyph for a requested
-           code Available in many BDF fonts between STARPROPERTIES -
+           code.  Available in many BDF fonts between STARPROPERTIES -
            ENDPROPERTIES.
 
            Set to value read from BDF font file.
@@ -306,6 +324,11 @@ struct font2 *
 pbm_loadfont2(const    char * const filename,
               PM_WCHAR        const maxmaxglyph);
 
+struct font2 *
+pbm_loadfont2select(const    char *            const filename,
+                    PM_WCHAR                   const maxmaxglyph,
+                    const struct pm_selector * const selectorP);
+
 struct font *
 pbm_loadpbmfont(const char * const filename);
 
@@ -320,9 +343,9 @@ pbm_loadbdffont2(const char * const filename,
                  PM_WCHAR     const maxmaxglyph);
 
 struct font2 *
-pbm_loadbdffont2_select(const char * const filename,
-                        PM_WCHAR     const maxmaxglyph,
-                        const void * const selector);
+pbm_loadbdffont2select(const char *               const filename,
+                       PM_WCHAR                   const maxmaxglyph,
+                       const struct pm_selector * const selectorP);
 
 void
 pbm_createbdffont2_base(struct font2 ** const font2P,
@@ -344,6 +367,38 @@ void
 pbm_dumpfont(struct font * const fontP,
              FILE *        const ofP);
 
+/* selector functions */
+
+void
+pm_selector_create(unsigned int          const max,
+                   struct pm_selector ** const selectorPP);
+
+void
+pm_selector_create_fixed(const unsigned char * const record,
+                         unsigned int          const min,
+                         unsigned int          const max,
+                         unsigned int          const count,
+                         struct pm_selector ** const selectorPP);
+
+void
+pm_selector_destroy(struct pm_selector * const selectorP);
+
+void
+pm_selector_copy(unsigned int               const max,
+                 const struct pm_selector * const srcSelectorP,
+                 struct pm_selector **      const destSelectorPP);
+
+void
+pm_selector_mark(struct pm_selector * const selectorP,
+                 unsigned int         const index);
+
+int  /* boolean */
+pm_selector_is_marked(const struct pm_selector * const selectorP,
+                      unsigned int               const index);
+
+unsigned int
+pm_selector_marked_ct(const struct pm_selector * const selectorP);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/pbmfontdata2.c b/lib/pbmfontdata2.c
index 11dd84e6..63dd36be 100644
--- a/lib/pbmfontdata2.c
+++ b/lib/pbmfontdata2.c
@@ -452,7 +452,7 @@ struct font2 const pbm_defaultBdffont2 = {
   255, NULL, 255,                 /* maxglyph, selector, maxmaxglyph */
   NULL, 0, 0,                     /* oldfont, fcols, frows */
   PBM_FORMAT,                     /* bit_format */
-  190, 190,                       /* total_chars, chars */
+  191, 191,                       /* total_chars, chars */
   FIXED_DATA,                     /* load_fn */
   32, 1,                          /* default_char, default_char_defined */
   (char *) "builtin bdf",         /* name */
diff --git a/lib/pm.h b/lib/pm.h
index 3fc92fb4..8d5973eb 100644
--- a/lib/pm.h
+++ b/lib/pm.h
@@ -380,12 +380,25 @@ pm_getline(FILE *   const ifP,
            int *    const eofP,
            size_t * const lineLenP);
 
+void
+pm_readfile(FILE *                 const fileP,
+            const unsigned char ** const bytesP,
+            size_t *               const szP);
+
+void
+pm_writefile(FILE *                const fileP,
+             const unsigned char * const bytes,
+             size_t                const sz);
+
 short
 pm_bs_short(short const s);
 
 long
 pm_bs_long(long const l);
 
+int
+pm_is_seekable(FILE * const fileP);
+
 unsigned int
 pm_tell(FILE * const fileP);
 
diff --git a/lib/pm_system.h b/lib/pm_system.h
index dfcd5b3f..58e17f05 100644
--- a/lib/pm_system.h
+++ b/lib/pm_system.h
@@ -76,8 +76,15 @@ pm_accept_null(int    const pipetosuckFd,
 struct bufferDesc {
     /* This is just a parameter for the routines below */
     unsigned int    size;
+       /* For a read operation, number amount of space available to store
+          data read.  For a write operation, number of bytes of data available.
+       */
     unsigned char * buffer;
     unsigned int *  bytesTransferredP;
+        /* The function returns the number of bytes placed in the buffer or
+           extracted from the buffer here.  NULL if you don't want that
+           information.
+        */
 };
 
 
diff --git a/lib/pmfileio.c b/lib/pmfileio.c
index bea01abe..5d6d9bc1 100644
--- a/lib/pmfileio.c
+++ b/lib/pmfileio.c
@@ -31,6 +31,7 @@
     /* This makes the the x64() functions available on AIX */
 
 #include "netpbm/pm_config.h"
+#include <stdbool.h>
 #include <unistd.h>
 #include <assert.h>
 #include <stdio.h>
@@ -451,27 +452,16 @@ pm_tmpfile_fd(void) {
 }
 
 
-
-FILE *
-pm_openr_seekable(const char name[]) {
+static bool
+isSeekable(FILE * const fP) {
 /*----------------------------------------------------------------------------
-  Open the file named by name[] such that it is seekable (i.e. it can be
-  rewound and read in multiple passes with fseek()).
+   The file is seekable -- we can set its read/write position to anything we
+   want.
 
-  If the file is actually seekable, this reduces to the same as
-  pm_openr().  If not, we copy the named file to a temporary file
-  and return that file's stream descriptor.
-
-  We use a file that the operating system recognizes as temporary, so
-  it picks the filename and deletes the file when Caller closes it.
+   If we can't tell if it is seekable, we return false.
 -----------------------------------------------------------------------------*/
-    int stat_rc;
-    int seekable;  /* logical: file is seekable */
+    int statRc;
     struct stat statbuf;
-    FILE * original_file;
-    FILE * seekable_file;
-
-    original_file = pm_openr((char *) name);
 
     /* I would use fseek() to determine if the file is seekable and
        be a little more general than checking the type of file, but I
@@ -485,41 +475,62 @@ pm_openr_seekable(const char name[]) {
        some other file is, it doesn't hurt much to assume it isn't.
     */
 
-    stat_rc = fstat(fileno(original_file), &statbuf);
-    if (stat_rc == 0 && S_ISREG(statbuf.st_mode))
-        seekable = TRUE;
-    else
-        seekable = FALSE;
+    statRc = fstat(fileno(fP), &statbuf);
+
+    return statRc == 0 && S_ISREG(statbuf.st_mode);
+}
+
+
+
+FILE *
+pm_openr_seekable(const char name[]) {
+/*----------------------------------------------------------------------------
+  Open the file named by name[] such that it is seekable (i.e. it can be
+  rewound and read in multiple passes with fseek()).
+
+  If the file is actually seekable, this reduces to the same as
+  pm_openr().  If not, we copy the named file to a temporary file
+  and return that file's stream descriptor.
+
+  We use a file that the operating system recognizes as temporary, so
+  it picks the filename and deletes the file when Caller closes it.
+-----------------------------------------------------------------------------*/
+    FILE * originalFileP;
+    FILE * seekableFileP;
+
+    originalFileP = pm_openr((char *) name);
 
-    if (seekable) {
-        seekable_file = original_file;
+    if (isSeekable(originalFileP)) {
+        seekableFileP = originalFileP;
     } else {
-        seekable_file = pm_tmpfile();
+        seekableFileP = pm_tmpfile();
 
         /* Copy the input into the temporary seekable file */
-        while (!feof(original_file) && !ferror(original_file)
-               && !ferror(seekable_file)) {
+        while (!feof(originalFileP) && !ferror(originalFileP)
+               && !ferror(seekableFileP)) {
             char buffer[4096];
-            int bytes_read;
-            bytes_read = fread(buffer, 1, sizeof(buffer), original_file);
-            fwrite(buffer, 1, bytes_read, seekable_file);
+            size_t nBytesRead;
+
+            nBytesRead = fread(buffer, 1, sizeof(buffer), originalFileP);
+            fwrite(buffer, 1, nBytesRead, seekableFileP);
         }
-        if (ferror(original_file))
+        if (ferror(originalFileP))
             pm_error("Error reading input file into temporary file.  "
                      "Errno = %s (%d)", strerror(errno), errno);
-        if (ferror(seekable_file))
+        if (ferror(seekableFileP))
             pm_error("Error writing input into temporary file.  "
                      "Errno = %s (%d)", strerror(errno), errno);
-        pm_close(original_file);
+        pm_close(originalFileP);
         {
-            int seek_rc;
-            seek_rc = fseek(seekable_file, 0, SEEK_SET);
-            if (seek_rc != 0)
+            int seekRc;
+
+            seekRc = fseek(seekableFileP, 0, SEEK_SET);
+            if (seekRc != 0)
                 pm_error("fseek() failed to rewind temporary file.  "
                          "Errno = %s (%d)", strerror(errno), errno);
         }
     }
-    return seekable_file;
+    return seekableFileP;
 }
 
 
@@ -799,48 +810,50 @@ pm_readmagicnumber(FILE * const ifP) {
    Oliver Trepte, oliver@fysik4.kth.se, 930613
 */
 
-#define PM_BUF_SIZE 16384      /* First try this size of the buffer, then
-                                  double this until we reach PM_MAX_BUF_INC */
-#define PM_MAX_BUF_INC 65536   /* Don't allocate more memory in larger blocks
-                                  than this. */
+static size_t const initBufSz = 16384;
+  /* First try this size of the buffer, then
+     double this until we reach 'maxBufInc' */
+static size_t const maxBufInc = 65536;
+    /* Don't allocate more memory in larger blocks than this. */
 
 char *
-pm_read_unknown_size(FILE * const file,
-                     long * const nread) {
-    long nalloc;
+pm_read_unknown_size(FILE * const ifP,
+                     long * const nReadP) {
+    size_t nAlloc;
     char * buf;
+    size_t nRead;
     bool eof;
 
-    *nread = 0;
-    nalloc = PM_BUF_SIZE;
-    MALLOCARRAY(buf, nalloc);
+    nAlloc = initBufSz;   /* initial value */
 
-    if (!buf)
-        pm_error("Failed to allocate %lu bytes for read buffer",
-                 (unsigned long) nalloc);
+    MALLOCARRAY(buf, nAlloc);
 
-    eof = FALSE;  /* initial value */
+    if (!buf)
+        pm_error("Failed to allocate %lu bytes for read buffer", nAlloc);
 
-    while(!eof) {
+    for (eof = false, nRead = 0; !eof; ) {
         int val;
 
-        if (*nread >= nalloc) { /* We need a larger buffer */
-            if (nalloc > PM_MAX_BUF_INC)
-                nalloc += PM_MAX_BUF_INC;
+        if (nRead >= nAlloc) { /* We need a larger buffer */
+            if (nAlloc > maxBufInc)
+                nAlloc += maxBufInc;
             else
-                nalloc += nalloc;
-            REALLOCARRAY(buf, nalloc);
+                nAlloc += nAlloc;
+            REALLOCARRAY(buf, nAlloc);
             if (!buf)
                 pm_error("Failed to allocate %lu bytes for read buffer",
-                         (unsigned long) nalloc);
+                         nAlloc);
         }
 
-        val = getc(file);
+        val = getc(ifP);
         if (val == EOF)
-            eof = TRUE;
+            eof = true;
         else
-            buf[(*nread)++] = val;
+            buf[nRead++] = val;
     }
+
+    *nReadP = (long)nRead;
+
     return buf;
 }
 
@@ -926,6 +939,72 @@ pm_getline(FILE *   const ifP,
 
 
 
+void
+pm_readfile(FILE *                 const fileP,
+            const unsigned char ** const bytesP,
+            size_t *               const szP) {
+
+    unsigned char * buf;
+    size_t allocatedSz;
+    size_t szSoFar;
+    size_t chunkSz;
+    bool eof;
+
+    for (szSoFar = 0, buf = NULL, allocatedSz = 0, chunkSz = 4096,
+             eof = false;
+         !eof; ) {
+
+        size_t bytesReadCt;
+
+        if (szSoFar + chunkSz > allocatedSz) {
+            allocatedSz = szSoFar + chunkSz;
+            REALLOCARRAY(buf, allocatedSz);
+
+            if (!buf) {
+                pm_error("Failed to get memory for %lu byte input buffer",
+                         allocatedSz);
+            }
+        }
+        bytesReadCt = fread(buf + szSoFar, 1, chunkSz, fileP);
+
+        if (ferror(fileP))
+            pm_error("Failed to read input from file");
+
+        szSoFar += bytesReadCt;
+
+        if (bytesReadCt < chunkSz)
+            eof = true;
+        else {
+            /* Double buffer and read size up to 1 MiB */
+            if (szSoFar <= 1024*1024)
+                chunkSz = szSoFar;
+        }
+    }
+
+    *bytesP = buf;
+    *szP    = szSoFar;
+}
+
+
+
+void
+pm_writefile(FILE *                const fileP,
+             const unsigned char * const bytes,
+             size_t                const sz) {
+
+    size_t bytesWrittenCt;
+
+    bytesWrittenCt = fwrite(bytes, 1, sz, fileP);
+
+    if (bytesWrittenCt != sz) {
+        pm_error("Failed to write %lu bytes to Standard Output.  "
+                 "%lu bytes successfully written",
+                 sz, bytesWrittenCt);
+    }
+}
+
+
+
 union cheat {
     uint32_t l;
     short s;
@@ -965,6 +1044,20 @@ pm_bs_long(long const l) {
 
 
 
+int
+pm_is_seekable(FILE * const fP) {
+
+    return isSeekable(fP) ? 1 : 0;
+}
+
+
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpragmas"
+#pragma GCC diagnostic ignored "-Wduplicated-cond"
+
+
+
 void
 pm_tell2(FILE *       const fileP,
          void *       const fileposP,
@@ -1005,6 +1098,10 @@ pm_tell2(FILE *       const fileP,
 
 
 
+#pragma GCC diagnostic pop
+
+
+
 unsigned int
 pm_tell(FILE * const fileP) {
 
@@ -1017,6 +1114,12 @@ pm_tell(FILE * const fileP) {
 
 
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpragmas"
+#pragma GCC diagnostic ignored "-Wduplicated-cond"
+
+
+
 void
 pm_seek2(FILE *             const fileP,
          const pm_filepos * const fileposP,
@@ -1044,6 +1147,10 @@ pm_seek2(FILE *             const fileP,
 
 
 
+#pragma GCC diagnostic pop
+
+
+
 void
 pm_seek(FILE * const fileP, unsigned long filepos) {
 /*----------------------------------------------------------------------------
diff --git a/lib/pnm.h b/lib/pnm.h
index 0625cb5c..a8aad161 100644
--- a/lib/pnm.h
+++ b/lib/pnm.h
@@ -18,7 +18,18 @@ extern "C" {
 
 
 typedef pixel xel;
+    /* Xels come in three types: PBM, PGM, and PPM; the user of an Xel has to
+       know which as a matter of context (and like a pixel, the user also has
+       to interpret an xel in the context of a certain maxval).  Though the
+       structure is identical to 'pixel', the values are the same only for PPM
+       xels.  For a PGM xel, the 'r' and 'g' components of the 'xel' structure
+       are zero and the 'b' component is the gray level.  For a PBM xel, the
+       'r' and 'g' components are zero and the 'b' component is 0 for black
+       or maxval for white.
+    */
+
 typedef pixval xelval;
+
 #define PNM_OVERALLMAXVAL PPM_OVERALLMAXVAL
 #define PNM_MAXMAXVAL PPM_MAXMAXVAL
 #define pnm_unnormalize ppm_unnormalize
diff --git a/lib/ppmcmap.h b/lib/ppmcmap.h
index dd3e5c14..4ce822a6 100644
--- a/lib/ppmcmap.h
+++ b/lib/ppmcmap.h
@@ -16,30 +16,37 @@ extern "C" {
 typedef struct colorhist_item* colorhist_vector;
 struct colorhist_item {
     pixel color;
-    int value;
+    int   value;
 };
 
 typedef struct colorhist_list_item* colorhist_list;
 struct colorhist_list_item {
     struct colorhist_item ch;
-    colorhist_list next;
+    colorhist_list        next;
 };
 
 colorhist_vector
-ppm_computecolorhist( pixel ** const pixels, 
-                      const int cols, const int rows, const int maxcolors, 
-                      int * const colorsP );
+ppm_computecolorhist(pixel ** const pixels,
+                     int      const cols,
+                     int      const rows,
+                     int      const maxcolors,
+                     int *    const colorsP);
 colorhist_vector
-ppm_computecolorhist2(FILE * const ifp,
-                      const int cols, const int rows, 
-                      const pixval maxval, const int format, 
-                      const int maxcolors, int * const colorsP );
+ppm_computecolorhist2(FILE * const ifP,
+                      int    const cols,
+                      int    const rows,
+                      pixval const maxval,
+                      int    const format,
+                      int    const maxcolors,
+                      int *  const colorsP);
 
 void
-ppm_addtocolorhist(colorhist_vector chv, 
-                   int * const colorsP, const int maxcolors, 
-                   const pixel * const colorP, 
-                   const int value, const int position );
+ppm_addtocolorhist(colorhist_vector       chv,
+                   int *            const colorsP,
+                   int              const maxcolors,
+                   const pixel *    const colorP,
+                   int              const value,
+                   int              const position);
 
 void
 ppm_freecolorhist(colorhist_vector const chv);
@@ -50,35 +57,40 @@ ppm_freecolorhist(colorhist_vector const chv);
 typedef colorhist_list* colorhash_table;
 
 colorhash_table
-ppm_computecolorhash( pixel ** const pixels, 
-                      const int cols, const int rows, 
-                      const int maxcolors, int * const colorsP );
+ppm_computecolorhash(pixel ** const pixels,
+                     int      const cols,
+                     int      const rows,
+                     int      const maxcolors,
+                     int *    const colorsP);
 
 colorhash_table
-ppm_computecolorhash2(FILE * const ifp,
-                      const int cols, const int rows, 
-                      const pixval maxval, const int format, 
-                      const int maxcolors, int * const colorsP);
+ppm_computecolorhash2(FILE * const ifP,
+                      int    const cols,
+                      int    const rows,
+                      pixval const maxval,
+                      int    const format,
+                      int    const maxcolors,
+                      int *  const colorsP);
 
 int
-ppm_lookupcolor(colorhash_table const cht, 
+ppm_lookupcolor(colorhash_table const cht,
                 const pixel *   const colorP );
 
 colorhist_vector
-ppm_colorhashtocolorhist(colorhash_table const cht, 
+ppm_colorhashtocolorhist(colorhash_table const cht,
                          int             const maxcolors);
 
 colorhash_table
-ppm_colorhisttocolorhash(colorhist_vector const chv, 
+ppm_colorhisttocolorhash(colorhist_vector const chv,
                          int              const colors);
 
 int
-ppm_addtocolorhash(colorhash_table const cht, 
-                   const pixel *   const colorP, 
+ppm_addtocolorhash(colorhash_table const cht,
+                   const pixel *   const colorP,
                    int             const value);
 
 void
-ppm_delfromcolorhash(colorhash_table const cht, 
+ppm_delfromcolorhash(colorhash_table const cht,
                      const pixel *   const colorP);
 
 
@@ -114,7 +126,7 @@ ppm_colorrowtomapfile(FILE *  const ofP,
 
 void
 ppm_sortcolorrow(pixel * const colorrow,
-                 int     const ncolors, 
+                 int     const ncolors,
                  int (*cmpfunc)(pixel *, pixel *));
 
 int
@@ -124,8 +136,8 @@ ppm_addtocolorrow(pixel * const colorrow,
                   pixel * const pixelP);
 
 int
-ppm_findclosestcolor(const pixel * const colormap, 
-                     int           const ncolors, 
+ppm_findclosestcolor(const pixel * const colormap,
+                     int           const ncolors,
                      const pixel * const pP);
 
 /* standard sort function for ppm_sortcolorrow() */
diff --git a/lib/ppmfloyd.h b/lib/ppmfloyd.h
deleted file mode 100644
index 264fc0b6..00000000
--- a/lib/ppmfloyd.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/* These declarations were supposed to be in the libfloyd.h file in the ilbm
-   package, but that file was missing, so I made them up myself.  
-   - Bryan 01.03.10.
-*/
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-#if 0
-} /* to fake out automatic code indenters */
-#endif
-
-struct ppm_fs_info {
-    /* thisXerr and nextXerr are dynamically allocated arrays each of whose
-       dimension is the width of the image plus 2
-       */
-    long * thisrederr;
-    long * thisgreenerr;
-    long * thisblueerr;
-    long * nextrederr;
-    long * nextgreenerr;
-    long * nextblueerr;
-    int lefttoright;
-    int cols;
-    pixval maxval;
-    int flags;
-    pixel * pixrow;
-    int col_end;
-    pixval red, green, blue;
-};
-
-typedef struct ppm_fs_info ppm_fs_info;
-
-/* Bitmasks for ppm_fs_info.flags */
-#define FS_RANDOMINIT 0x01
-#define FS_ALTERNATE  0x02
-
-ppm_fs_info *
-ppm_fs_init(unsigned int const cols,
-            pixval       const maxval,
-            unsigned int const flags);
-
-void
-ppm_fs_free(ppm_fs_info *fi);
-
-int
-ppm_fs_startrow(ppm_fs_info *fi, pixel *pixrow);
-
-int
-ppm_fs_next(ppm_fs_info *fi, int col);
-
-void
-ppm_fs_endrow(ppm_fs_info *fi);
-
-void
-ppm_fs_update(    ppm_fs_info *fi, int col, pixel *pP);
-
-
-void
-ppm_fs_update3(ppm_fs_info * const fi, 
-               int           const col, 
-               pixval        const r, 
-               pixval        const g, 
-               pixval        const b);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/lib/util/LICENSE.txt b/lib/util/LICENSE.txt
index aeb06a7f..4baac593 100644
--- a/lib/util/LICENSE.txt
+++ b/lib/util/LICENSE.txt
@@ -113,7 +113,7 @@ written permission.
    
 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
 WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
-MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
    
                         The End
 
diff --git a/lib/util/Makefile b/lib/util/Makefile
index 02119edf..d8e2d135 100644
--- a/lib/util/Makefile
+++ b/lib/util/Makefile
@@ -19,6 +19,10 @@ UTILOBJECTS = \
   matrix.o \
   nsleep.o \
   nstring.o \
+  rand.o \
+  randsysrand.o \
+  randsysrandom.o \
+  randmersenne.o \
   runlength.o \
   shhopt.o \
   token.o \
diff --git a/lib/util/mallocvar.h b/lib/util/mallocvar.h
index 00ba6484..23b28c40 100644
--- a/lib/util/mallocvar.h
+++ b/lib/util/mallocvar.h
@@ -24,30 +24,40 @@ extern "C" {
 
 static __inline__ void
 mallocProduct(void **      const resultP,
-              unsigned int const factor1,
+              size_t       const factor1,
               unsigned int const factor2) {
 /*----------------------------------------------------------------------------
    malloc a space whose size in bytes is the product of 'factor1' and
-   'factor2'.  But if that size cannot be represented as an unsigned int,
-   return NULL without allocating anything.  Also return NULL if the malloc
-   fails.
+   'factor2'.  But if the malloc fails, or that size is too large even to
+   request from malloc, return NULL without allocating anything.
 
    If either factor is zero, malloc a single byte.
-
-   Note that malloc() actually takes a size_t size argument, so the
-   proper test would be whether the size can be represented by size_t,
-   not unsigned int.  But there is no reliable indication available to
-   us, like UINT_MAX, of what the limitations of size_t are.  We
-   assume size_t is at least as expressive as unsigned int and that
-   nobody really needs to allocate more than 4GB of memory.
 -----------------------------------------------------------------------------*/
+    /* C99 introduces SIZE_MAX, the maximum size_t value.
+
+       Pre-C99, we do the best we can, assuming conventional encoding of
+       numbers and that size_t is unsigned.
+    */
+    size_t const sizeMax =
+#if defined(SIZE_MAX)
+        SIZE_MAX
+#else
+        ~((size_t)0)
+#endif
+        ;
+
     if (factor1 == 0 || factor2 == 0)
         *resultP = malloc(1);
     else {
-        if (UINT_MAX / factor2 < factor1)
+        /* N.B. The type of malloc's argument is size_t */
+        if ((size_t)factor2 != factor2)
             *resultP = NULL;
-        else
-            *resultP = malloc(factor1 * factor2);
+        else {
+            if (sizeMax / factor2 < factor1)
+                *resultP = NULL;
+            else
+                *resultP = malloc(factor1 * factor2);
+        }
     }
 }
 
@@ -55,18 +65,30 @@ mallocProduct(void **      const resultP,
 
 static __inline__ void
 reallocProduct(void **      const blockP,
-               unsigned int const factor1,
+               size_t       const factor1,
                unsigned int const factor2) {
 
+    size_t const sizeMax =
+#if defined(SIZE_MAX)
+        SIZE_MAX
+#else
+        ~((size_t)0)
+#endif
+        ;
+
     void * const oldBlockP = *blockP;
 
     void * newBlockP;
 
-    if (UINT_MAX / factor2 < factor1)
+    /* N.B. The type of realloc's argument is size_t */
+    if ((size_t)factor2 != factor2)
         newBlockP = NULL;
-    else
-        newBlockP = realloc(oldBlockP, factor1 * factor2);
-
+    else {
+        if (sizeMax / factor2 < factor1)
+            newBlockP = NULL;
+        else
+            newBlockP = realloc(oldBlockP, factor1 * factor2);
+    }
     if (newBlockP)
         *blockP = newBlockP;
     else {
diff --git a/lib/util/nstring.c b/lib/util/nstring.c
index aff90ff3..4bbb041f 100644
--- a/lib/util/nstring.c
+++ b/lib/util/nstring.c
@@ -1,110 +1,28 @@
-/*
- * snprintf.c - a portable implementation of snprintf
- *
-
-   THIS MODULE WAS ADAPTED FOR NETPBM BY BRYAN HENDERSON ON 2002.03.24.
-   Bryan got the base from
-   http://www.ijs.si/software/snprintf/snprintf-2.2.tar.gz, but made
-   a lot of changes and additions.
-   The code from ww.ijs.si was written by
-
-     Mark Martinec <mark.martinec@ijs.si>
-
-   in April 1999 and June 2000.  Martinec claims copyright as of 1999, 2000,
-   2001, and 2002 and licenses the code to Netpbm maintainers and users (as
-   members of the public) under the GNU General Public License.
-
-   All other authors likewise license this code to the public under the
-   GNU General Public license.
-
- *
- * FEATURES
- * - careful adherence to specs regarding flags, field width and precision;
- * - good performance for large string handling (large format, large
- *   argument or large paddings). Performance is similar to system's sprintf
- *   and in several cases significantly better (make sure you compile with
- *   optimizations turned on, tell the compiler the code is strict ANSI
- *   if necessary to give it more freedom for optimizations);
- * - return value semantics per ISO/IEC 9899:1999 ("ISO C99");
- * - written in standard ISO/ANSI C - requires an ANSI C compiler.
- *
- * IMPLEMENTED CONVERSION SPECIFIERS AND DATA TYPES
- *
- * This snprintf implements only the following conversion specifiers:
- * s, c, d, u, o, x, X, p, f  (and synonyms: i, D, U, O - see below)
- * with flags: '-', '+', ' ', '0' and '#'.
- * An asterisk is acceptable for field width as well as precision.
- *
- * Length modifiers 'h' (short int), 'l' (long int),
- * and 'll' (long long int) are implemented.
- *
- * Conversion of numeric data (conversion specifiers d, u, o, x, X, p)
- * with length modifiers (none or h, l, ll) is left to the system routine
- * sprintf, but all handling of flags, field width and precision as well as
- * c and s conversions is done very carefully by this portable routine.
- * If a string precision (truncation) is specified (e.g. %.8s) it is
- * guaranteed the string beyond the specified precision will not be referenced.
- *
- * Length modifiers h, l and ll are ignored for c and s conversions (you
- * can't use data types wint_t and wchar_t).
- *
- * The following common synonyms for conversion characters are acceptable:
- *   - i is a synonym for d
- *   - D is a synonym for ld, explicit length modifiers are ignored
- *   - U is a synonym for lu, explicit length modifiers are ignored
- *   - O is a synonym for lo, explicit length modifiers are ignored
- * The D, O and U conversion characters are nonstandard, they are accepted
- * for backward compatibility only, and should not be used for new code.
- *
- * The following is specifically NOT implemented:
- *   - flag ' (thousands' grouping character) is recognized but ignored
- *   - numeric conversion specifiers: e, E, g, G and synonym F,
- *     as well as the new a and A conversion specifiers
- *   - length modifier 'L' (long double) and 'q' (quad - use 'll' instead)
- *   - wide character/string conversions: lc, ls, and nonstandard
- *     synonyms C and S
- *   - writeback of converted string length: conversion character n
- *   - the n$ specification for direct reference to n-th argument
- *   - locales
- *
- * It is permitted for str_m to be zero, and it is permitted to specify NULL
- * pointer for resulting string argument if str_m is zero (as per ISO C99).
- *
- * The return value is the number of characters which would be generated
- * for the given input, excluding the trailing null. If this value
- * is greater or equal to str_m, not all characters from the result
- * have been stored in str, output bytes beyond the (str_m-1) -th character
- * are discarded. If str_m is greater than zero it is guaranteed
- * the resulting string will be null-terminated.
- *
- * NOTE that this matches the ISO C99, OpenBSD, and GNU C library 2.1,
- * but is different from some older and vendor implementations,
- * and is also different from XPG, XSH5, SUSv2 specifications.
- * For historical discussion on changes in the semantics and standards
- * of snprintf see printf(3) man page in the Linux programmers manual.
- *
- * Routines asprintf and vasprintf return a pointer (in the ptr argument)
- * to a buffer sufficiently large to hold the resulting string. This pointer
- * should be passed to free(3) to release the allocated storage when it is
- * no longer needed. If sufficient space cannot be allocated, these functions
- * will return -1 and set ptr to be a NULL pointer. These two routines are a
- * GNU C library extensions (glibc).
- *
- * Routines asnprintf and vasnprintf are similar to asprintf and vasprintf,
- * yet, like snprintf and vsnprintf counterparts, will write at most str_m-1
- * characters into the allocated output string, the last character in the
- * allocated buffer then gets the terminating null. If the formatted string
- * length (the return value) is greater than or equal to the str_m argument,
- * the resulting string was truncated and some of the formatted characters
- * were discarded. These routines present a handy way to limit the amount
- * of allocated memory to some sane value.
- *
- * AVAILABILITY
- *   http://www.ijs.si/software/snprintf/
- *
- */
-
-
+/*=============================================================================
+                               nstring.c
+===============================================================================
+
+  pm_snprintf (and pm_vsnprintf) in this file used to be derived from
+  'portable_snprintf' from
+  http://www.ijs.si/software/snprintf/snprintf-2.2.tar.gz, because not all
+  system C libraries had snprintf.  But in 2013, we extended that snprintf to
+  implement %f by calling 'snprintf' in the system C library, just to see if
+  it caused any build failures.  As of August 2022, there had been no
+  complaints of problems caused by this reliance on the system providing
+  snprintf, so we just made pm_snprintf a wrapper of snprintf for everything.
+
+  Eventually we will remove pm_snprintf and pm_vsnprintf altogether and their
+  callers will call 'snprintf' and 'vsnprintf' instead
+
+  Note that snprintf is required by the C99 standard.
+
+  The code from which pm_snprintf was formerly derived was protected by
+  copyright and licensed to the public under GPL.  A user in August 2022 noted
+  that GPL was insufficient for his use of it, making him unable to use
+  libnetpbm.
+
+  Code in this file is contributed to the public domain by its authors.
+=============================================================================*/
 #define _DEFAULT_SOURCE /* New name for SVID & BSD source defines */
 #define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
 #define _BSD_SOURCE  /* Make sure strdup() is in string.h */
@@ -112,9 +30,6 @@
    /* Because of conditional compilation, this is GNU source only if the C
       library is GNU.
    */
-#define PORTABLE_SNPRINTF_VERSION_MAJOR 2
-#define PORTABLE_SNPRINTF_VERSION_MINOR 2
-
 #include <sys/types.h>
 #include <limits.h>
 #include <string.h>
@@ -129,64 +44,6 @@
 
 #include "nstring.h"
 
-#ifdef isdigit
-#undef isdigit
-#endif
-#define isdigit(c) ((c) >= '0' && (c) <= '9')
-
-/* For copying strings longer or equal to 'breakeven_point'
- * it is more efficient to call memcpy() than to do it inline.
- * The value depends mostly on the processor architecture,
- * but also on the compiler and its optimization capabilities.
- * The value is not critical, some small value greater than zero
- * will be just fine if you don't care to squeeze every drop
- * of performance out of the code.
- *
- * Small values favor memcpy, large values favor inline code.
- */
-#if defined(__alpha__) || defined(__alpha)
-#  define breakeven_point   2	/* AXP (DEC Alpha)     - gcc or cc or egcs */
-#endif
-#if defined(__i386__)  || defined(__i386)
-#  define breakeven_point  12	/* Intel Pentium/Linux - gcc 2.96 */
-#endif
-#if defined(__hppa)
-#  define breakeven_point  10	/* HP-PA               - gcc */
-#endif
-#if defined(__sparc__) || defined(__sparc)
-#  define breakeven_point  33	/* Sun Sparc 5         - gcc 2.8.1 */
-#endif
-
-/* some other values of possible interest: */
-/* #define breakeven_point  8 */  /* VAX 4000          - vaxc */
-/* #define breakeven_point 19 */  /* VAX 4000          - gcc 2.7.0 */
-
-#ifndef breakeven_point
-#  define breakeven_point   6	/* some reasonable one-size-fits-all value */
-#endif
-
-#define fast_memcpy(d,s,n) \
-  { register size_t nn = (size_t)(n); \
-    if (nn >= breakeven_point) memcpy((d), (s), nn); \
-    else if (nn > 0) { /* proc call overhead is worth only for large strings*/\
-      register char *dd; register const char *ss; \
-      for (ss=(s), dd=(d); nn>0; nn--) *dd++ = *ss++; } }
-
-#define fast_memset(d,c,n) \
-  { register size_t nn = (size_t)(n); \
-    if (nn >= breakeven_point) memset((d), (int)(c), nn); \
-    else if (nn > 0) { /* proc call overhead is worth only for large strings*/\
-      register char *dd; register const int cc=(int)(c); \
-      for (dd=(d); nn>0; nn--) *dd++ = cc; } }
-
-/* declarations */
-
-static char credits[] = "\n\
-@(#)snprintf.c, v2.2: Mark Martinec, <mark.martinec@ijs.si>\n\
-@(#)snprintf.c, v2.2: Copyright 1999, Mark Martinec. Frontier Artistic License applies.\n\
-@(#)snprintf.c, v2.2: http://www.ijs.si/software/snprintf/\n";
-
-
 /* MacOS X before 10.7, for one, does not have strnlen */
 size_t
 pm_strnlen(const char * const s,
@@ -203,556 +60,25 @@ pm_strnlen(const char * const s,
 
 void
 pm_vsnprintf(char *       const str,
-             size_t       const str_m,
+             size_t       const maxSize,
              const char * const fmt,
              va_list            ap,
              size_t *     const sizeP) {
 
-    size_t str_l = 0;
-    const char *p = fmt;
-
-    /* In contrast with POSIX, the ISO C99 now says that str can be
-       NULL and str_m can be 0.  This is more useful than the old:
-       if (str_m < 1) return -1;
-    */
+    int rc;
 
-    if (!p) p = "";
-    while (*p) {
-        if (*p != '%') {
-            /* if (str_l < str_m) str[str_l++] = *p++; -- this would
-               be sufficient but the following code achieves better
-               performance for cases * where format string is long and
-               contains few conversions
-            */
-            const char *q = strchr(p + 1,'%');
-            size_t n = !q ? strlen(p) : (q - p);
-            if (str_l < str_m) {
-                size_t const avail = str_m - str_l;
-                fast_memcpy(str + str_l, p, (MIN(n, avail)));
-            }
-            p += n; str_l += n;
-        } else {
-            size_t min_field_width;
-            size_t precision = 0;
-            bool precision_specified;
-            bool justify_left;
-            bool alternate_form;
-            bool force_sign;
-            bool space_for_positive;
-                /* If both the ' ' and '+' flags appear,
-                   the ' ' flag should be ignored.
-                */
-            char length_modifier = '\0';  /* allowed values: \0, h, l, L */
-            char tmp[32];
-                /* temporary buffer for simple numeric->string conversion */
-
-            const char *str_arg;
-                /* string address in case of string argument */
-            size_t str_arg_l;
-                /* natural field width of arg without padding and sign */
-            unsigned char uchar_arg;
-                /* unsigned char argument value - only defined for c
-                   conversion.  N.B. standard explicitly states the char
-                   argument for the c conversion is unsigned.
-                */
-
-            bool zero_padding;
-
-            size_t number_of_zeros_to_pad;
-                /* number of zeros to be inserted for numeric
-                   conversions as required by the precision or minimal
-                   field width
-                */
-
-            size_t zero_padding_insertion_ind;
-                /* index into tmp where zero padding is to be inserted */
-
-            char fmt_spec;
-                /* current conversion specifier character */
-
-            str_arg = credits;
-                /* just to make compiler happy (defined but not used) */
-            str_arg = NULL;
-            ++p;  /* skip '%' */
-
-            /* parse flags */
-            justify_left = false;  /* initial value */
-            alternate_form = false;  /* initial value */
-            force_sign = false;  /* initial value */
-            space_for_positive = false;  /* initial value */
-            zero_padding = false;  /* initial value */
-            number_of_zeros_to_pad = 0;  /* initial value */
-            zero_padding_insertion_ind = 0;  /* initial value */
-            fmt_spec = '\0';  /* initial value */
-
-            while (*p == '0' || *p == '-' || *p == '+' ||
-                   *p == ' ' || *p == '#' || *p == '\'') {
-                switch (*p) {
-                case '0': zero_padding = true; break;
-                case '-': justify_left = true; break;
-                case '+': force_sign = true; space_for_positive = false; break;
-                case ' ': force_sign = true; break;
-                    /* If both the ' ' and '+' flags appear, the ' '
-                       flag should be ignored
-                    */
-                case '#': alternate_form = true; break;
-                case '\'': break;
-                }
-                ++p;
-            }
-            /* If the '0' and '-' flags both appear, the '0' flag
-               should be ignored.
-            */
+    rc = vsnprintf(str, maxSize, fmt, ap);
 
-            /* parse field width */
-            if (*p == '*') {
-                int j;
-                ++p;
-                j = va_arg(ap, int);
-                if (j >= 0) { min_field_width = j; justify_left = false; }
-                else { min_field_width = -j; justify_left = true; }
-            } else if (isdigit((int)(*p))) {
-                /* size_t could be wider than unsigned int; make sure
-                   we treat argument like common implementations do
-                */
-                unsigned int uj = *p++ - '0';
-                while (isdigit((int)(*p)))
-                    uj = 10*uj + (unsigned int)(*p++ - '0');
-                min_field_width = uj;
-            } else
-                min_field_width = 0;
-
-            /* parse precision */
-            if (*p == '.') {
-                ++p;
-                precision_specified = true;
-                if (*p == '*') {
-                    int j = va_arg(ap, int);
-                    p++;
-                    if (j >= 0) precision = j;
-                    else {
-                        precision_specified = false; precision = 0;
-                        /* NOTE: Solaris 2.6 man page claims that in
-                           this case the precision should be set to 0.
-                           Digital Unix 4.0, HPUX 10 and BSD man page
-                           claim that this case should be treated as
-                           unspecified precision, which is what we do
-                           here.
-                        */
-                    }
-                } else if (isdigit((int)(*p))) {
-                    /* size_t could be wider than unsigned int; make
-                       sure we treat argument like common
-                       implementations do
-                    */
-                    unsigned int uj = *p++ - '0';
-                    while (isdigit((int)(*p)))
-                        uj = 10*uj + (unsigned int)(*p++ - '0');
-                    precision = uj;
-                }
-            } else
-                precision_specified = false;
-
-            /* parse 'h', 'l' and 'll' length modifiers */
-            if (*p == 'h' || *p == 'l') {
-                length_modifier = *p; p++;
-                if (length_modifier == 'l' && *p == 'l') {
-                    /* double l = long long */
-                    length_modifier = 'l';  /* treat it as a single 'l' */
-                    p++;
-                }
-            }
-            fmt_spec = *p;
-
-            /* common synonyms: */
-            switch (fmt_spec) {
-            case 'i': fmt_spec = 'd'; break;
-            case 'D': fmt_spec = 'd'; length_modifier = 'l'; break;
-            case 'U': fmt_spec = 'u'; length_modifier = 'l'; break;
-            case 'O': fmt_spec = 'o'; length_modifier = 'l'; break;
-            default: break;
-            }
-            /* get parameter value, do initial processing */
-            switch (fmt_spec) {
-            case '%':
-                /* % behaves similar to 's' regarding flags and field widths */
-            case 'c':
-                /* c behaves similar to 's' regarding flags and field widths */
-            case 's':
-                /* wint_t and wchar_t not handled */
-                length_modifier = '\0';
-                /* the result of zero padding flag with non-numeric
-                    conversion specifier is undefined. Solaris and
-                    HPUX 10 does zero padding in this case, Digital
-                    Unix and Linux does not.
-                */
-
-                zero_padding = false;
-                    /* turn zero padding off for string conversions */
-                str_arg_l = 1;
-                switch (fmt_spec) {
-                case '%':
-                    str_arg = p; break;
-                case 'c': {
-                    int j = va_arg(ap, int);
-                    uchar_arg = (unsigned char) j;
-                        /* standard demands unsigned char */
-                    str_arg = (const char *) &uchar_arg;
-                    break;
-                }
-                case 's':
-                    str_arg = va_arg(ap, const char *);
-                    if (!str_arg)
-                        /* make sure not to address string beyond the
-                           specified precision !!!
-                        */
-                        str_arg_l = 0;
-                    else if (!precision_specified)
-                        /* truncate string if necessary as requested by
-                           precision
-                        */
-                        str_arg_l = strlen(str_arg);
-                    else if (precision == 0)
-                        str_arg_l = 0;
-                    else {
-                        /* memchr on HP does not like n > 2^31  !!! */
-                        const char * q =
-                            memchr(str_arg, '\0', MIN(precision, 0x7fffffff));
-                        str_arg_l = !q ? precision : (q-str_arg);
-                    }
-                    break;
-                default: break;
-                }
-                break;
-            case 'd': case 'u': case 'o': case 'x': case 'X': case 'p': {
-                /* NOTE: the u, o, x, X and p conversion specifiers imply
-                   the value is unsigned;  d implies a signed value
-                */
-                int arg_sign = 0;
-                /* 0  if numeric argument is zero (or if pointer is NULL
-                      for 'p'),
-                   +1 if greater than zero (or nonzero for unsigned arguments),
-                   -1 if negative (unsigned argument is never negative)
-                */
-
-                int int_arg = 0;
-                unsigned int uint_arg = 0;
-                   /* defined only for length modifier h, or for no
-                      length modifiers
-                   */
-
-                long int long_arg = 0;  unsigned long int ulong_arg = 0;
-                /* only defined for length modifier l */
-
-                void *ptr_arg = NULL;
-                /* pointer argument value -only defined for p conversion */
-
-                if (fmt_spec == 'p') {
-                    /* HPUX 10: An l, h, ll or L before any other
-                        conversion character (other than d, i, u, o,
-                        x, or X) is ignored.
-
-                      Digital Unix: not specified, but seems to behave
-                      as HPUX does.
-
-                      Solaris: If an h, l, or L appears before any
-                      other conversion specifier (other than d, i, u,
-                      o, x, or X), the behavior is
-                      undefined. (Actually %hp converts only 16-bits
-                      of address and %llp treats address as 64-bit
-                      data which is incompatible with (void *)
-                      argument on a 32-bit system).
-                    */
-
-                    length_modifier = '\0';
-                    ptr_arg = va_arg(ap, void *);
-                    if (ptr_arg != NULL) arg_sign = 1;
-                } else if (fmt_spec == 'd') {  /* signed */
-                    switch (length_modifier) {
-                    case '\0':
-                    case 'h':
-                        /* It is non-portable to specify a second
-                           argument of char or short to va_arg,
-                           because arguments seen by the called
-                           function are not char or short.  C converts
-                           char and short arguments to int before
-                           passing them to a function.
-                        */
-                        int_arg = va_arg(ap, int);
-                        if      (int_arg > 0) arg_sign =  1;
-                        else if (int_arg < 0) arg_sign = -1;
-                        break;
-                    case 'l':
-                        long_arg = va_arg(ap, long int);
-                        if      (long_arg > 0) arg_sign =  1;
-                        else if (long_arg < 0) arg_sign = -1;
-                        break;
-                    }
-                } else {  /* unsigned */
-                    switch (length_modifier) {
-                    case '\0':
-                    case 'h':
-                        uint_arg = va_arg(ap, unsigned int);
-                        if (uint_arg)
-                            arg_sign = 1;
-                        break;
-                    case 'l':
-                        ulong_arg = va_arg(ap, unsigned long int);
-                        if (ulong_arg)
-                            arg_sign = 1;
-                        break;
-                    }
-                }
-                str_arg = tmp; str_arg_l = 0;
-                /* NOTE: For d, i, u, o, x, and X conversions, if
-                   precision is specified, the '0' flag should be
-                   ignored. This is so with Solaris 2.6, Digital UNIX
-                   4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with
-                   Perl.
-                */
-                if (precision_specified)
-                    zero_padding = false;
-                if (fmt_spec == 'd') {
-                    if (force_sign && arg_sign >= 0)
-                        tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
-                    /* leave negative numbers for sprintf to handle,
-                       to avoid handling tricky cases like (short
-                       int)(-32768)
-                    */
-                } else if (alternate_form) {
-                    if (arg_sign != 0 && (fmt_spec == 'x' ||
-                                          fmt_spec == 'X')) {
-                        tmp[str_arg_l++] = '0';
-                        tmp[str_arg_l++] = fmt_spec;
-                    }
-                    /* alternate form should have no effect for p
-                       conversion, but ...
-                    */
-                }
-                zero_padding_insertion_ind = str_arg_l;
-                if (!precision_specified)
-                    precision = 1;   /* default precision is 1 */
-                if (precision == 0 && arg_sign == 0) {
-                    /* converted to null string */
-                    /* When zero value is formatted with an explicit
-                       precision 0, the resulting formatted string is
-                       empty (d, i, u, o, x, X, p).
-                    */
-                } else {
-                    char f[5]; int f_l = 0;
-                    f[f_l++] = '%';
-                        /* construct a simple format string for sprintf */
-                    if (!length_modifier) { }
-                    else if (length_modifier=='2') {
-                        f[f_l++] = 'l'; f[f_l++] = 'l';
-                    }
-                    else
-                        f[f_l++] = length_modifier;
-                    f[f_l++] = fmt_spec; f[f_l++] = '\0';
-                    if (fmt_spec == 'p')
-                        str_arg_l += sprintf(tmp+str_arg_l, f, ptr_arg);
-                    else if (fmt_spec == 'd') {  /* signed */
-                        switch (length_modifier) {
-                        case '\0':
-                        case 'h':
-                            str_arg_l+=sprintf(tmp+str_arg_l, f, int_arg);
-                            break;
-                        case 'l':
-                            str_arg_l+=sprintf(tmp+str_arg_l, f, long_arg);
-                            break;
-                        }
-                    } else {  /* unsigned */
-                        switch (length_modifier) {
-                        case '\0':
-                        case 'h':
-                            str_arg_l += sprintf(tmp+str_arg_l, f, uint_arg);
-                            break;
-                        case 'l':
-                            str_arg_l += sprintf(tmp+str_arg_l, f, ulong_arg);
-                            break;
-                        }
-                    }
-                    /* include the optional minus sign and possible "0x"
-                       in the region before the zero padding insertion point
-                    */
-                    if (zero_padding_insertion_ind < str_arg_l &&
-                        tmp[zero_padding_insertion_ind] == '-') {
-                        zero_padding_insertion_ind += 1;
-                    }
-                    if (zero_padding_insertion_ind + 1 < str_arg_l &&
-                        tmp[zero_padding_insertion_ind]   == '0' &&
-                        (tmp[zero_padding_insertion_ind+1] == 'x' ||
-                         tmp[zero_padding_insertion_ind+1] == 'X') ) {
-                        zero_padding_insertion_ind += 2;
-                    }
-                }
-                {
-                    size_t const num_of_digits =
-                        str_arg_l - zero_padding_insertion_ind;
-                    if (alternate_form && fmt_spec == 'o'
-                        /* unless zero is already the first character */
-                        && !(zero_padding_insertion_ind < str_arg_l
-                             && tmp[zero_padding_insertion_ind] == '0')) {
-                        /* assure leading zero for alternate-form
-                           octal numbers
-                        */
-                        if (!precision_specified ||
-                            precision < num_of_digits+1) {
-                            /* precision is increased to force the
-                               first character to be zero, except if a
-                               zero value is formatted with an
-                               explicit precision of zero
-                            */
-                            precision = num_of_digits+1;
-                            precision_specified = true;
-                        }
-                    }
-                    /* zero padding to specified precision? */
-                    if (num_of_digits < precision)
-                        number_of_zeros_to_pad = precision - num_of_digits;
-                }
-                /* zero padding to specified minimal field width? */
-                if (!justify_left && zero_padding) {
-                    int const n =
-                        min_field_width - (str_arg_l+number_of_zeros_to_pad);
-                    if (n > 0)
-                        number_of_zeros_to_pad += n;
-                }
-            } break;
-            case 'f': {
-                char f[10];
-                if (precision_specified)
-                    snprintf(f, ARRAY_SIZE(f), "%%%u.%uf",
-                             (unsigned)min_field_width, (unsigned)precision);
-                else
-                    snprintf(f, ARRAY_SIZE(f), "%%%uf",
-                             (unsigned)min_field_width);
-
-                str_arg_l = sprintf(tmp, f, va_arg(ap, double));
-                str_arg = &tmp[0];
-
-                min_field_width = 0;
-                zero_padding_insertion_ind = 0;
-            } break;
-            default:
-                /* Unrecognized conversion specifier.  Discard the
-                   unrecognized conversion, just keep the unrecognized
-                   conversion character.
-                */
-                zero_padding = false;
-                    /* turn zero padding off for non-numeric convers. */
-                /* reset flags */
-                justify_left = true;
-                min_field_width = 0;
-                str_arg = p;
-                str_arg_l = 0;
-                if (*p)
-                    /* include invalid conversion specifier unchanged
-                       if not at end-of-string
-                    */
-                    ++str_arg_l;
-                break;
-            }
-            if (*p)
-                p++;  /* step over the just processed conversion specifier */
-            /* insert padding to the left as requested by
-               min_field_width; this does not include the zero padding
-               in case of numerical conversions
-            */
+    assert((size_t)rc == rc);
 
-            if (!justify_left) {
-                /* left padding with blank or zero */
-                int n = min_field_width - (str_arg_l + number_of_zeros_to_pad);
-                if (n > 0) {
-                    if (str_l < str_m) {
-                        size_t const avail = str_m - str_l;
-                        fast_memset(str + str_l, (zero_padding ? '0' : ' '),
-                                    (MIN(n, avail)));
-                    }
-                    str_l += n;
-                }
-            }
-            /* zero padding as requested by the precision or by the
-               minimal field width for numeric conversions required?
-            */
-            if (number_of_zeros_to_pad <= 0) {
-                /* will not copy first part of numeric right now,
-                   force it to be copied later in its entirety
-                */
-                zero_padding_insertion_ind = 0;
-            } else {
-                {
-                    /* insert first part of numerics (sign or '0x') before
-                       zero padding
-                    */
-                    int const n = zero_padding_insertion_ind;
-                    if (n > 0) {
-                        if (str_l < str_m) {
-                            size_t const avail = str_m - str_l;
-                            fast_memcpy(str + str_l, str_arg, (MIN(n, avail)));
-                        }
-                        str_l += n;
-                    }
-                }
-                {
-                    /* insert zero padding as requested by the precision
-                       or min field width
-                    */
-                    int const n = number_of_zeros_to_pad;
-                    if (n > 0) {
-                        if (str_l < str_m) {
-                            size_t const avail = str_m - str_l;
-                            fast_memset(str + str_l, '0', (MIN(n, avail)));
-                        }
-                        str_l += n;
-                    }
-                }
-            }
-            /* insert formatted string (or as-is conversion specifier
-               for unknown conversions)
-            */
-            {
-                int const n = str_arg_l - zero_padding_insertion_ind;
-                if (n > 0) {
-                    if (str_l < str_m) {
-                        size_t const avail = str_m-str_l;
-                        fast_memcpy(str + str_l,
-                                    str_arg + zero_padding_insertion_ind,
-                                    MIN(n, avail));
-                    }
-                    str_l += n;
-                }
-            }
-            /* insert right padding */
-            if (justify_left) {
-                /* right blank padding to the field width */
-                int const n =
-                    min_field_width - (str_arg_l + number_of_zeros_to_pad);
-                if (n > 0) {
-                    if (str_l < str_m) {
-                        size_t const avail = str_m - str_l;
-                        fast_memset(str+str_l, ' ', (MIN(n, avail)));
-                    }
-                    str_l += n;
-                }
-            }
-        }
-    }
-    if (str_m > 0) {
-        /* make sure the string is null-terminated even at the expense
-           of overwriting the last character (shouldn't happen, but
-           just in case)
-        */
-        str[MIN(str_l, str_m - 1)] = '\0';
-    }
-    *sizeP = str_l;
+    *sizeP = (size_t)rc;
 }
 
 
 
 int
 pm_snprintf(char *       const dest,
-            size_t       const str_m,
+            size_t       const maxSize,
             const char * const fmt,
             ...) {
 
@@ -761,7 +87,7 @@ pm_snprintf(char *       const dest,
 
     va_start(ap, fmt);
 
-    pm_vsnprintf(dest, str_m, fmt, ap, &size);
+    pm_vsnprintf(dest, maxSize, fmt, ap, &size);
 
     va_end(ap);
 
@@ -999,47 +325,83 @@ pm_strishex(const char * const subject) {
 
 
 void
-pm_string_to_uint(const char *   const string,
-                  unsigned int * const uintP,
+pm_string_to_long(const char *   const string,
+                  long *         const longP,
                   const char **  const errorP) {
 
     if (strlen(string) == 0)
         pm_asprintf(errorP, "Value is a null string");
     else {
         char * tailptr;
-        long longValue;
-
-        /* We can't use 'strtoul'.  Contrary to expectations, though as
-           designed, it returns junk if there is a minus sign.
-        */
 
         /* strtol() does a bizarre thing where if the number is out
            of range, it returns a clamped value but tells you about it
            by setting errno = ERANGE.  If it is not out of range,
            strtol() leaves errno alone.
         */
-        errno = 0;  /* So we can tell if strtoul() overflowed */
+        errno = 0;  /* So we can tell if strtol() overflowed */
 
-        longValue = strtol(string, &tailptr, 10);
+        *longP = strtol(string, &tailptr, 10);
 
         if (*tailptr != '\0')
             pm_asprintf(errorP, "Non-numeric crap in string: '%s'", tailptr);
         else {
              if (errno == ERANGE)
                  pm_asprintf(errorP, "Number is too large for computation");
-             else {
-                 if (longValue < 0)
-                     pm_asprintf(errorP, "Number is negative");
-                 else {
-                     if ((unsigned int)longValue != longValue)
-                         pm_asprintf(errorP,
-                                     "Number is too large for computation");
-                     else {
-                         *uintP = (unsigned int)longValue;
-                         *errorP = NULL;
-                     }
-                 }
-             }
+             else
+                 *errorP = NULL;
+        }
+    }
+}
+
+
+
+void
+pm_string_to_int(const char *   const string,
+                 int *          const intP,
+                 const char **  const errorP) {
+
+    long longValue;
+
+    pm_string_to_long(string, &longValue, errorP);
+
+    if (!*errorP) {
+        if ((int)longValue != longValue)
+            pm_asprintf(errorP,
+                        "Number is too large for computation");
+        else {
+            *intP = (int)longValue;
+            *errorP = NULL;
+        }
+    }
+}
+
+
+
+void
+pm_string_to_uint(const char *   const string,
+                  unsigned int * const uintP,
+                  const char **  const errorP) {
+
+    /* We can't use 'strtoul'.  Contrary to expectations, though as
+       designed, it returns junk if there is a minus sign.
+    */
+
+    long longValue;
+
+    pm_string_to_long(string, &longValue, errorP);
+
+    if (!*errorP) {
+        if (longValue < 0)
+            pm_asprintf(errorP, "Number is negative");
+        else {
+            if ((unsigned int)longValue != longValue)
+                pm_asprintf(errorP,
+                            "Number is too large for computation");
+            else {
+                *uintP = (unsigned int)longValue;
+                *errorP = NULL;
+            }
         }
     }
 }
diff --git a/lib/util/nstring.h b/lib/util/nstring.h
index 5159277c..1f03e4f2 100644
--- a/lib/util/nstring.h
+++ b/lib/util/nstring.h
@@ -30,9 +30,7 @@ extern "C" {
 #define STRSEQ(A, B) \
 	(strneq((A), (B), sizeof(A)))
 
-#define MEMEQ(a,b,c) (memcmp(a, b, c) == 0)
-
-#define MEMSEQ(a,b) (memeq(a, b, sizeof(*(a))) == 0)
+#define MEMSEQ(a,b) (memeq(a, b, sizeof(*(a))))
 
 #define MEMSSET(a,b) (memset(a, b, sizeof(*(a))))
 
@@ -126,12 +124,9 @@ strncaseeq(const char * const comparand,
 #define TOUPPER(C) ((char)toupper((unsigned char)(C)))
 
 
-/* These are all private versions of commonly available standard C
-   library subroutines whose names are the same except with the N at
-   the end.  Because not all standard C libraries have them all,
-   Netpbm must include them in its own libraries, and because some
-   standard C libraries have some of them, Netpbm must use different
-   names for them.
+/* Most of these are private versions of commonly available standard C library
+   subroutines whose names are similar.  They're here because not all standard
+   C libraries have them.
 
    The GNU C library has all of them.  All but the oldest standard C libraries
    have snprintf().
@@ -146,7 +141,7 @@ strncaseeq(const char * const comparand,
 
      - If the function can't get the memory, it returns 'pm_strsol',
        which is a string that is in static memory that contains text
-       indicating an out of memory failure has occurred, intead of
+       indicating an out of memory failure has occurred, instead of
        NULL.  This makes it much easier for programs to ignore this
        possibility.
 
@@ -162,13 +157,13 @@ pm_strnlen(const char * const s,
 
 int
 pm_snprintf(char *       const dest,
-            size_t       const str_m,
+            size_t       const maxSize,
             const char * const fmt,
             ...) PM_GNU_PRINTF_ATTR(3,4);
 
 void
 pm_vsnprintf(char *       const str,
-             size_t       const str_m,
+             size_t       const maxSize,
              const char * const fmt,
              va_list            ap,
              size_t *     const sizeP);
@@ -209,6 +204,16 @@ bool
 pm_strishex(const char * const subject);
 
 void
+pm_string_to_long(const char *   const string,
+                  long *         const longP,
+                  const char **  const errorP);
+
+void
+pm_string_to_int(const char *   const string,
+                 int *          const intP,
+                 const char **  const errorP);
+
+void
 pm_string_to_uint(const char *   const string,
                   unsigned int * const uintP,
                   const char **  const errorP);
diff --git a/lib/util/rand.c b/lib/util/rand.c
new file mode 100644
index 00000000..6a0a2cdb
--- /dev/null
+++ b/lib/util/rand.c
@@ -0,0 +1,294 @@
+/*
+
+Pseudo-random number generator for Netpbm
+
+The interface provided herein should be flexible enough for anybody
+who wishes to use some other random number generator.
+
+---
+
+If you desire to implement a different generator, or writing an original
+one, first take a look at the random number generator section of the
+GNU Scientific Library package (GSL).
+
+GNU Scientific Library
+https://www.gnu.org/software/gsl/
+
+GSL Random Number Generators
+https://wnww.gnu.org/software/gsl/doc/html/rng.html
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <strings.h>
+#include <time.h>
+#include <float.h>
+#include <math.h>
+
+#include "netpbm/pm_c_util.h"
+#include "netpbm/mallocvar.h"
+#include "netpbm/pm.h"
+#include "netpbm/rand.h"
+
+/*-----------------------------------------------------------------------------
+                              Use
+-------------------------------------------------------------------------------
+  Typical usage:
+
+      #include "rand.h"
+
+      ...
+
+      myfunction( ... , unsigned int const seed , ... ) {
+
+          struct randSt;
+
+          ...
+
+          pm_randinit(&randSt);
+          pm_srand(&randSt, seed);  // pm_srand2() is often more useful
+
+          ...
+
+          pm_rand(&randSt);
+
+          ...
+
+          pm_randterm(&randSt);
+
+      }
+-----------------------------------------------------------------------------*/
+
+
+
+/*-----------------------------------------------------------------------------
+                            Design note
+-------------------------------------------------------------------------------
+
+  Netpbm code contains multiple random number generators.  Stock Netpbm always
+  uses an internal pseudo-random number generator that implements the Mersenne
+  Twister method and does not rely on any randomness facility of the operating
+  system, but it is easy to compile an alternative version that uses others.
+
+  The Mersenne Twister method was new to Netpbm in Netpbm 10.94 (March 2021).
+  Before that, Netpbm used standard OS-provided facilities.
+
+  Programs that use random numbers have existed in Netpbm since PBMPlus days.
+  The system rand() function was used in instances randomness was required;
+  exceptions were rare and all of them appear to be errors on the part of the
+  original author.
+
+  Although the rand() function is available in every system on which Netpbm
+  runs, differences exist in the underlying algorithm, so that Netpbm programs
+  produce different output on different systems even when the user specifies
+  the same random number seed.
+
+  This was not considered a problem in the early days.  Deterministic
+  operation was not a feature users requested and it was impossible regardless
+  of the random number generation method on most programs because they did not
+  allow a user to specify a seed for the generator.
+
+  This state of affairs changed as Netpbm got firmly established as a
+  base-level system package.  Security became critical for many users.  A
+  crucial component of quality control is automated regression tests (="make
+  check").  Unpredictable behavior gets in the way of testing.  One by one
+  programs were given the -randomseed (or -seed) option to ensure reproducible
+  results.  Often this was done as new test cases were written.  However,
+  inconsistent output caused by system-level differences in rand()
+  implementation remained a major obstacle.
+
+  In 2020 the decision was made to replace all calls to rand() in the Netpbm
+  source code with an internal random number generator.  We decided to use the
+  Mersenne Twister, which is concise, enjoys a fine reputation and is
+  available under liberal conditions (see below.)
+-----------------------------------------------------------------------------*/
+
+
+void
+pm_srand(struct pm_randSt * const randStP,
+         unsigned int       const seed) {
+/*----------------------------------------------------------------------------
+  Initialize (or "seed") the random number generation sequence with value
+  'seed'.
+-----------------------------------------------------------------------------*/
+    pm_randinit(randStP);
+
+    randStP->vtable.srand(randStP, seed);
+
+    randStP->seed = seed;
+}
+
+
+
+void
+pm_srand2(struct pm_randSt * const randStP,
+          bool               const seedValid,
+          unsigned int       const seed) {
+/*----------------------------------------------------------------------------
+  Seed the random number generator.  If 'seedValid' is true, use 'seed"..
+  Otherwise, use pm_randseed().
+
+  For historical reasons pm_randseed() is defined in libpm.c rather than
+  this source file.
+-----------------------------------------------------------------------------*/
+    pm_srand(randStP, seedValid ? seed : pm_randseed() );
+
+}
+
+
+
+unsigned long int
+pm_rand(struct pm_randSt * const randStP) {
+/*----------------------------------------------------------------------------
+  An integer random number in the interval [0, randStP->max].
+-----------------------------------------------------------------------------*/
+    return randStP->vtable.rand(randStP);
+}
+
+
+
+double
+pm_drand(struct pm_randSt * const randStP) {
+/*----------------------------------------------------------------------------
+  A floating point random number in the interval [0, 1).
+
+  Although the return value is declared as double, the actual value will have
+  no more precision than a single call to pm_rand() provides.  This is 32 bits
+  for Mersenne Twister.
+-----------------------------------------------------------------------------*/
+    return (double) pm_rand(randStP) / randStP->max;
+}
+
+
+
+void
+pm_gaussrand2(struct pm_randSt * const randStP,
+              double *           const r1P,
+              double *           const r2P) {
+/*----------------------------------------------------------------------------
+  Generate two Gaussian (or normally) distributed random numbers *r1P and
+  *r2P.
+
+  Mean = 0, Standard deviation = 1.
+
+  This is called the Box-Muller method.
+
+  For details of this algorithm and other methods for producing
+  Gaussian random numbers see:
+
+  http://www.doc.ic.ac.uk/~wl/papers/07/csur07dt.pdf
+-----------------------------------------------------------------------------*/
+    double u1, u2;
+
+    u1 = pm_drand(randStP);
+    u2 = pm_drand(randStP);
+
+    if (u1 < DBL_EPSILON)
+        u1 = DBL_EPSILON;
+
+    *r1P = sqrt(-2.0 * log(u1)) * cos(2.0 * M_PI * u2);
+    *r2P = sqrt(-2.0 * log(u1)) * sin(2.0 * M_PI * u2);
+}
+
+
+
+double
+pm_gaussrand(struct pm_randSt * const randStP) {
+/*----------------------------------------------------------------------------
+  A Gaussian (or normally) distributed random number.
+
+  Mean = 0, Standard deviation = 1.
+
+  If a randStP->gaussCache has a value, return that value.  Otherwise call
+  pm_gaussrand2; return one generated value, remember the other.
+-----------------------------------------------------------------------------*/
+    double retval;
+
+    if (!randStP->gaussCacheValid) {
+        pm_gaussrand2(randStP, &retval, &randStP->gaussCache);
+        randStP->gaussCacheValid = true;
+    } else {
+        retval = randStP->gaussCache;
+        randStP->gaussCacheValid = false;
+    }
+
+    return retval;
+}
+
+
+
+uint32_t
+pm_rand32(struct pm_randSt * const randStP) {
+/*-----------------------------------------------------------------------------
+  Generate a 32-bit random number.
+
+  This is a provision for users who select a non-default random number
+  generator which returns less than 32 bits per call.  Many system generators
+  are known to return 31 bits (max = 2147483647 or 0x7FFFFFFF).
+
+  This does not work with generators that return less than 11 bits per call.
+  The least we know of is the archaic RANDU, which generates 15 bits (max =
+  32767 or 0x7FFF).
+-----------------------------------------------------------------------------*/
+    unsigned int const randMax = randStP->max;
+
+    uint32_t retval;
+
+    if (randMax >= 0xFFFFFFFF)
+        retval = pm_rand(randStP);
+    else {
+        uint32_t scale;
+
+        retval = 0;  /* Initial value */
+
+        for (scale = 0xFFFFFFFF; scale > 0; scale /= (randMax +1))
+            retval *= (randMax + 1) + pm_rand(randStP);
+    }
+
+    return retval;;
+}
+
+
+
+void
+pm_randinit(struct pm_randSt * const randStP) {
+/*----------------------------------------------------------------------------
+  Initialize the random number generator.
+-----------------------------------------------------------------------------*/
+    switch (PM_RANDOM_NUMBER_GENERATOR) {
+    case PM_RAND_SYS_RAND:
+        randStP->vtable = pm_randsysrand_vtable;
+        break;
+    case PM_RAND_SYS_RANDOM:
+        randStP->vtable = pm_randsysrandom_vtable;
+        break;
+    case PM_RAND_MERSENNETWISTER:
+        randStP->vtable = pm_randmersenne_vtable;
+        break;
+    default:
+        pm_error("INTERNAL ERROR: Invalid value of "
+                 "PM_RANDOM_NUMBER_GENERATOR (random number generator "
+                 "engine type): %u", PM_RANDOM_NUMBER_GENERATOR);
+    }
+
+    randStP->vtable.init(randStP);
+
+    randStP->gaussCacheValid = false;
+}
+
+
+
+void
+pm_randterm(struct pm_randSt * const randStP) {
+/*----------------------------------------------------------------------------
+  Tear down the random number generator.
+-----------------------------------------------------------------------------*/
+     if (randStP->stateP)
+         free(randStP->stateP);
+}
+
+
+
+
diff --git a/lib/util/rand.h b/lib/util/rand.h
new file mode 100644
index 00000000..44095243
--- /dev/null
+++ b/lib/util/rand.h
@@ -0,0 +1,112 @@
+/* Interface header file for random number generator functions in libnetpbm */
+
+#ifndef RAND_H_INCLUDED
+#define RAND_H_INCLUDED
+
+#include <inttypes.h>
+
+#include "netpbm/pm_c_util.h"
+#include "netpbm/mallocvar.h"
+
+/*
+  Definitions for selecting the random number generator
+
+  The default random number generator is Mersenne Twister.  Here we
+  provide a means to revert to the system rand() generator if need be.
+
+  Glibc provides generators: rand(), random() and drand48().  Each has
+  its own associated functions.  In the Glibc documentation rand() is
+  called "ISO", random() is called "BSD" and drand48() is called "SVID".
+  If your system has the glibc documentation installed "info rand" should
+  get you to the relevant page.  The documentation is available online
+  from:
+
+  https://www.gnu.org/software/libc/manual/html_node/Pseudo_002dRandom-Numbers.html
+  Pseudo-Random Numbers (The GNU C Library)
+
+  Glibc's choice of name is confusing for what it calls "ISO" rand()
+  was available in early BSD systems.
+
+  Functions by these names appear on most Unix systems, but generation
+  formulas and default initial states are known to differ.  On systems
+  which do not use glibc, what is called rand() may have no relation
+  with the formula of the ISO C standard.  Likewise random() may have
+  no relation with the BSD formula.
+*/
+
+enum PmRandEngine {PM_RAND_SYS_RAND,         /* rand()   */
+                   PM_RAND_SYS_RANDOM,       /* random() */
+                   PM_RAND_SYS_DRAND48,      /* drand48()  reserved */
+                   PM_RAND_MERSENNETWISTER   /* default */};
+
+#ifndef PM_RANDOM_NUMBER_GENERATOR
+  #define PM_RANDOM_NUMBER_GENERATOR PM_RAND_MERSENNETWISTER
+#endif
+
+
+/* Structure to hold random number generator profile and internal state */
+
+struct pm_randSt;
+
+struct pm_rand_vtable {
+    void
+    (*init)(struct pm_randSt * const randStP);
+
+    void
+    (*srand)(struct pm_randSt * const randStP,
+              unsigned int       const seed);
+
+    unsigned long int
+    (*rand)(struct pm_randSt * const randStP);
+};
+
+extern struct pm_rand_vtable const pm_randsysrand_vtable;
+extern struct pm_rand_vtable const pm_randsysrandom_vtable;
+extern struct pm_rand_vtable const pm_randmersenne_vtable;
+
+struct pm_randSt {
+    struct pm_rand_vtable vtable;
+    void *                stateP;  /* Internal state */
+    unsigned int          max;
+    unsigned int          seed;
+    bool                  gaussCacheValid;
+    double                gaussCache;
+};
+
+/* Function declarations */
+
+extern void
+pm_randinit(struct pm_randSt * const randStP);
+
+extern void
+pm_randterm(struct pm_randSt * const randStP);
+
+extern void
+pm_srand(struct pm_randSt * const randStP,
+         unsigned int       const seed);
+
+
+extern void
+pm_srand2(struct pm_randSt * const randStP,
+          bool               const withSeed,
+          unsigned int       const seedVal);
+
+extern unsigned long int
+pm_rand(struct pm_randSt * const randStP);
+
+extern double
+pm_drand(struct pm_randSt * const randStP);
+
+extern void
+pm_gaussrand2(struct pm_randSt * const randStP,
+              double *           const r1P,
+              double *           const r2P);
+
+extern double
+pm_gaussrand(struct pm_randSt * const randStP);
+
+extern uint32_t
+pm_rand32(struct pm_randSt * const randStP);
+
+
+#endif
diff --git a/lib/util/randmersenne.c b/lib/util/randmersenne.c
new file mode 100644
index 00000000..34355a23
--- /dev/null
+++ b/lib/util/randmersenne.c
@@ -0,0 +1,192 @@
+#include "netpbm/pm.h"
+#include "netpbm/rand.h"
+
+/* +++++ Start of Mersenne Twister pseudorandom number generator code +++++ */
+
+/*
+   Original source code from:
+   http://www.math.sci.hiroshima-u.ac.jp/m-mat/MT/VERSIONS/C-LANG/c-lang.html
+
+   A C-program for MT19937, with initialization improved 2002/1/26.
+   Coded by Takuji Nishimura and Makoto Matsumoto.
+
+   Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
+   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 names of its contributors may not be used to endorse or promote
+        products derived from this software without specific prior written
+        permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   Any feedback is very welcome.
+   http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+   email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
+
+   Above conditions apply in the following code to the line which says:
+   +++++ End of Mersenne Twister pseudorandom number generator code +++++
+*/
+
+/* Period parameters */
+
+#define MT_N 624
+#define MT_M 397
+#define MT_MATRIX_A 0x9908b0dfUL   /* constant vector a */
+
+struct MtState {
+    uint32_t mt[MT_N]; /* the array for the state vector  */
+    unsigned int mtIndex;
+};
+
+
+
+static void
+randMtAlloc(struct MtState ** const statePP) {
+
+    struct MtState * stateP;
+
+    MALLOCVAR_NOFAIL(stateP);
+
+    *statePP = stateP;
+}
+
+
+
+/* 32 bit masks */
+
+static uint32_t const FMASK = 0xffffffffUL; /* all bits */
+static uint32_t const UMASK = 0x80000000UL; /* most significant bit */
+static uint32_t const LMASK = 0x7fffffffUL; /* least significant 31 bits */
+
+
+
+static void
+srandMt(struct MtState * const stateP,
+        unsigned int     const seed) {
+/*-----------------------------------------------------------------------------
+  Initialize state array mt[MT_N] with seed
+-----------------------------------------------------------------------------*/
+    unsigned int mtIndex;
+    uint32_t * const mt = stateP->mt;
+
+    mt[0]= seed & FMASK;
+
+    for (mtIndex = 1; mtIndex < MT_N; ++mtIndex) {
+        mt[mtIndex] = (1812433253UL * (mt[mtIndex-1]
+                       ^ (mt[mtIndex-1] >> 30)) + mtIndex);
+
+        /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
+    }
+
+    stateP->mtIndex = mtIndex;
+}
+
+
+
+static unsigned long int
+randMt32(struct MtState * const stateP) {
+/*----------------------------------------------------------------------------
+  Generate a 32 bit random number   interval: [0, 0xffffffff]
+  ----------------------------------------------------------------------------*/
+    unsigned int mtIndex;
+    uint32_t retval;
+
+    if (stateP->mtIndex >= MT_N) {
+        /* generate N words at one time */
+        uint32_t * const mt = stateP->mt;
+        uint32_t const mag01[2]={0x0UL, MT_MATRIX_A};
+        /* mag01[x] = x * MT_MATRIX_A  for x=0, 1 */
+
+        int k;
+        uint32_t y;
+
+        if (stateP->mtIndex >= MT_N+1) {
+            pm_error("Internal error in Mersenne Twister random number"
+                     "generator");
+        }
+
+        for (k = 0; k < MT_N-MT_M; ++k) {
+            y = (mt[k] & UMASK) | (mt[k+1] & LMASK);
+            mt[k] = mt[k + MT_M] ^ (y >> 1) ^ mag01[y & 0x1UL];
+        }
+        for (; k < MT_N-1; ++k) {
+            y = (mt[k] & UMASK) | (mt[k+1] & LMASK);
+            mt[k] = mt[k+(MT_M-MT_N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
+        }
+        y = (mt[MT_N - 1] & UMASK) | (mt[0] & LMASK);
+        mt[MT_N - 1] = mt[MT_M - 1] ^ (y >> 1) ^ mag01[y & 0x1UL];
+
+        mtIndex = 0;
+    } else
+        mtIndex = stateP->mtIndex;
+
+    retval = stateP->mt[mtIndex];
+
+    /* Tempering */
+    retval ^= (retval >> 11);
+    retval ^= (retval <<  7) & 0x9d2c5680UL;
+    retval ^= (retval << 15) & 0xefc60000UL;
+    retval ^= (retval >> 18);
+
+    stateP->mtIndex = mtIndex + 1;
+
+    return retval;
+}
+
+/* +++++ End of Mersenne Twister pseudorandom number generator code +++++ */
+
+
+static void
+vinit(struct pm_randSt * const randStP) {
+
+    randMtAlloc((struct MtState ** const) &randStP->stateP);
+    randStP->max    = 0xffffffffUL;
+}
+
+
+
+static void
+vsrand(struct pm_randSt * const randStP,
+       unsigned int       const seed) {
+
+    srandMt(randStP->stateP, seed);
+}
+
+
+
+static unsigned long int
+vrand(struct pm_randSt * const randStP) {
+
+    return randMt32(randStP->stateP);
+}
+
+
+
+struct pm_rand_vtable const pm_randmersenne_vtable = {
+    &vinit,
+    &vsrand,
+    &vrand
+};
+
+
diff --git a/lib/util/randsysrand.c b/lib/util/randsysrand.c
new file mode 100644
index 00000000..f97a5d3c
--- /dev/null
+++ b/lib/util/randsysrand.c
@@ -0,0 +1,39 @@
+#include <stdlib.h>
+
+#include "netpbm/rand.h"
+
+
+
+static void
+vinit(struct pm_randSt * const randStP) {
+
+    randStP->max    = RAND_MAX;
+    randStP->stateP = NULL;
+}
+
+
+
+static void
+vsrand(struct pm_randSt * const randStP,
+       unsigned int       const seed) {
+
+    srand(seed);
+}
+
+
+
+static unsigned long int
+vrand(struct pm_randSt * const randStP) {
+
+    return rand();
+}
+
+
+
+struct pm_rand_vtable const pm_randsysrand_vtable = {
+    &vinit,
+    &vsrand,
+    &vrand
+};
+
+
diff --git a/lib/util/randsysrandom.c b/lib/util/randsysrandom.c
new file mode 100644
index 00000000..f26bb18d
--- /dev/null
+++ b/lib/util/randsysrandom.c
@@ -0,0 +1,45 @@
+/* Implementation note: Mingw/Windows does not provide POSIX 'random', so
+   netpbm/pm_config.h makes that a macro for POSIX 'rand' on that platform
+*/
+
+#define _DEFAULT_SOURCE /* New name for SVID & BSD source defines */
+#define _XOPEN_SOURCE 500  /* Make sure random() is in stdlib.h */
+#define _BSD_SOURCE  /* Make sure random() is in stdlib.h */
+
+#include <stdlib.h>
+
+#include "netpbm/pm_config.h"
+#include "netpbm/rand.h"
+
+static void
+vinit(struct pm_randSt * const randStP) {
+
+    randStP->max    = RAND_MAX;
+    randStP->stateP = NULL;
+}
+
+
+
+static void
+vsrand(struct pm_randSt * const randStP,
+       unsigned int       const seed) {
+
+    srandom(seed);
+}
+
+
+
+static unsigned long int
+vrand(struct pm_randSt * const randStP) {
+
+    return random();
+}
+
+
+struct pm_rand_vtable const pm_randsysrandom_vtable = {
+    &vinit,
+    &vsrand,
+    &vrand
+};
+
+
diff --git a/lib/util/runlength.c b/lib/util/runlength.c
index 62e3bf0c..8f60759d 100644
--- a/lib/util/runlength.c
+++ b/lib/util/runlength.c
@@ -29,7 +29,7 @@
   A survey of netpbm source code in 2015 found Packbits encoding in the
   following Netpbm programs: pbmtoescp2, pbmtomacp, pnmtopalm, pnmtopclxl,
   pnmtops, ppmtoilbm and ppmtopjxl.
- 
+
   Packbits is an option in the TIFF standard; pamtotiff can generate TIFF
   images that use Packbits compression, but does so via code in the TIFF
   library (not part of Netpbm).
@@ -47,7 +47,7 @@
 
   Today, all Netpbm programs that do Packbits compression with the exception
   of pamtotiff, pbmtoppa, pbmtogo and pamtotga use the facilities in this
-  file for it.  
+  file for it.
 =============================================================================*/
 
 #include <string.h>
@@ -71,7 +71,7 @@ static const char * const errorUndefinedMode =
    strings follow a single index or "flag" byte N.  There are several
    variations, differing in the format of the flag byte, maximum string
    length and element size (byte or word).
-   
+
    In the most widely used version, Packbits, the meaning of the flag byte
    N is defined as follows:
 
@@ -110,7 +110,7 @@ pm_rlenc_compressbyte(const unsigned char * const inbuf,
 
     int packBase;
     int packSign;
- 
+
     switch (mode) {
     case PM_RLE_PACKBITS:
         packBase = 257 ; packSign = -1; break;
@@ -128,7 +128,7 @@ pm_rlenc_compressbyte(const unsigned char * const inbuf,
             for (count = 0;
                  inCurs < inSize &&
                      inbuf[inCurs] == inbuf[hold] &&
-                     count < maxRun; 
+                     count < maxRun;
                  ++inCurs, ++count)
                 ;
             outbuf[outCurs++] = (unsigned char) (packBase + packSign * count);
@@ -139,7 +139,7 @@ pm_rlenc_compressbyte(const unsigned char * const inbuf,
             size_t count;
             ++outCurs;
             count = 0;
-            while(((inCurs + 2 >= inSize) && (inCurs < inSize) ) || 
+            while(((inCurs + 2 >= inSize) && (inCurs < inSize) ) ||
                   ((inCurs + 2 <  inSize) &&
                    ((inbuf[inCurs] != inbuf[inCurs+1]  )
                     || (inbuf[inCurs] != inbuf[inCurs+2]  ) ) )    ) {
@@ -242,7 +242,7 @@ pm_rlenc_compressword(const uint16_t   * const inbuf,
             outCurs += count * 2;
         }
     }
-    
+
     if (mode == PM_RLE_SGI16) {
         * (uint16_t *) &outbuf[outCurs] = 0;     /* terminator */
         outCurs += 2;
@@ -336,7 +336,7 @@ pm_rlenc_maxbytes(size_t          const inSize,  /* number of elements */
     size_t itemSize;   /* Size of item, in bytes */
     size_t miscSize;   /* Size of other elements such as term code, in bytes */
     size_t overhead;   /* Worst-case overhead, in bytes */
-    /* return value:      Worst-case output size, in bytes */ 
+    /* return value:      Worst-case output size, in bytes */
 
     switch (mode) {
     case PM_RLE_PACKBITS:
@@ -359,7 +359,7 @@ pm_rlenc_maxbytes(size_t          const inSize,  /* number of elements */
     default:
         pm_error(errorUndefinedMode, mode);
     }
-    
+
     overhead = miscSize +
         (inSize / blockSize + (inSize % blockSize > 0 ? 1 : 0) ) * flagSize;
 
diff --git a/lib/util/shhopt.README b/lib/util/shhopt.README
index 2d241edf..f34f9a39 100644
--- a/lib/util/shhopt.README
+++ b/lib/util/shhopt.README
@@ -7,19 +7,20 @@ The file LICENSE.TXT in this directory contains the license (the
 Artistic License) under which Bryan took and redistributed Shhopt and
 the license under which Bryan offers the modified Shhopt to others.
 
-Bryan made the following changes to shhopt for Netpbm.  It is fully
-backward compatible with the original.
+Bryan made the following changes to shhopt for Netpbm.  
 
 - OPT_FLOAT (floating point number) data type added
 
-- optParseOptions2() added.  Advantages over optParseOptions(): You
+- symbols prefixed with "pm_".
+
+- pm_optParseOptions2() added.  Advantages over pm_optParseOptions(): You
   can have a syntax where there is no such thing as a short option
   (e.g. -a.  Maybe stacked like -tanp).  Then the long options can
   have either 1 or 2 dashes (e.g. -width or --width).  Of course, -w
   could be an abbreviation of -width; that's not the same thing as a
   short option.
 
-- optParseOptions3() added.  Advantages over optParseOptions2(): 
+- pm_optParseOptions3() added.  Advantages over pm_optParseOptions2(): 
   Tells you whether (how many times, actually) an option was
   specified - no need to play games with defaults.  Also, no need
   to initialize an option value variable.
@@ -34,6 +35,15 @@ backward compatible with the original.
 - replace isdigit() with ISDIGIT() from Netpbm nstring.h so weird 
   8-bit characters don't cause incorrect results.
 
+- OPT_NAMELIST and OPT_STRINGLIST added.
+
+WARNING: pm_optParseOptionsX modify their argv argument (the array of
+pointers, not the the things to which they point).
+
+WARNING: The option values returned by pm_optParseOptionsX for options of type
+OPT_STRING reside in the program's argument space (the memory addressed by the
+program's argv array).
+
 ------------------------------------------------------------------------------
 
 
diff --git a/lib/util/shhopt.c b/lib/util/shhopt.c
index ab489fef..00f9c341 100644
--- a/lib/util/shhopt.c
+++ b/lib/util/shhopt.c
@@ -6,7 +6,7 @@
  |                  or passed to functions as specified.
  |
  |  REQUIREMENTS    Some systems lack the ANSI C -function strtoul. If your
- |                  system is one of those, you'll ned to write one yourself,
+ |                  system is one of those, you'll need to write one yourself,
  |                  or get the GNU liberty-library (from prep.ai.mit.edu).
  |
  |  WRITTEN BY      Sverre H. Huseby <sverrehu@online.no>
@@ -92,51 +92,71 @@ optStructCount(const optEntry opt[])
 
 
 
-static int
-optMatch(optEntry     const opt[],
-         const char * const s,
-         int          const lng) {
+enum Shortlong {SL_SHORT, SL_LONG};
+
+
+static void
+optMatch(optEntry       const opt[],
+         const char *   const targetOpt,
+         enum Shortlong const shortLong,
+         bool *         const foundP,
+         int *          const optIndexP) {
 /*------------------------------------------------------------------------
  |  FUNCTION      Find a matching option.
  |
- |  INPUT         opt     array of possible options.
- |                s       string to match, without `-' or `--'.
- |                lng     match long option, otherwise short.
+ |  INPUT         opt        array of valid option names.
+ |                targetOpt  option string to match, without `-' or `--'.
+ |                           e.g. "verbose" or "height=5"
+ |                shortLong  whether to match short option or long
  |
- |  RETURNS       Index to the option if found, -1 if not found.
+ |  RETURNS       *foundP     there is a matching option class the table
+ !                *optIndexP  index in the option class table
+ |                            meaningless if *foundP is false
  |
  |  DESCRIPTION   Short options are matched from the first character in
  |                the given string.
+ |
+ |                Where multiple entries in opt[] match, return the first.
  */
 
-    unsigned int const nopt = optStructCount(opt);
+    unsigned int const optCt = optStructCount(opt);
 
     unsigned int q;
     unsigned int matchlen;
-    const char * p;
+    bool found;
+    unsigned int optIndex;
 
-    matchlen = 0;  /* initial value */
-
-    if (lng) {
-        if ((p = strchr(s, '=')) != NULL)
-            matchlen = p - s;
+    if (shortLong == SL_LONG) {
+        const char * const equalPos = strchr(targetOpt, '=');
+        if (equalPos)
+            matchlen = equalPos - &targetOpt[0];
         else
-            matchlen = strlen(s);
-    }
-    for (q = 0; q < nopt; ++q) {
-        if (lng) {
+            matchlen = strlen(targetOpt);
+    } else
+        matchlen = 0;
+
+    for (q = 0, found = false; q < optCt && !found; ++q) {
+        switch (shortLong) {
+        case SL_LONG: {
             if (opt[q].longName) {
-                if (strncmp(s, opt[q].longName, matchlen) == 0)
-                    return q;
+                if (strneq(targetOpt, opt[q].longName, matchlen)) {
+                    found = true;
+                    optIndex = q;
+                }
             }
-        } else {
+        }
+        case SL_SHORT: {
             if (opt[q].shortName) {
-                if (s[0] == opt[q].shortName)
-                    return q;
+                if (targetOpt[0] == opt[q].shortName) {
+                    found = true;
+                    optIndex = q;
+                }
             }
         }
+        }
     }
-    return -1;
+    *foundP    = found;
+    *optIndexP = optIndex;
 }
 
 
@@ -394,7 +414,7 @@ static void
 optExecute(optEntry  const opt, char *arg, int lng)
 {
     if (opt.specified)
-        (*(opt.specified))++;
+        *opt.specified = 1;
 
     switch (opt.type) {
     case OPT_FLAG:
@@ -556,13 +576,12 @@ pm_optSetFatalFunc(void (*f)(const char *, ...)) {
 void
 pm_optParseOptions(int *argc, char *argv[], optStruct opt[], int allowNegNum)
 {
-    int  ai,        /* argv index. */
-         optarg,    /* argv index of option argument, or -1 if none. */
-         mi,        /* Match index in opt. */
-         done;
-    char *arg,      /* Pointer to argument to an option. */
-         *o,        /* pointer to an option character */
-         *p;
+    int ai;        /* argv index. */
+    int optarg;    /* argv index of option argument, or -1 if none. */
+    int done;
+    char * arg;      /* Pointer to argument to an option. */
+    char * o;        /* pointer to an option character */
+    char * p;
 
     optEntry *opt_table;  /* malloc'ed array */
 
@@ -579,7 +598,7 @@ pm_optParseOptions(int *argc, char *argv[], optStruct opt[], int allowNegNum)
          *  "--" indicates that the rest of the argv-array does not
          *  contain options.
          */
-        if (strcmp(argv[ai], "--") == 0) {
+        if (streq(argv[ai], "--")) {
             argvRemove(argc, argv, ai);
             break;
         }
@@ -587,10 +606,13 @@ pm_optParseOptions(int *argc, char *argv[], optStruct opt[], int allowNegNum)
         if (allowNegNum && argv[ai][0] == '-' && ISDIGIT(argv[ai][1])) {
             ++ai;
             continue;
-        } else if (strncmp(argv[ai], "--", 2) == 0) {
+        } else if (strneq(argv[ai], "--", 2)) {
+            bool found;
+            int mi;
             /* long option */
             /* find matching option */
-            if ((mi = optMatch(opt_table, argv[ai] + 2, 1)) < 0)
+            optMatch(opt_table, argv[ai] + 2, SL_LONG, &found, &mi);
+            if (!found)
                 optFatal("unrecognized option `%s'", argv[ai]);
 
             /* possibly locate the argument to this option. */
@@ -629,8 +651,11 @@ pm_optParseOptions(int *argc, char *argv[], optStruct opt[], int allowNegNum)
             done = 0;
             optarg = -1;
             while (*o && !done) {
+                bool found;
+                int mi;
                 /* find matching option */
-                if ((mi = optMatch(opt_table, o, 0)) < 0)
+                optMatch(opt_table, o, SL_SHORT, &found, &mi);
+                if (!found)
                     optFatal("unrecognized option `-%c'", *o);
 
                 /* does this option take an argument? */
@@ -679,7 +704,6 @@ parse_short_option_token(char *argv[], const int argc, const int ai,
 -----------------------------------------------------------------------------*/
     char *o;  /* A short option character */
     char *arg;
-    int mi;   /* index into option table */
     unsigned char processed_arg;  /* boolean */
         /* We processed an argument to one of the one-character options.
            This necessarily means there are no more options in this token
@@ -691,8 +715,11 @@ parse_short_option_token(char *argv[], const int argc, const int ai,
     o = argv[ai] + 1;
     processed_arg = 0;  /* initial value */
     while (*o && !processed_arg) {
+        bool found;
+        int mi;   /* index into option table */
 		/* find matching option */
-		if ((mi = optMatch(opt_table, o, 0)) < 0)
+		optMatch(opt_table, o, SL_SHORT, &found, &mi);
+		if (!found)
 		    optFatal("unrecognized option `-%c'", *o);
 
 		/* does this option take an argument? */
@@ -721,7 +748,7 @@ static void
 fatalUnrecognizedLongOption(const char * const optionName,
                             optEntry     const optTable[]) {
 
-    unsigned int const nopt = optStructCount(optTable);
+    unsigned int const optCt = optStructCount(optTable);
 
     unsigned int q;
 
@@ -730,7 +757,7 @@ fatalUnrecognizedLongOption(const char * const optionName,
     optList[0] = '\0';  /* initial value */
 
     for (q = 0;
-         q < nopt && strlen(optList) + 1 <= sizeof(optList);
+         q < optCt && strlen(optList) + 1 <= sizeof(optList);
          ++q) {
 
         const optEntry * const optEntryP = &optTable[q];
@@ -777,6 +804,7 @@ parse_long_option(char *   const argv[],
          "=".  NULL if no "=" in the token.
          */
     char *arg;     /* The argument of an option; NULL if none */
+    bool found;
     int mi;    /* index into option table */
 
     /* The current token is an option, and its name starts at
@@ -784,7 +812,8 @@ parse_long_option(char *   const argv[],
     */
     *tokens_consumed_p = 1;  /* initial assumption */
     /* find matching option */
-    if ((mi = optMatch(opt_table, &argv[ai][namepos], 1)) < 0)
+    optMatch(opt_table, &argv[ai][namepos], SL_LONG, &found, &mi);
+    if (!found)
         fatalUnrecognizedLongOption(argv[ai], opt_table);
 
     /* possibly locate the argument to this option. */
diff --git a/lib/util/shhopt.h b/lib/util/shhopt.h
index d9304f9f..27adc144 100644
--- a/lib/util/shhopt.h
+++ b/lib/util/shhopt.h
@@ -10,14 +10,12 @@ main ( int argc, char **argv ) {
     /* initial values here are just to demonstrate what gets set and
        what doesn't by the code below.
     */
-    int help_flag = 7;
-    unsigned int help_spec =7;
-    unsigned int height_spec =7;
-    unsigned int name_spec= 7;
+    unsigned int heightSpec =7;
+    unsigned int nameSpec= 7;
     char *name= "initial";
     int height=7;
-    int verbose_flag=7;
-    int debug_flag=7;
+    int verboseFlag=7;
+    int debugFlag=7;
     char ** methodlist;
     struct optNameValue * optlist;
 
@@ -26,13 +24,12 @@ main ( int argc, char **argv ) {
     optEntry * option_def;
     MALLOCARRAY(option_def, 100);
 
-    OPTENT3(0,   "help",     OPT_FLAG,       &help_flag,    &help_spec,   0);
-    OPTENT3(0,   "height",   OPT_INT,        &height,       &height_spec, 0);
-    OPTENT3('n', "name",     OPT_STRING,     &name,         &name_spec,   0);
-    OPTENT3('v', "verbose",  OPT_FLAG,       &verbose_flag, NULL,         0);
-    OPTENT3('g', "debug",    OPT_FLAG,       &debug_flag,   NULL,         0);
-    OPTENT3(0,   "methods",  OPT_STRINGLIST, &methodlist,   NULL,         0);
-    OPTENT3(0,   "options",  OPT_NAMELIST,   &optlist,      NULL,         0);
+    OPTENT3(0,   "height",   OPT_INT,        &height,       &heightSpec,  0);
+    OPTENT3('n', "name",     OPT_STRING,     &name,         &nameSpec,    0);
+    OPTENT3('v', "verbose",  OPT_FLAG,       &verboseFlag,  NULL,         0);
+    OPTENT3('g', "debug",    OPT_FLAG,       &debugFlag,    NULL,         0);
+    OPTENT3(0,   "methods",  OPT_STRINGLIST, &methodlist,   &methodSpec,  0);
+    OPTENT3(0,   "options",  OPT_NAMELIST,   &optlist,      &optSpec,     0);
 
     opt.opt_table = option_def;
     opt.short_allowed = 1;
@@ -43,16 +40,14 @@ main ( int argc, char **argv ) {
 
 
     printf("argc=%d\n", argc);
-    printf("help_flag=%d\n", help_flag);
-    printf("help_spec=%d\n", help_spec);
     printf("height=%d\n", height);
-    printf("height_spec=%d\n", height_spec);
+    printf("height_spec=%d\n", heightSpec);
     printf("name='%s'\n", name);
-    printf("name_spec=%d\n", name_spec);
-    printf("verbose_flag=%d\n", verbose_flag);
-    printf("debug_flag=%d\n", verbose_flag);
+    printf("name_spec=%d\n", nameSpec);
+    printf("verbose_flag=%d\n", verboseFlag);
+    printf("debug_flag=%d\n", verboseFlag);
 
-    if (methodlist) {
+    if (methodSpec) {
         unsigned int i;
         printf("methods: ");
         while (methodlist[i]) {
@@ -63,7 +58,7 @@ main ( int argc, char **argv ) {
     } else
         printf("No -options\n");
 
-    if (optlist) {
+    if (optSpec) {
         unsigned int i;
         while (optlist[i].name) {
             printf("option '%s' = '%s'\n", optlist[i].name, optlist[i].value);
@@ -76,7 +71,7 @@ main ( int argc, char **argv ) {
 
 Now run this program with something like
 
-  myprog -vg --name=Bryan --hei 4 "My first argument" --help
+  myprog -vg --name=Bryan --hei 4 "My first argument" --verbose
 
   or do it with opt.short_allowed=0 and
 
@@ -87,6 +82,7 @@ Now run this program with something like
   you need an OPTENTINIT call to establish the empty option table:
 
     optEntry * option_def;
+    unsigned int option_def_index;
     MALLOCARRAY(option_def, 1);
     OPTENTINIT;
 
@@ -144,8 +140,8 @@ typedef struct {
            the rightmost one affects this return value.
         */
     unsigned int *specified;
-        /* pointer to variable in which to return the number of times that
-           the option was specified.  If NULL, don't return anything.
+        /* pointer to variable in which to return 1 if the option was
+           specified and 0 if it was not.  If NULL, don't return anything.
         */
     int        flags;      /* modifier flags. */
 } optEntry;
@@ -184,7 +180,7 @@ typedef struct {
 
        unsigned int option_def_index = 0;
        optStruct *option_def = malloc(100*sizeof(optStruct));
-       OPTENTRY('h', "help",     OPT_FLAG, &help_flag, 0);
+       OPTENTRY('h', "verbose",  OPT_FLAG, &verbose_flag, 0);
        OPTENTRY(0,   "alphaout", OPT_STRING, &alpha_filename, 0);
 */
 
@@ -213,15 +209,23 @@ typedef struct {
 /* OPTENT3 is the same as OPTENTRY except that it also sets the "specified"
    element of the table entry (so it assumes OPTION_DEF is a table of optEntry
    instead of optStruct).  This is a pointer to a variable that the parser
-   will set to the number of times that the option appears in the command
-   line.
+   will set to an indication of whether the option appears in the command
+   line.  1 for yes; 0 for no.
+
+   HISTORICAL NOTE: Until 2019, this was the number of times the option was
+   specified, but much Netpbm code assumed it was never more than 1, and no
+   Netpbm code has ever given semantics to specifying the same option class
+   multiple times.
 
    Here is an example:
 
        unsigned int option_def_index = 0;
+       unsigned int verbose_flag;
+       const char * alpha_filename
+       unsigned int alpha_spec;
        MALLOCARRAY_NOFAIL(option_def, 100);
-       OPTENT3('h', "help",     OPT_FLAG, &help_flag, 0);
-       OPTENT3(0,   "alphaout", OPT_STRING, &alpha_filename, 0);
+       OPTENT3('h', "verbose",  OPT_FLAG,   &verbose_flag,   NULL,        0);
+       OPTENT3(0,   "alphaout", OPT_STRING, &alpha_filename, &alpha_spec, 0);
 */
 
 #define OPTENT3(shortvalue,longvalue,typevalue,outputvalue,specifiedvalue, \
diff --git a/other/Makefile b/other/Makefile
index aa0d75bb..b3884666 100644
--- a/other/Makefile
+++ b/other/Makefile
@@ -24,10 +24,14 @@ endif
 # build.
 
 PORTBINARIES = pamarith pambayer pamchannel pamdepth \
-	pamendian pamexec pamfix pamlookup pampick pamsplit \
+	pamendian pamfix pamlookup pampick pamsplit \
 	pamstack pamsummcol pamunlookup pamvalidate pnmcolormap \
 	ppmdcfont ppmddumpfont ppmdmkfont 
 
+ifneq ($(DONT_HAVE_PROCESS_MGMT),Y)
+  PORTBINARIES += pamexec
+endif
+
 ifneq ($(LINUXSVGALIB),NONE)
   PORTBINARIES += ppmsvgalib
 endif
diff --git a/other/pamarith.c b/other/pamarith.c
index 3f44dc73..31f52a59 100644
--- a/other/pamarith.c
+++ b/other/pamarith.c
@@ -1,14 +1,18 @@
 #include <assert.h>
 #include <string.h>
 #include <limits.h>
+#include <math.h>
 
 #include "pm_c_util.h"
 #include "mallocvar.h"
+#include "nstring.h"
 #include "shhopt.h"
 #include "pam.h"
 
-enum function {FN_ADD, FN_SUBTRACT, FN_MULTIPLY, FN_DIVIDE, FN_DIFFERENCE,
-               FN_MINIMUM, FN_MAXIMUM, FN_MEAN, FN_COMPARE,
+static double const EPSILON = 1.0e-5;
+
+enum Function {FN_ADD, FN_SUBTRACT, FN_MULTIPLY, FN_DIVIDE, FN_DIFFERENCE,
+               FN_MINIMUM, FN_MAXIMUM, FN_MEAN, FN_EQUAL, FN_COMPARE,
                FN_AND, FN_OR, FN_NAND, FN_NOR, FN_XOR,
                FN_SHIFTLEFT, FN_SHIFTRIGHT
               };
@@ -16,16 +20,15 @@ enum function {FN_ADD, FN_SUBTRACT, FN_MULTIPLY, FN_DIVIDE, FN_DIFFERENCE,
 
 
 static bool
-isDyadic(enum function const function) {
+isDyadic(enum Function const function) {
 
     bool retval;
-    
+
     switch (function) {
     case FN_ADD:
     case FN_MULTIPLY:
     case FN_MINIMUM:
     case FN_MAXIMUM:
-    case FN_MEAN:
     case FN_AND:
     case FN_NAND:
     case FN_OR:
@@ -37,8 +40,10 @@ isDyadic(enum function const function) {
     case FN_DIFFERENCE:
     case FN_COMPARE:
     case FN_DIVIDE:
+    case FN_MEAN:
     case FN_SHIFTLEFT:
     case FN_SHIFTRIGHT:
+    case FN_EQUAL:
         retval = TRUE;
         break;
     }
@@ -51,9 +56,10 @@ struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    enum function function;
+    enum Function function;
     unsigned int operandCt;
     const char ** operandFileNames;
+    double closeness;
 };
 
 
@@ -71,12 +77,14 @@ parseCommandLine(int argc, const char ** const argv,
     optStruct3 opt;
 
     unsigned int option_def_index;
-    
+
     unsigned int addSpec, subtractSpec, multiplySpec, divideSpec,
         differenceSpec,
-        minimumSpec, maximumSpec, meanSpec, compareSpec,
+        minimumSpec, maximumSpec, meanSpec, equalSpec, compareSpec,
         andSpec, orSpec, nandSpec, norSpec, xorSpec,
-        shiftleftSpec, shiftrightSpec;
+        shiftleftSpec, shiftrightSpec, closenessSpec;
+
+    float closeness;
 
     MALLOCARRAY_NOFAIL(option_def, 100);
 
@@ -89,6 +97,7 @@ parseCommandLine(int argc, const char ** const argv,
     OPTENT3(0, "minimum",     OPT_FLAG,   NULL, &minimumSpec,    0);
     OPTENT3(0, "maximum",     OPT_FLAG,   NULL, &maximumSpec,    0);
     OPTENT3(0, "mean",        OPT_FLAG,   NULL, &meanSpec,       0);
+    OPTENT3(0, "equal",       OPT_FLAG,   NULL, &equalSpec,      0);
     OPTENT3(0, "compare",     OPT_FLAG,   NULL, &compareSpec,    0);
     OPTENT3(0, "and",         OPT_FLAG,   NULL, &andSpec,        0);
     OPTENT3(0, "or",          OPT_FLAG,   NULL, &orSpec,         0);
@@ -97,6 +106,7 @@ parseCommandLine(int argc, const char ** const argv,
     OPTENT3(0, "xor",         OPT_FLAG,   NULL, &xorSpec,        0);
     OPTENT3(0, "shiftleft",   OPT_FLAG,   NULL, &shiftleftSpec,  0);
     OPTENT3(0, "shiftright",  OPT_FLAG,   NULL, &shiftrightSpec, 0);
+    OPTENT3(0, "closeness",   OPT_FLOAT,  &closeness, &closenessSpec, 0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
@@ -106,7 +116,7 @@ parseCommandLine(int argc, const char ** const argv,
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (addSpec + subtractSpec + multiplySpec + divideSpec + differenceSpec +
-        minimumSpec + maximumSpec + meanSpec + compareSpec +
+        minimumSpec + maximumSpec + meanSpec + equalSpec + compareSpec +
         andSpec + orSpec + nandSpec + norSpec + xorSpec +
         shiftleftSpec + shiftrightSpec > 1)
         pm_error("You may specify only one function");
@@ -127,6 +137,8 @@ parseCommandLine(int argc, const char ** const argv,
         cmdlineP->function = FN_MAXIMUM;
     else if (meanSpec)
         cmdlineP->function = FN_MEAN;
+    else if (equalSpec)
+        cmdlineP->function = FN_EQUAL;
     else if (compareSpec)
         cmdlineP->function = FN_COMPARE;
     else if (andSpec)
@@ -146,21 +158,35 @@ parseCommandLine(int argc, const char ** const argv,
     else
         pm_error("You must specify a function (e.g. '-add')");
 
+    if (closenessSpec) {
+        if (cmdlineP->function != FN_EQUAL)
+            pm_error("-closeness is valid only with -equal");
+        else {
+            if (closeness < 0 || closeness > 100)
+                pm_error("-closeness value %f is not a valid percentage",
+                         closeness);
+            cmdlineP->closeness = (double)closeness/100;
+        }
+    } else
+        cmdlineP->closeness = EPSILON;
+
     if (argc-1 < 2)
         pm_error("You must specify at least two arguments: the files which "
                  "are the operands of the function.  You specified %u",
                  argc-1);
     else {
         if (isDyadic(cmdlineP->function) && argc-1 > 2)
-            pm_error("You specified %u arguments, but a dyadic function.  "
-                     "For a dyadic function, you must specify 2 arguments:  "
-                     "the operands of the function", argc-1);
+            pm_error("You specified %u arguments, but a function "
+                     "which is not associative and commutative.  "
+                     "Unless a function is associative and commutative "
+                     "(like -add), you must specify exactly two arguments. ",
+                     argc-1);
         else {
             cmdlineP->operandCt = argc-1;
             cmdlineP->operandFileNames = &argv[1];
         }
     }
-}        
+}
 
 
 
@@ -179,11 +205,69 @@ enum category {
 
 
 
+static void
+validateSameWidthHeight(const struct pam * const inpam  /* array */,
+                        unsigned int       const operandCt) {
+    unsigned int i;
+
+    for (i = 1; i < operandCt; ++i) {
+
+        if (i > 0) {
+            if (inpam[i].width  != inpam[0].width ||
+                inpam[i].height != inpam[0].height) {
+                pm_error("The images must be the same width and height.  "
+                         "The first is %ux%ux%u, but another is %ux%ux%u",
+                         inpam[0].width, inpam[0].height, inpam[0].depth,
+                         inpam[i].width, inpam[i].height, inpam[i].depth);
+            }
+        }
+    }
+}
+
+
+
+static void
+validateCompatibleDepth(const struct pam * const inpam  /* array */,
+                        unsigned int       const operandCt) {
+
+    unsigned int i;
+    bool         haveNonUnityDepth;
+    unsigned int nonUnityDepth;
+
+    for (i = 0, haveNonUnityDepth = false; i < operandCt; ++i) {
+        if (inpam[i].depth != 1) {
+            if (haveNonUnityDepth) {
+                if (inpam[i].depth != nonUnityDepth)
+                    pm_error("The images must have the same depth "
+                             "or depth 1.  "
+                             "But one has depth %u and another %u",
+                             nonUnityDepth, inpam[i].depth);
+            } else {
+                haveNonUnityDepth = true;
+                nonUnityDepth = inpam[i].depth;
+            }
+        }
+    }
+}
+
+
+
+static void
+validateConsistentDimensions(const struct pam * const inpam  /* array */,
+                             unsigned int       const operandCt) {
+
+    validateSameWidthHeight(inpam, operandCt);
+
+    validateCompatibleDepth(inpam, operandCt);
+}
+
+
+
 static enum category
-functionCategory(enum function const function) {
+functionCategory(enum Function const function) {
 
     enum category retval;
-    
+
     switch (function) {
     case FN_ADD:
     case FN_SUBTRACT:
@@ -191,6 +275,7 @@ functionCategory(enum function const function) {
     case FN_MINIMUM:
     case FN_MAXIMUM:
     case FN_MEAN:
+    case FN_EQUAL:
     case FN_COMPARE:
     case FN_MULTIPLY:
     case FN_DIVIDE:
@@ -237,58 +322,147 @@ outFmtForCompare(int const format1,
 
 
 
+static unsigned int
+maxDepth(const struct pam * const pam,
+         unsigned int       const pamCt) {
+
+    unsigned int maxDepthSoFar;
+    unsigned int i;
+
+    assert(pamCt >= 1);
+
+    maxDepthSoFar = pam[0].depth;
+    for (i = 1; i < pamCt; ++i) {
+        if (pam[i].depth > maxDepthSoFar)
+            maxDepthSoFar = pam[i].depth;
+    }
+    return maxDepthSoFar;
+}
+
+
+
+static int
+maxFormat(const struct pam * const pam,
+          unsigned int       const pamCt) {
+
+    int maxFormatSoFar;
+    unsigned int i;
+
+    assert(pamCt >= 1);
+
+    maxFormatSoFar = pam[0].format;
+    for (i = 1; i < pamCt; ++i) {
+        if (pam[i].format > maxFormatSoFar)
+            maxFormatSoFar = pam[i].format;
+    }
+    return maxFormatSoFar;
+}
+
+
+
+static sample
+maxMaxval(const struct pam * const pam,
+          unsigned int       const pamCt) {
+
+    sample maxMaxvalSoFar;
+    unsigned int i;
+
+    assert(pamCt >= 1);
+
+    maxMaxvalSoFar = pam[0].maxval;
+    for (i = 1; i < pamCt; ++i) {
+        if (pam[i].maxval > maxMaxvalSoFar)
+            maxMaxvalSoFar = pam[i].maxval;
+    }
+    return maxMaxvalSoFar;
+}
+
+
+
+static bool
+maxvalsAreEqual(const struct pam * const pam,
+                unsigned int       const pamCt) {
+
+    bool equalSoFar;
+    unsigned int i;
+
+    assert(pamCt >= 1);
+
+    equalSoFar = true;
+
+    for (i = 1; i < pamCt; ++i) {
+        if (pam[i].maxval != pam[0].maxval)
+            equalSoFar = false;
+    }
+    return equalSoFar;
+}
+
+
+
 static void
-computeOutputType(struct pam *  const outpamP,
-                  struct pam    const inpam1,
-                  struct pam    const inpam2,
-                  enum function const function) {
+computeOutputType(struct pam *       const outpamP,
+                  const struct pam * const inpam,   /* array */
+                  unsigned int       const operandCt,
+                  enum Function      const function) {
+
+    assert(operandCt >= 1);
 
     outpamP->size        = sizeof(struct pam);
     outpamP->len         = PAM_STRUCT_SIZE(tuple_type);
     outpamP->file        = stdout;
     outpamP->plainformat = FALSE;
-    outpamP->height      = inpam1.height;
-    outpamP->width       = inpam1.width;
-    outpamP->depth       = MAX(inpam1.depth, inpam2.depth);
+    outpamP->height      = inpam[0].height;
+    outpamP->width       = inpam[0].width;
+    outpamP->depth       = maxDepth(inpam, operandCt);
 
-    if (function == FN_COMPARE)
-        outpamP->format = outFmtForCompare(inpam1.format, inpam2.format);
-    else
-        outpamP->format = MAX(inpam1.format, inpam2.format);
+
+    if (function == FN_COMPARE) {
+        assert(operandCt == 2);
+        outpamP->format = outFmtForCompare(inpam[0].format, inpam[1].format);
+    } else
+        outpamP->format = maxFormat(inpam, operandCt);
 
     switch (functionCategory(function)) {
     case CATEGORY_FRACTIONAL_ARITH:
         if (function == FN_COMPARE)
             outpamP->maxval = 2;
+        else if (function == FN_EQUAL)
+            outpamP->maxval = 1;
         else
-            outpamP->maxval = MAX(inpam1.maxval, inpam2.maxval);
+            outpamP->maxval = maxMaxval(inpam, operandCt);
         break;
     case CATEGORY_BITSTRING:
-        if (inpam2.maxval != inpam1.maxval)
+        if (!maxvalsAreEqual(inpam, operandCt))
             pm_error("For a bit string operation, the maxvals of the "
-                     "left and right image must be the same.  You have "
-                     "left=%u and right=%u", 
-                     (unsigned)inpam1.maxval, (unsigned)inpam2.maxval);
+                     "operand images must be the same.  Yours differ");
 
-        if (pm_bitstomaxval(pm_maxvaltobits(inpam1.maxval)) != inpam1.maxval)
+        if (pm_bitstomaxval(pm_maxvaltobits(inpam[0].maxval)) !=
+            inpam[0].maxval)
             pm_error("For a bit string operation, the maxvals of the inputs "
                      "must be a full binary count, i.e. a power of two "
                      "minus one such as 0xff.  You have 0x%x",
-                     (unsigned)inpam1.maxval);
+                     (unsigned)inpam[0].maxval);
 
-        outpamP->maxval = inpam1.maxval;
+        outpamP->maxval = inpam[0].maxval;
         break;
     case CATEGORY_SHIFT:
-        if (pm_bitstomaxval(pm_maxvaltobits(inpam1.maxval)) != inpam1.maxval)
+        if (pm_bitstomaxval(pm_maxvaltobits(inpam[0].maxval)) !=
+            inpam[0].maxval)
             pm_error("For a bit shift operation, the maxval of the left "
                      "input image "
                      "must be a full binary count, i.e. a power of two "
                      "minus one such as 0xff.  You have 0x%x",
-                     (unsigned)inpam1.maxval);
-        outpamP->maxval = inpam1.maxval;
+                     (unsigned)inpam[0].maxval);
+        outpamP->maxval = inpam[0].maxval;
     }
     outpamP->bytes_per_sample = (pm_maxvaltobits(outpamP->maxval)+7)/8;
-    strcpy(outpamP->tuple_type, inpam1.tuple_type);
+
+    if (outpamP->maxval > 1 &&
+        strneq(inpam[0].tuple_type, "BLACKANDWHITE", 13)) {
+
+        strcpy(outpamP->tuple_type, "");
+    } else
+        strcpy(outpamP->tuple_type, inpam[0].tuple_type);
 }
 
 
@@ -311,6 +485,21 @@ samplenSum(samplen      const operands[],
 
 
 static samplen
+samplenProduct(samplen      const operands[],
+               unsigned int const operandCt) {
+
+    unsigned int i;
+    double product;
+
+    for (i = 1, product = operands[0]; i < operandCt; ++i)
+        product *= operands[i];
+
+    return product;
+}
+
+
+
+static samplen
 samplenMin(samplen      const operands[],
            unsigned int const operandCt) {
 
@@ -358,24 +547,28 @@ samplenMean(samplen      const operands[],
 
 
 static samplen
-samplenProduct(samplen      const operands[],
-               unsigned int const operandCt) {
+samplenEqual(samplen      const operands[],
+             unsigned int const operandCt,
+             double       const closeness) {
 
     unsigned int i;
-    double product;
+    bool allEqual;
 
-    for (i = 1, product = operands[0]; i < operandCt; ++i)
-        product *= operands[i];
+    for (i = 1, allEqual = true; i < operandCt; ++i) {
+        if (fabs(operands[i]- operands[0]) > closeness)
+            allEqual = false;
+    }
 
-    return product;
+    return allEqual ? 1.0 : 0.0;
 }
 
 
 
 static samplen
-applyNormalizedFunction(enum function const function,
+applyNormalizedFunction(enum Function const function,
                         samplen       const operands[],
-                        unsigned int  const operandCt) {
+                        unsigned int  const operandCt,
+                        double        const closeness) {
 
     samplen result;
 
@@ -394,7 +587,7 @@ applyNormalizedFunction(enum function const function,
         operands[0] / operands[1] : 1.;
         break;
     case FN_DIFFERENCE:
-        result = operands[0] > operands[1] ? 
+        result = operands[0] > operands[1] ?
             operands[0] - operands[1] : operands[1] - operands[0];
         break;
     case FN_MINIMUM:
@@ -406,8 +599,11 @@ applyNormalizedFunction(enum function const function,
     case FN_MEAN:
         result = samplenMean(operands, operandCt);
         break;
+    case FN_EQUAL:
+        result = samplenEqual(operands, operandCt, closeness);
+        break;
     case FN_COMPARE:
-        result = 
+        result =
             operands[0] > operands[1] ?
             1. : operands[0] < operands[1] ?
             0. : .5;
@@ -423,16 +619,11 @@ applyNormalizedFunction(enum function const function,
 
 
 static void
-doNormalizedArith(struct pam *  const inpam1P,
-                  struct pam *  const inpam2P,
-                  struct pam *  const outpamP,
-                  enum function const function) {
-
-    /* Some of the logic in this subroutine is designed for future
-       expansion into non-dyadic computations.  But for now, all
-       computations have exactly two operands.
-    */
-    unsigned int const operandCt = 2;
+doNormalizedArith(const struct pam * const inpam,  /* array */
+                  unsigned int       const operandCt,
+                  const struct pam * const outpamP,
+                  enum Function      const function,
+                  double             const closeness) {
 
     tuplen ** tuplerown;
         /* tuplerown[0] is the current row in the first operand image */
@@ -444,38 +635,43 @@ doNormalizedArith(struct pam *  const inpam1P,
            computation
         */
     unsigned int * plane;
-        /* plane[0] is the plane number in the first operand image for 
+        /* plane[0] is the plane number in the first operand image for
            the current one-sample computation.  plane[1] is the plane number
            in the second operand image, etc.
          */
+    unsigned int i;
 
     MALLOCARRAY_NOFAIL(operands, operandCt);
     MALLOCARRAY_NOFAIL(plane, operandCt);
     MALLOCARRAY_NOFAIL(tuplerown, operandCt);
 
-    tuplerown[0] = pnm_allocpamrown(inpam1P);
-    tuplerown[1] = pnm_allocpamrown(inpam2P);
+    for (i = 0; i < operandCt; ++i)
+        tuplerown[i] = pnm_allocpamrown(&inpam[i]);
     tuplerownOut = pnm_allocpamrown(outpamP);
 
     for (row = 0; row < outpamP->height; ++row) {
+        unsigned int i;
         unsigned int col;
-        pnm_readpamrown(inpam1P, tuplerown[0]);
-        pnm_readpamrown(inpam2P, tuplerown[1]);
-        
+
+        for (i = 0; i < operandCt; ++i)
+            pnm_readpamrown(&inpam[i], tuplerown[i]);
+
         for (col = 0; col < outpamP->width; ++col) {
             unsigned int outplane;
-            
+
             for (outplane = 0; outplane < outpamP->depth; ++outplane) {
+                unsigned int i;
                 unsigned int op;
 
-                plane[0] = MIN(outplane, inpam1P->depth-1);
-                plane[1] = MIN(outplane, inpam2P->depth-1);
+                for (i = 0; i < operandCt; ++i)
+                    plane[i] = MIN(outplane, inpam[i].depth-1);
 
                 for (op = 0; op < operandCt; ++op)
                     operands[op] = tuplerown[op][col][plane[op]];
 
-                tuplerownOut[col][outplane] = 
-                    applyNormalizedFunction(function, operands, operandCt); 
+                tuplerownOut[col][outplane] =
+                    applyNormalizedFunction(function, operands, operandCt,
+                                            closeness);
                 assert(tuplerownOut[col][outplane] >= 0.);
                 assert(tuplerownOut[col][outplane] <= 1.);
             }
@@ -483,8 +679,8 @@ doNormalizedArith(struct pam *  const inpam1P,
         pnm_writepamrown(outpamP, tuplerownOut);
     }
 
-    pnm_freepamrown(tuplerown[0]);
-    pnm_freepamrown(tuplerown[1]);
+    for (i = 0; i < operandCt; ++i)
+        pnm_freepamrown(tuplerown[i]);
     free(tuplerown);
     pnm_freepamrown(tuplerownOut);
     free(plane);
@@ -512,6 +708,22 @@ sampleSum(sample       const operands[],
 
 
 static sample
+sampleProduct(sample       const operands[],
+              unsigned int const operandCt,
+              sample       const maxval) {
+
+    unsigned int i;
+    double product;
+
+    for (i = 0, product = 1.0; i < operandCt; ++i) {
+        product *= ((double)operands[i]/maxval);
+    }
+    return (sample)(product * maxval + 0.5);
+}
+
+
+
+static sample
 sampleMin(sample       const operands[],
           unsigned int const operandCt) {
 
@@ -561,17 +773,18 @@ sampleMean(sample       const operands[],
 
 
 static sample
-sampleProduct(sample       const operands[],
-              unsigned int const operandCt,
-              sample       const maxval) {
+sampleEqual(sample       const operands[],
+            unsigned int const operandCt,
+            sample       const maxval) {
 
     unsigned int i;
-    double product;
+    bool allEqual;
 
-    for (i = 0, product = 1.0; i < operandCt; ++i) {
-        product *= ((double)operands[i]/maxval);
+    for (i = 1, allEqual = true; i < operandCt; ++i) {
+        if (operands[i] != operands[0])
+            allEqual = false;
     }
-    return (sample)(product * maxval + 0.5);
+    return allEqual ? maxval : 0;
 }
 
 
@@ -654,7 +867,7 @@ sampleXor(sample       const operands[],
 
 
 static sample
-applyUnNormalizedFunction(enum function const function,
+applyUnNormalizedFunction(enum Function const function,
                           sample        const operands[],
                           unsigned int  const operandCt,
                           sample        const maxval) {
@@ -694,6 +907,9 @@ applyUnNormalizedFunction(enum function const function,
     case FN_MEAN:
         result = sampleMean(operands, operandCt);
         break;
+    case FN_EQUAL:
+        result = sampleEqual(operands, operandCt, maxval);
+        break;
     case FN_COMPARE:
         result = operands[0] > operands[1] ?
             2 : operands[0] < operands[1] ? 0 : 1;
@@ -738,21 +954,15 @@ applyUnNormalizedFunction(enum function const function,
 
 
 static void
-doUnNormalizedArith(struct pam *  const inpam1P,
-                    struct pam *  const inpam2P,
-                    struct pam *  const outpamP,
-                    enum function const function) {
+doUnNormalizedArith(const struct pam * const inpam,  /* array */
+                    unsigned int       const operandCt,
+                    const struct pam * const outpamP,
+                    enum Function      const function) {
 /*----------------------------------------------------------------------------
    Take advantage of the fact that both inputs and the output use the same
    maxval to do the computation without time-consuming normalization of
    sample values.
 -----------------------------------------------------------------------------*/
-    /* Some of the logic in this subroutine is designed for future
-       expansion into non-dyadic computations.  But for now, all
-       computations have exactly two operands.
-    */
-    unsigned int const operandCt = 2;
-
     sample const maxval = outpamP->maxval;
 
     tuple ** tuplerow;
@@ -765,42 +975,42 @@ doUnNormalizedArith(struct pam *  const inpam1P,
            computation
         */
     unsigned int * plane;
-        /* plane[0] is the plane number in the first operand image for 
+        /* plane[0] is the plane number in the first operand image for
            the current one-sample computation.  plane[1] is the plane number
            in the second operand image, etc.
          */
-
-    /* Input conditions: */
-    assert(inpam1P->maxval == maxval);
-    assert(inpam2P->maxval == maxval);
-    assert(outpamP->maxval == maxval);
+    unsigned int i;
 
     MALLOCARRAY_NOFAIL(operands, operandCt);
     MALLOCARRAY_NOFAIL(plane, operandCt);
     MALLOCARRAY_NOFAIL(tuplerow, operandCt);
 
-    tuplerow[0]   = pnm_allocpamrow(inpam1P);
-    tuplerow[1]   = pnm_allocpamrow(inpam2P);
+    for (i = 0; i < operandCt; ++i)
+        tuplerow[i]   = pnm_allocpamrow(&inpam[i]);
+
     tuplerowOut = pnm_allocpamrow(outpamP);
 
     for (row = 0; row < outpamP->height; ++row) {
+        unsigned int i;
         unsigned int col;
-        pnm_readpamrow(inpam1P, tuplerow[0]);
-        pnm_readpamrow(inpam2P, tuplerow[1]);
-        
+
+        for (i = 0; i < operandCt; ++i)
+            pnm_readpamrow(&inpam[i], tuplerow[i]);
+
         for (col = 0; col < outpamP->width; ++col) {
             unsigned int outplane;
-            
+
             for (outplane = 0; outplane < outpamP->depth; ++outplane) {
                 unsigned int op;
+                unsigned int i;
 
-                plane[0] = MIN(outplane, inpam1P->depth-1);
-                plane[1] = MIN(outplane, inpam2P->depth-1);
+                for (i = 0; i < operandCt; ++i)
+                    plane[i] = MIN(outplane, inpam[i].depth-1);
 
                 for (op = 0; op < operandCt; ++op)
                     operands[op] = tuplerow[op][col][plane[op]];
 
-                tuplerowOut[col][outplane] = 
+                tuplerowOut[col][outplane] =
                     applyUnNormalizedFunction(function, operands, operandCt,
                                               maxval);
 
@@ -811,8 +1021,8 @@ doUnNormalizedArith(struct pam *  const inpam1P,
         pnm_writepamrow(outpamP, tuplerowOut);
     }
 
-    pnm_freepamrow(tuplerow[0]);
-    pnm_freepamrow(tuplerow[1]);
+    for (i = 0; i < operandCt; ++i)
+        pnm_freepamrow(tuplerow[i]);
     free(tuplerow);
     pnm_freepamrow(tuplerowOut);
     free(plane);
@@ -825,57 +1035,60 @@ int
 main(int argc, const char *argv[]) {
 
     struct CmdlineInfo cmdline;
-    struct pam inpam1;
-    struct pam inpam2;
-    struct pam outpam;
-    FILE * if1P;
-    FILE * if2P;
-    
+    struct pam * inpam;  /* malloc'ed array */
+    FILE **      ifP;    /* malloc'ed array */
+    struct pam   outpam;
+
     pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
-    if (cmdline.operandCt != 2)
-        /* Code for > 2 operands not written yet */
-        pm_error("You specified %u operands.  We understand only 2.",
-                 cmdline.operandCt);
+    MALLOCARRAY(inpam, cmdline.operandCt);
+    MALLOCARRAY(ifP,   cmdline.operandCt);
 
-    if1P = pm_openr(cmdline.operandFileNames[0]);
-    if2P = pm_openr(cmdline.operandFileNames[1]);
-
-    pnm_readpaminit(if1P, &inpam1, PAM_STRUCT_SIZE(tuple_type));
-    pnm_readpaminit(if2P, &inpam2, PAM_STRUCT_SIZE(tuple_type));
+    if (!inpam || !ifP)
+        pm_error("Failed to allocate arrays for %u operands",
+                 cmdline.operandCt);
 
-    if (inpam1.width != inpam2.width || inpam1.height != inpam2.height)
-        pm_error("The two images must be the same width and height.  "
-                 "The first is %ux%ux%u, but the second is %ux%ux%u",
-                 inpam1.width, inpam1.height, inpam1.depth,
-                 inpam2.width, inpam2.height, inpam2.depth);
+    {
+        unsigned int i;
+        for (i = 0; i < cmdline.operandCt; ++i) {
+            ifP[i] = pm_openr(cmdline.operandFileNames[i]);
 
-    if (inpam1.depth != 1 && inpam2.depth != 1 && inpam1.depth != inpam2.depth)
-        pm_error("The two images must have the same depth or one of them "
-                 "must have depth 1.  The first has depth %u and the second "
-                 "has depth %u", inpam1.depth, inpam2.depth);
+            pnm_readpaminit(ifP[i], &inpam[i], PAM_STRUCT_SIZE(tuple_type));
+        }
+    }
+    validateConsistentDimensions(inpam, cmdline.operandCt);
 
-    computeOutputType(&outpam, inpam1, inpam2, cmdline.function);
+    computeOutputType(&outpam, inpam, cmdline.operandCt, cmdline.function);
 
     pnm_writepaminit(&outpam);
 
-    switch (functionCategory(cmdline.function)) {    
+    switch (functionCategory(cmdline.function)) {
     case CATEGORY_FRACTIONAL_ARITH:
-        if (inpam1.maxval == inpam2.maxval && inpam2.maxval == outpam.maxval)
-            doUnNormalizedArith(&inpam1, &inpam2, &outpam, cmdline.function);
+        if (maxvalsAreEqual(inpam, cmdline.operandCt) &&
+            inpam[0].maxval == outpam.maxval)
+            doUnNormalizedArith(inpam, cmdline.operandCt, &outpam,
+                                cmdline.function);
         else
-            doNormalizedArith(&inpam1, &inpam2, &outpam, cmdline.function);
+            doNormalizedArith(inpam, cmdline.operandCt, &outpam,
+                              cmdline.function, cmdline.closeness);
         break;
     case CATEGORY_BITSTRING:
     case CATEGORY_SHIFT:
-        doUnNormalizedArith(&inpam1, &inpam2, &outpam, cmdline.function);
+        doUnNormalizedArith(inpam, cmdline.operandCt, &outpam,
+                            cmdline.function);
         break;
     }
 
-    pm_close(if1P);
-    pm_close(if2P);
-    
+    {
+        unsigned int i;
+        for (i = 0; i < cmdline.operandCt; ++i)
+            pm_close(ifP[i]);
+    }
+
     return 0;
 }
+
+
+
diff --git a/other/pambayer.c b/other/pambayer.c
index 9cffc8f0..599dc11e 100644
--- a/other/pambayer.c
+++ b/other/pambayer.c
@@ -18,7 +18,7 @@
   USA
 
   Copyright Alexandre Becoulet <diaxen AT free DOT fr>
-  
+
   Completely rewritten for Netpbm by Bryan Henderson August 2005.
 */
 
@@ -32,24 +32,24 @@
 #include "nstring.h"
 
 
-enum bayerType {
+enum BayerType {
     BAYER1,
     BAYER2,
     BAYER3,
     BAYER4
 };
 
-struct cmdlineInfo {
-    const char * inputFilespec;
-    enum bayerType bayerType;
-    unsigned int nointerpolate;
+struct CmdlineInfo {
+    const char *   inputFilespec;
+    enum BayerType bayerType;
+    unsigned int   nointerpolate;
 };
 
 
 
 static void
 parseCommandLine(int argc, const char ** argv,
-                 struct cmdlineInfo * const cmdlineP) {
+                 struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that the file spec array we return is stored in the storage that
    was passed to us as the argv array.
@@ -66,10 +66,10 @@ parseCommandLine(int argc, const char ** argv,
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENT3 */
-    OPTENT3(0, "type",     OPT_UINT, &type,
-            &typeSpec, 0);
+    OPTENT3(0, "type",          OPT_UINT, &type,
+            &typeSpec,                      0);
     OPTENT3(0, "nointerpolate", OPT_FLAG, NULL,
-            &cmdlineP->nointerpolate, 0);
+            &cmdlineP->nointerpolate,       0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
@@ -104,47 +104,60 @@ parseCommandLine(int argc, const char ** argv,
 
 static void
 clearTuples(const struct pam * const pamP,
-	    tuple **           const outtuples) {
+            tuple **           const outtuples) {
+/*----------------------------------------------------------------------------
+  Make tuples at the edge that may not get set to anything by the normal
+  computation of the bayer pattern black.
+-----------------------------------------------------------------------------*/
+    if (pamP->height <= 4 || pamP->width <= 4) {
+        unsigned int row;
+
+        for (row = 0; row < pamP->height; ++row) {
+            unsigned int col;
+            for (col = 0; col < pamP->width; ++col) {
+                unsigned int plane;
+                for (plane = 0; plane < pamP->depth; ++plane)
+                    outtuples[row][col][plane] = 0;
+            }
+        }
+    } else {
+        unsigned int col;
+        unsigned int row;
 
-    unsigned int row;
-    unsigned int col;
-    unsigned int plane;
+        for (col = 0; col < pamP->width; ++col) {
+            unsigned int plane;
 
-    if(pamP->height <= 4 || pamP->width <= 4) {
-        for(row=0; row < pamP->height; ++row)
-          for(col=0; col < pamP->width; ++col)
-            for (plane=0; plane < pamP->depth; ++plane)
-              outtuples[row][col][plane] = 0;
-    }
-    else {
-        for(col = 0; col < pamP->width; ++col)
             for (plane = 0; plane < pamP->depth; ++plane) {
                 outtuples[0][col][plane] = 0;
                 outtuples[1][col][plane] = 0;
                 outtuples[pamP->height-2][col][plane] = 0;
                 outtuples[pamP->height-1][col][plane] = 0;
-          }
+            }
 
-        for(row = 2; row < pamP->height - 2; ++row)
-            for (plane = 0; plane < pamP->depth; ++plane) {
-                outtuples[row][0][plane] = 0;
-                outtuples[row][1][plane] = 0;
-                outtuples[row][pamP->width-2][plane] = 0;
-                outtuples[row][pamP->width-1][plane] = 0;
+            for (row = 2; row < pamP->height - 2; ++row) {
+                unsigned int plane;
+
+                for (plane = 0; plane < pamP->depth; ++plane) {
+                    outtuples[row][0][plane] = 0;
+                    outtuples[row][1][plane] = 0;
+                    outtuples[row][pamP->width-2][plane] = 0;
+                    outtuples[row][pamP->width-1][plane] = 0;
+                }
             }
+        }
     }
 }
 
 
 
 static void
-calc_4(const struct pam * const pamP,
-       tuple **           const intuples,
-       tuple **           const outtuples,
-       unsigned int       const plane,
-       bool               const noInterpolation,
-       unsigned int       const xoffset,
-       unsigned int       const yoffset) {
+calc4(const struct pam * const pamP,
+      tuple **           const intuples,
+      tuple **           const outtuples,
+      unsigned int       const plane,
+      bool               const noInterpolation,
+      unsigned int       const xoffset,
+      unsigned int       const yoffset) {
 /*----------------------------------------------------------------------------
     X . X
     . . .
@@ -158,7 +171,7 @@ calc_4(const struct pam * const pamP,
   (even/odd is with respect to ('xoffset', 'yoffset')).
 -----------------------------------------------------------------------------*/
     unsigned int row;
-    
+
     /* Do the even rows -- the even column pixels get copied from the input,
        while the odd column pixels get the mean of adjacent even ones
     */
@@ -177,7 +190,7 @@ calc_4(const struct pam * const pamP,
     for (row = yoffset; row + 2 < pamP->height; row += 2) {
         unsigned int col;
         for (col = xoffset; col < pamP->width; ++col) {
-            outtuples[row + 1][col][plane] = 
+            outtuples[row + 1][col][plane] =
                 noInterpolation ?
                 0 :
                 (outtuples[row][col][plane] +
@@ -189,13 +202,13 @@ calc_4(const struct pam * const pamP,
 
 
 static void
-calc_5(const struct pam * const pamP,
-       tuple **           const intuples,
-       tuple **           const outtuples,
-       unsigned int       const plane,
-       bool               const noInterpolation,
-       unsigned int       const xoffset,
-       unsigned int       const yoffset) {
+calc5(const struct pam * const pamP,
+      tuple **           const intuples,
+      tuple **           const outtuples,
+      unsigned int       const plane,
+      bool               const noInterpolation,
+      unsigned int       const xoffset,
+      unsigned int       const yoffset) {
 /*----------------------------------------------------------------------------
    . X .
    X . X
@@ -231,7 +244,7 @@ calc_5(const struct pam * const pamP,
 
 
 
-struct compAction {
+struct CompAction {
     unsigned int xoffset;
     unsigned int yoffset;
     void (*calc)(const struct pam * const pamP,
@@ -244,54 +257,68 @@ struct compAction {
 };
 
 
+struct BayerPattern {
+
+    struct CompAction compAction[3];
+        /* compAction[n] tells how to compute Plane 'n' */
+};
+
 
-static struct compAction const comp_1[3] = {
+
+static struct BayerPattern const bayer1 = {
 /*----------------------------------------------------------------------------
   G B G B
   R G R G
   G B G B
   R G R G
 -----------------------------------------------------------------------------*/
-
-    { 0, 1, calc_4 },
-    { 0, 1, calc_5 },
-    { 1, 0, calc_4 }
+    {  /* compAction */
+        { 0, 1, calc4 },
+        { 0, 1, calc5 },
+        { 1, 0, calc4 }
+    }
 };
 
-static struct compAction const comp_2[3] = {
+static struct BayerPattern const bayer2 = {
 /*----------------------------------------------------------------------------
   R G R G
   G B G B
   R G R G
   G B G B
 -----------------------------------------------------------------------------*/
-    { 0, 0, calc_4 },
-    { 0, 0, calc_5 },
-    { 1, 1, calc_4 }
+    {  /* compAction */
+        { 0, 0, calc4 },
+        { 0, 0, calc5 },
+        { 1, 1, calc4 }
+    }
 };
 
-static struct compAction const comp_3[3] = {
+static struct BayerPattern const bayer3 = {
 /*----------------------------------------------------------------------------
   B G B G
   G R G R
   B G B G
   G R G R
 -----------------------------------------------------------------------------*/
-    { 1, 1, calc_4 },
-    { 0, 0, calc_5 },
-    { 0, 0, calc_4 }
+    {  /* compAction */
+        { 1, 1, calc4 },
+        { 0, 0, calc5 },
+        { 0, 0, calc4 }
+    }
 };
 
-static struct compAction const comp_4[3] = {
+static struct BayerPattern const bayer4 = {
 /*----------------------------------------------------------------------------
   G R G R
   B G B G
   G R G R
   B G B G
 -----------------------------------------------------------------------------*/
-    { 1, 0, calc_4 },
-    { 0, 1, calc_5 },
-    { 0, 1, calc_4 }
+    {  /* compAction */
+        { 1, 0, calc4 },
+        { 0, 1, calc5 },
+        { 0, 1, calc4 }
+    }
 };
 
 
@@ -315,56 +342,83 @@ makeOutputPam(const struct pam * const inpamP,
 
 
 
-static const struct compAction *
-actionTableForType(enum bayerType const bayerType) {
+struct XyOffset {
+/*----------------------------------------------------------------------------
+   A two-dimensional offset within a matrix.
+-----------------------------------------------------------------------------*/
+    unsigned int row;
+    unsigned int col;
+};
+
+
+
+static const struct CompAction *
+actionTableForType(enum BayerType const bayerType) {
 
-    const struct compAction * retval;
+    const struct CompAction * retval;
 
     switch (bayerType) {
-    case BAYER1: retval = comp_1; break;
-    case BAYER2: retval = comp_2; break;
-    case BAYER3: retval = comp_3; break;
-    case BAYER4: retval = comp_4; break;
+    case BAYER1: retval = bayer1.compAction; break;
+    case BAYER2: retval = bayer2.compAction; break;
+    case BAYER3: retval = bayer3.compAction; break;
+    case BAYER4: retval = bayer4.compAction; break;
     }
     return retval;
 }
 
 
 
-int
+static void
+calcImage(struct pam *   const inpamP,
+          tuple **       const intuples,
+          struct pam *   const outpamP,
+          tuple **       const outtuples,
+          enum BayerType const bayerType,
+          bool           const wantNoInterpolate) {
+
+    const struct CompAction * const compActionTable =
+        actionTableForType(bayerType);
+
+    unsigned int plane;
+
+    clearTuples(outpamP, outtuples);
+
+    for (plane = 0; plane < 3; ++plane) {
+
+        struct CompAction const compAction = compActionTable[plane];
+
+        compAction.calc(inpamP, intuples, outtuples, plane,
+                        wantNoInterpolate,
+                        compAction.xoffset, compAction.yoffset);
+    }
+}
+
+
+            int
 main(int argc, const char **argv) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     FILE * ifP;
     struct pam inpam;
     struct pam outpam;
     tuple ** intuples;
     tuple ** outtuples;
-    const struct compAction * compActionTable;
-    unsigned int plane;
 
     pm_proginit(&argc, argv);
-    
+
     parseCommandLine(argc, argv, &cmdline);
-    
+
     ifP = pm_openr(cmdline.inputFilespec);
-    
-    intuples = pnm_readpam(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
 
-    compActionTable = actionTableForType(cmdline.bayerType);
+    intuples = pnm_readpam(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
 
     makeOutputPam(&inpam, &outpam);
 
     outtuples = pnm_allocpamarray(&outpam);
-    clearTuples(&outpam, outtuples);
 
-    for (plane = 0; plane < 3; ++plane) {
-        struct compAction const compAction = compActionTable[plane];
+    calcImage(&inpam, intuples, &outpam, outtuples,cmdline.bayerType,
+              !!cmdline.nointerpolate);
 
-        compAction.calc(&inpam, intuples, outtuples, plane,
-                        cmdline.nointerpolate,
-                        compAction.xoffset, compAction.yoffset);
-    }
     pnm_writepam(&outpam, outtuples);
 
     pnm_freepamarray(outtuples, &outpam);
@@ -372,3 +426,6 @@ main(int argc, const char **argv) {
 
     return 0;
 }
+
+
+
diff --git a/other/pamdepth.c b/other/pamdepth.c
index 96613d07..46601864 100644
--- a/other/pamdepth.c
+++ b/other/pamdepth.c
@@ -17,7 +17,7 @@
 #include "shhopt.h"
 #include "pam.h"
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -30,7 +30,7 @@ struct cmdlineInfo {
 
 static void
 parseCommandLine(int argc, const char ** argv,
-                 struct cmdlineInfo *cmdlineP) {
+                 struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that the file spec strings we return are stored in the storage that
    was passed to us as the argv array.
@@ -45,7 +45,7 @@ parseCommandLine(int argc, const char ** argv,
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENTRY */
-    OPTENT3(0, "verbose",  OPT_STRING, NULL, 
+    OPTENT3(0, "verbose",  OPT_STRING, NULL,
             &cmdlineP->verbose, 0);
 
     opt.opt_table = option_def;
@@ -64,8 +64,8 @@ parseCommandLine(int argc, const char ** argv,
             pm_error("New maxval must be at least 1.  You specified %d",
                      intval);
         else if (intval > PNM_OVERALLMAXVAL)
-            pm_error("newmaxval (%d) is too large.\n"
-                     "The maximum allowed by the PNM formats is %d.",
+            pm_error("newmaxval (%d) is too large.  "
+                     "The maximum allowed by the PNM formats is %u.",
                      intval, PNM_OVERALLMAXVAL);
         else
             cmdlineP->newMaxval = intval;
@@ -101,7 +101,7 @@ createSampleMap(sample   const oldMaxval,
 static void
 transformRaster(struct pam * const inpamP,
                 struct pam * const outpamP) {
-                
+
     tuple * tuplerow;
     unsigned int row;
     sample * sampleMap;  /* malloc'ed */
@@ -136,7 +136,7 @@ transformRaster(struct pam * const inpamP,
 int
 main(int argc, const char * argv[]) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     FILE * ifP;
     struct pam inpam;
     struct pam outpam;
@@ -153,15 +153,15 @@ main(int argc, const char * argv[]) {
         pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
 
         outpam = inpam;  /* initial value */
-        
+
         outpam.file = stdout;
         outpam.maxval = cmdline.newMaxval;
-        
+
         if (PNM_FORMAT_TYPE(inpam.format) == PBM_TYPE) {
             outpam.format = PGM_TYPE;
         } else
             outpam.format = inpam.format;
-        
+
         if (streq(inpam.tuple_type, PAM_PBM_TUPLETYPE)) {
             pm_message("promoting from black and white to grayscale");
             strcpy(outpam.tuple_type, PAM_PGM_TUPLETYPE);
@@ -182,3 +182,6 @@ main(int argc, const char * argv[]) {
 
     return 0;
 }
+
+
+
diff --git a/other/pamendian.c b/other/pamendian.c
index c24d9629..8826b06f 100644
--- a/other/pamendian.c
+++ b/other/pamendian.c
@@ -1,20 +1,21 @@
-/******************************************************************************
+/*=============================================================================
                               pamendian
-*******************************************************************************
+===============================================================================
 
   Reverse the endianness of multi-byte samples in a Netpbm stream.
   I.e. convert between the true format and the little endian variation of
   it.
-******************************************************************************/
-  
+=============================================================================*/
+
 #include "pam.h"
 
 
 static sample
-reverseSample(sample const insample, unsigned int const bytesPerSample) {
+reverseSample(sample       const insample,
+              unsigned int const bytesPerSample) {
 /*----------------------------------------------------------------------------
   Return a sample whose value is the least significant
-  'bytes_per_sample' bytes, in reverse order.
+  'bytesPerSample' bytes, in reverse order.
 -----------------------------------------------------------------------------*/
     unsigned int bytePos;
     sample shiftedInsample;
@@ -30,14 +31,14 @@ reverseSample(sample const insample, unsigned int const bytesPerSample) {
 
 
 
-int main(int argc, char *argv[]) {
+int main(int argc, const char ** argv) {
 
     struct pam inpam, outpam;
     tuple * intuplerow;
     tuple * outtuplerow;
     unsigned int row;
 
-    pnm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     pnm_readpaminit(stdin, &inpam, PAM_STRUCT_SIZE(tuple_type));
 
@@ -46,27 +47,39 @@ int main(int argc, char *argv[]) {
 
     pnm_writepaminit(&outpam);
 
-    intuplerow = pnm_allocpamrow(&inpam);      
-    outtuplerow = pnm_allocpamrow(&outpam);
-
+    /* We read the samples as if the maxval is 65535 so pnm_readpamrow, which
+       assumes big-endian samples, doesn't choke on a little-endian sample,
+       finding it to exceed the maxval.  (The pure way to do this would be not
+       to use libnetpbm row reading and writing facilities on little-endian
+       pseudo-Netpbm images, but this program isn't important enough to
+       justify that effort).
+    */
     inpam.maxval = 65535;
 
-    for (row = 0; row < inpam.height; row++) {
+    intuplerow  = pnm_allocpamrow(&inpam);
+    outtuplerow = pnm_allocpamrow(&outpam);
+
+    for (row = 0; row < inpam.height; ++row) {
         unsigned int col;
+
         pnm_readpamrow(&inpam, intuplerow);
-        for (col = 0; col < inpam.width; col++) {
+        for (col = 0; col < inpam.width; ++col) {
             unsigned int plane;
-            for (plane = 0; plane < inpam.depth; plane++) 
-                outtuplerow[col][plane] = 
-                    reverseSample(intuplerow[col][plane], 
+
+            for (plane = 0; plane < inpam.depth; ++plane) {
+                outtuplerow[col][plane] =
+                    reverseSample(intuplerow[col][plane],
                                   inpam.bytes_per_sample);
+            }
         }
         pnm_writepamrow(&outpam, outtuplerow);
     }
 
-    pnm_freepamrow(outtuplerow);        
-    pnm_freepamrow(intuplerow);        
+    pnm_freepamrow(outtuplerow);
+    pnm_freepamrow(intuplerow);
 
-    exit(0);
+    return 0;
 }
 
+
+
diff --git a/other/pamexec.c b/other/pamexec.c
index c3a1ee78..cbde81ac 100644
--- a/other/pamexec.c
+++ b/other/pamexec.c
@@ -15,8 +15,11 @@
 #define _BSD_SOURCE 1      /* Make sure strdup() is in string.h */
 #define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
 
+#include <stdbool.h>
 #include <string.h>
 #include <stdio.h>
+#include <signal.h>
+#include <setjmp.h>
 #include <errno.h>
 
 #include "pm_c_util.h"
@@ -25,7 +28,27 @@
 #include "mallocvar.h"
 #include "pam.h"
 
-struct cmdlineInfo {
+
+/* About SIGPIPE:
+
+   Unix has a strange function where by default, if you write into a pipe when
+   the reading side of the pipe has been closed, it generates a signal (of
+   class SIGPIPE), but if you tell the OS to ignore signals of class SIGPIPE,
+   then instead of generating that signal, the system call to write to the
+   pipe just fails.
+
+   Pamexec writes to a pipe when it feeds an image to the user's program's
+   Standard Input.  Should the user's program close its end of the pipe (such
+   as by exiting) before reading the whole image, that would, if we did
+   nothing to deal with it, cause Pamexec to receive a SIGPIPE signal, which
+   would make the OS terminate Pamexec.
+
+   We don't want that, so we tell the OS to ignore SIGPIPE signals, so that
+   instead our attempt to write to the pipe just fails and we fail with a
+   meaningful error message.
+*/
+
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -40,7 +63,7 @@ struct cmdlineInfo {
 
 static void
 parseCommandLine(int argc, const char ** argv,
-                 struct cmdlineInfo * const cmdlineP) {
+                 struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that the pointers we place into *cmdlineP are sometimes to storage
    in the argv array.
@@ -59,13 +82,13 @@ parseCommandLine(int argc, const char ** argv,
     OPTENT3(0,   "check",   OPT_FLAG,   NULL,         &cmdlineP->check, 0);
 
     opt.opt_table = option_def;
-    opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */
-    opt.allowNegNum = FALSE;   /* We have no parms that are negative numbers */
+    opt.short_allowed = false; /* We have no short (old-fashioned) options */
+    opt.allowNegNum = false;   /* We have no parms that are negative numbers */
 
     pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
-    if (argc-1 < 1) 
+    if (argc-1 < 1)
         pm_error("You must specify at least one argument: the shell command "
                  "to execute");
     else {
@@ -92,7 +115,7 @@ pipeOneImage(FILE * const infileP,
     struct pam inpam;
     struct pam outpam;
     enum pm_check_code checkRetval;
-    
+
     unsigned int row;
     tuple * tuplerow;
 
@@ -107,9 +130,25 @@ pipeOneImage(FILE * const infileP,
 
     tuplerow = pnm_allocpamrow(&inpam);
 
-    for (row = 0; row < inpam.height; ++row) {
-        pnm_readpamrow(&inpam, tuplerow);
-        pnm_writepamrow(&outpam, tuplerow);
+    {
+        jmp_buf jmpbuf;
+        int rc;
+        rc = setjmp(jmpbuf);
+        if (rc == 0) {
+            pm_setjmpbuf(&jmpbuf);
+
+            for (row = 0; row < inpam.height; ++row) {
+                pnm_readpamrow(&inpam, tuplerow);
+                pnm_writepamrow(&outpam, tuplerow);
+            }
+        } else {
+            pm_setjmpbuf(NULL);
+            pm_error("Failed to read image and pipe it to program's "
+                     "Standard Input.  If previous messages indicate "
+                     "a broken pipe error, that means the program closed "
+                     "its Standard Error (possibly by exiting) before "
+                     "it had read the entire image>");
+        }
     }
 
     pnm_freepamrow(tuplerow);
@@ -133,7 +172,7 @@ doOneImage(FILE *        const ifP,
     ofP = popen(command, "w");
 
     if (ofP == NULL)
-        pm_asprintf(errorP, 
+        pm_asprintf(errorP,
                     "Failed to start shell to run command '%s'.  "
                     "errno = %d (%s)",
                     command, errno, strerror(errno));
@@ -141,7 +180,7 @@ doOneImage(FILE *        const ifP,
         int rc;
 
         pipeOneImage(ifP, ofP);
-            
+
         rc = pclose(ofP);
 
         if (check && rc != 0)
@@ -157,7 +196,7 @@ doOneImage(FILE *        const ifP,
 int
 main(int argc, const char *argv[]) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
 
     FILE *       ifP;         /* Input file pointer */
     int          eof;         /* No more images in input */
@@ -169,12 +208,17 @@ main(int argc, const char *argv[]) {
     pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
-    
+
+    /* Make write to closed pipe fail rather than generate a signal.
+       See comments at top of program.
+    */
+    signal(SIGPIPE, SIG_IGN);
+
     ifP = pm_openr(cmdline.inputFileName);
 
-    for (eof = FALSE, imageSeq = 0; !eof; ++imageSeq) {
+    for (eof = false, imageSeq = 0; !eof; ++imageSeq) {
         const char * error;
-        
+
         doOneImage(ifP, cmdline.command, cmdline.check, &error);
 
         if (error) {
@@ -185,9 +229,8 @@ main(int argc, const char *argv[]) {
         pnm_nextimage(ifP, &eof);
     }
     pm_close(ifP);
-    
+
     return 0;
 }
 
 
-
diff --git a/other/pamfix.c b/other/pamfix.c
index e40f51f4..4f4eedfc 100644
--- a/other/pamfix.c
+++ b/other/pamfix.c
@@ -109,7 +109,7 @@ analyzeRaster(const struct pam * const pamP,
               bool               const verbose) {
 /*----------------------------------------------------------------------------
    Go through the raster at which the stream described by *tweakedPamP is
-   presently positioned and count how many rows can be successfully read
+   currently positioned and count how many rows can be successfully read
    (including validating the samples against pamP->maxval) and determine the
    highest sample value in those rows.
 
diff --git a/other/pamunlookup.c b/other/pamunlookup.c
index 77c2807b..defa7b1f 100644
--- a/other/pamunlookup.c
+++ b/other/pamunlookup.c
@@ -19,7 +19,6 @@
 #include "pm_c_util.h"
 #include "mallocvar.h"
 #include "shhopt.h"
-#include "pm_system.h"
 #include "nstring.h"
 #include "pam.h"
 #include "pammap.h"
@@ -49,13 +48,13 @@ parseCommandLine(int argc, const char ** const argv,
     optStruct3 opt;
 
     unsigned int option_def_index;
-    
+
     unsigned int lookupfileSpec;
 
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENTRY */
-    OPTENT3(0, "lookupfile",     OPT_STRING, &cmdlineP->lookupfile,  
+    OPTENT3(0, "lookupfile",     OPT_STRING, &cmdlineP->lookupfile,
             &lookupfileSpec, 0);
 
     opt.opt_table = option_def;
@@ -74,17 +73,17 @@ parseCommandLine(int argc, const char ** const argv,
         cmdlineP->inputFileName = argv[1];
 
     free(option_def);
-}        
+}
 
 
 
 static void
-getLookup(const char * const lookupFileName, 
+getLookup(const char * const lookupFileName,
           tuple ***    const lookupP,
           struct pam * const lookuppamP) {
 /*----------------------------------------------------------------------------
    Get the lookup image (the one that maps integers to tuples, e.g. a
-   color index / color map / palette) from the file named 
+   color index / color map / palette) from the file named
    'lookupFileName'.
 
    Return the image as *lookupP and *lookuppamP.
@@ -95,14 +94,14 @@ getLookup(const char * const lookupFileName,
     tuple ** inputLookup;
 
     lookupfileP = pm_openr(lookupFileName);
-    inputLookup = pnm_readpam(lookupfileP, 
+    inputLookup = pnm_readpam(lookupfileP,
                               &inputLookuppam, PAM_STRUCT_SIZE(tuple_type));
 
     pm_close(lookupfileP);
-    
+
     if (inputLookuppam.height != 1)
         pm_error("The lookup table image must be one row.  "
-                 "Yours is %u rows.", 
+                 "Yours is %u rows.",
                  inputLookuppam.height);
 
     *lookupP = inputLookup;
@@ -129,7 +128,7 @@ makeReverseLookupHash(struct pam * const lookuppamP,
 
     for (col = 0; col < lookuppamP->width; ++col) {
         tuple const thisValue = lookup[0][col];
-        
+
         int found;
         int priorValue;
 
@@ -181,7 +180,7 @@ doUnlookup(struct pam * const inpamP,
 
     for (row = 0; row < inpamP->height; ++row) {
         unsigned int col;
-        
+
         pnm_readpamrow(inpamP, inrow);
 
         for (col = 0; col < inpamP->width; ++col) {
@@ -214,7 +213,7 @@ main(int argc, const char ** const argv) {
     tuple ** lookup;
 
     tuplehash lookupHash;
-    
+
     pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
@@ -230,7 +229,7 @@ main(int argc, const char ** const argv) {
                  "has depth %u.  They must be the same",
                  lookuppam.depth, inpam.depth);
     if (!streq(inpam.tuple_type, lookuppam.tuple_type))
-        pm_error("The lookup image has tupel type '%s', "
+        pm_error("The lookup image has tuple type '%s', "
                  "but the input image "
                  "has tuple type '%s'.  They must be the same",
                  lookuppam.tuple_type, inpam.tuple_type);
@@ -243,7 +242,7 @@ main(int argc, const char ** const argv) {
 
     pnm_destroytuplehash(lookupHash);
     pnm_freepamarray(lookup, &lookuppam);
-    
+
     return 0;
 }
 
diff --git a/other/pamx/Makefile b/other/pamx/Makefile
index e4892540..7fe7b9db 100644
--- a/other/pamx/Makefile
+++ b/other/pamx/Makefile
@@ -9,7 +9,10 @@ include $(BUILDDIR)/config.mk
 
 EXTERN_INCLUDE =
 
-ifeq ($(shell $(PKG_CONFIG) x11 --modversion --silence-errors),)
+TEST_PKGCONFIG_X11 := \
+  if $(PKG_CONFIG) x11 --exists; then echo exists; fi
+
+ifeq ($(shell $(TEST_PKGCONFIG_X11)),)
   # Pkg-config has never heard of X11, or doesn't even exist
 
   ifneq ($(X11LIB),NONE)
@@ -46,7 +49,8 @@ all: $(BINARIES)
 
 include $(SRCDIR)/common.mk
 
-ifeq ($(shell $(PKG_CONFIG) x11 --libs),)
+ifeq ($(shell $(TEST_PKGCONFIG_X11)),)
+  # Pkg-config has never heard of X11, or doesn't even exist
   X11_LIBOPTS = $(shell $(LIBOPT) $(LIBOPTR) $(X11LIB))
 else
   X11_LIBOPTS = $(shell $(PKG_CONFIG) x11 --libs)
diff --git a/other/pamx/window.c b/other/pamx/window.c
index d44008c9..61089ea5 100644
--- a/other/pamx/window.c
+++ b/other/pamx/window.c
@@ -1,8 +1,8 @@
 /*
    Functions to allocate and deallocate structures and structure data
- 
+
    By Jim Frost 1989.10.03, Bryan Henderson 2006.03.25.
- 
+
    See COPYRIGHT file for copyright information.
 */
 
@@ -80,10 +80,10 @@ static void
 setDeleteWindow(viewer * const viewerP) {
 
     Atom const protoAtom = XInternAtom(viewerP->dispP, "WM_PROTOCOLS", False);
-    
+
     viewerP->deleteAtom = XInternAtom(viewerP->dispP,
                                       "WM_DELETE_WINDOW", False);
-    
+
     if ((protoAtom != None) && (viewerP->deleteAtom != None))
         XChangeProperty(viewerP->dispP, viewerP->viewportWin,
                         protoAtom, XA_ATOM, 32, PropModeReplace,
@@ -139,7 +139,7 @@ createViewer(viewer **     const viewerPP,
              bool          const fullscreen) {
 
     viewer * viewerP;
-    
+
     XSetWindowAttributes  swa_view;
 
     MALLOCVAR_NOFAIL(viewerP);
@@ -164,7 +164,7 @@ createViewer(viewer **     const viewerPP,
         ButtonPressMask | Button1MotionMask | KeyPressMask |
         StructureNotifyMask | EnterWindowMask | LeaveWindowMask;
     swa_view.save_under       = FALSE;
-    
+
     viewerP->viewportWin =
         XCreateWindow(dispP, RootWindow(dispP, scrn),
                       viewerP->xpos, viewerP->ypos,
@@ -176,7 +176,7 @@ createViewer(viewer **     const viewerPP,
                       &swa_view);
 
     setXloadimageClassHint(viewerP->dispP, viewerP->viewportWin);
-    
+
     setDeleteWindow(viewerP);
 
     viewerP->blank = TRUE;
@@ -192,7 +192,7 @@ determineRepaintStrategy(viewer  *    const viewerP,
                          bool         const verbose,
                          XImageInfo * const ximageinfoP,
                          Pixmap *     const pixmapP) {
-                        
+
     /* Decide how we're going to handle repaints.  We have three modes:
        use backing-store, use background pixmap, and use exposures.
        If the server allows backing-store, we enable it and use it.
@@ -200,7 +200,7 @@ determineRepaintStrategy(viewer  *    const viewerP,
        server does not have backing-store, we try to send the image to
        a pixmap and use that as backing-store.  If that fails, we use
        exposures to blit the image (which is ugly but it works).
-       
+
        'use_pixmap' forces background pixmap mode, which may improve
        performance.
     */
@@ -303,7 +303,7 @@ createImageWindow(viewer *      const viewerP,
 
 static void
 destroyImageWindow(viewer * const viewerP) {
-    
+
     if (viewerP->imageWin) {
         if (viewerP->imageColormap &&
             (viewerP->imageColormap != DefaultColormap(viewerP->dispP, viewerP->scrn)))
@@ -311,7 +311,7 @@ destroyImageWindow(viewer * const viewerP) {
         XDestroyWindow(viewerP->dispP, viewerP->imageWin);
     }
 }
-                       
+
 
 
 static void
@@ -348,12 +348,32 @@ placeImage(viewer * const viewerP,
            int      const height,
            int *    const rxP,     /* input and output */
            int *    const ryP) {   /* input and output */
+/*----------------------------------------------------------------------------
+   Move the X window of *viewerP on the right place on the display to contain
+   an image whose dimensions are 'width' by 'height'.
+
+   As input *rxP and *ryP are the current location of the window (offset from
+   the top left corner of the display of the top left corner of the window).
+   We update them with the new location.
+
+   If the image is narrower than the display, center it.
+
+   Otherwise, either left-justify it or right-justify it depending upon the
+   current position of the window:
+
+      If in the current position, the right edge of the image is within the
+      display, right-justify.
 
+      Otherwise left-justify.
+
+
+   Do the analogous thing for vertical placement.
+-----------------------------------------------------------------------------*/
     int pixx, pixy;
-    
+
     pixx = *rxP;
     pixy = *ryP;
-    
+
     if (viewerP->width > width)
         pixx = (viewerP->width - width) / 2;
     else {
@@ -434,10 +454,10 @@ destroyViewer(viewer * const viewerP) {
     if (viewerP->imageWin)
         XDestroyWindow(viewerP->dispP, viewerP->imageWin);
     viewerP->imageWin = 0;
-    
+
     if (viewerP->viewportWin)
         XDestroyWindow(viewerP->dispP, viewerP->viewportWin);
-    
+
     viewerP->viewportWin = 0;
 
     XFreeCursor(viewerP->dispP, viewerP->cursor);
@@ -459,12 +479,12 @@ setViewportColormap(viewer *  const viewerP,
 
     if (cmap_atom == None)
         cmap_atom = XInternAtom(viewerP->dispP, "WM_COLORMAP_WINDOWS", False);
-    
+
     /* If the visual we're using is the same as the default visual (used by
        the viewport window) then we can set the viewport window to use the
        image's colormap.  This keeps most window managers happy.
     */
-    
+
     if (visualP == DefaultVisual(viewerP->dispP, viewerP->scrn)) {
         swa.colormap = viewerP->imageColormap;
         XChangeWindowAttributes(viewerP->dispP, viewerP->viewportWin,
@@ -507,11 +527,11 @@ iconName(const char * const s) {
         t = strchr(buf, ' ');
         if (t)
             *t = '\0';
-    
+
         /* Strip off leading path.  if you don't use unix-style paths,
            You might want to change this.
         */
-    
+
         t= strrchr(buf, '/');
         if (t) {
             char * p;
@@ -557,7 +577,7 @@ visualClassFromName(const char * const name) {
     unsigned int a;
     int class;
     bool found;
-    
+
     for (a = 0, found = FALSE; VisualClassName[a].name; ++a) {
         if (strcaseeq(VisualClassName[a].name, name)) {
             /* Check for uniqueness.  We special-case StaticGray
@@ -674,10 +694,10 @@ bestVisual(Display *      const disp,
         pm_message("bestVisual: didn't find any depths?!?");
         depth = DefaultDepth(disp, scrn);
     }
-    
+
     /* given this depth, find the best possible visual
      */
-    
+
     default_visualP = DefaultVisual(disp, scrn);
     switch (imageP->type) {
     case ITRUE: {
@@ -697,7 +717,7 @@ bestVisual(Display *      const disp,
                 visualP = bestVisualOfClassAndDepth(disp, scrn, TrueColor,
                                                     depth);
         }
-        
+
         if (!visualP || ((depth <= 8) &&
                          bestVisualOfClassAndDepth(disp, scrn, PseudoColor,
                                                    depth)))
@@ -711,7 +731,7 @@ bestVisual(Display *      const disp,
         if (!visualP)
             visualP = bestVisualOfClassAndDepth(disp, scrn, StaticGray, depth);
     } break;
-        
+
     case IRGB: {
         /* if it's an RGB image, we want PseudoColor if we can get it */
 
@@ -814,7 +834,7 @@ getImageDispDimensions(viewer *       const viewerP,
         *widthP  = viewerP->width;
         *heightP = viewerP->height;
     } else {
-        unsigned int const displayWidth = 
+        unsigned int const displayWidth =
             DisplayWidth(viewerP->dispP, viewerP->scrn);
         unsigned int const displayHeight =
             DisplayHeight(viewerP->dispP, viewerP->scrn);
@@ -878,9 +898,9 @@ getVisualAndDepth(Image *        const imageP,
 static void
 setNormalSizeHints(viewer *     const viewerP,
                    Image *      const imageP) {
-    
+
     XSizeHints sh;
-    
+
     sh.width  = viewerP->width;
     sh.height = viewerP->height;
     if (viewerP->fullscreen) {
@@ -984,7 +1004,7 @@ run(viewer *     const viewerP,
             KeySym ks;
             XComposeStatus status;
             Status rc;
-            
+
             rc = XLookupString(&event.key, buf, 128, &ks, &status);
             if (rc == 1) {
                 char const ret = buf[0];
@@ -1093,7 +1113,7 @@ static void
 resizeViewer(viewer *     const viewerP,
              unsigned int const newWidth,
              unsigned int const newHeight) {
-    
+
     if (viewerP->width != newWidth || viewerP->height != newHeight) {
         XResizeWindow(viewerP->dispP, viewerP->viewportWin,
                       newWidth, newHeight);
@@ -1116,7 +1136,7 @@ displayInViewer(viewer *       const viewerP,
                 const char *   const title,
                 bool           const verbose,
                 int *          const retvalP) {
-    
+
     XImageInfo *     ximageInfoP;
     Visual *         visual;
     unsigned int     depth;
@@ -1134,7 +1154,7 @@ displayInViewer(viewer *       const viewerP,
     getVisualAndDepth(imageP, viewerP->dispP, viewerP->scrn,
                       fit, visualSpec, visualClass,
                       &visual, &depth);
-    
+
     if (verbose && (visual != DefaultVisual(viewerP->dispP, viewerP->scrn)))
         pm_message("Using %s visual", nameOfVisualClass(visual->class));
 
@@ -1211,3 +1231,6 @@ displayInViewer(viewer *       const viewerP,
 
     *retvalP = retvalueFromExitReason(exitReason);
 }
+
+
+
diff --git a/other/pnmcolormap.c b/other/pnmcolormap.c
index f687f037..fbe85d4e 100644
--- a/other/pnmcolormap.c
+++ b/other/pnmcolormap.c
@@ -1,7 +1,6 @@
-/******************************************************************************
-                               pnmcolormap.c
-*******************************************************************************
-
+/*=============================================================================
+                               pnmcolormap
+===============================================================================
   Create a colormap file (a PPM image containing one pixel of each of a set
   of colors).  Base the set of colors on an input image.
 
@@ -20,9 +19,8 @@
   copyright notice and this permission notice appear in supporting
   documentation.  This software is provided "as is" without express or
   implied warranty.
-
-******************************************************************************/
-
+=============================================================================*/
+#include <assert.h>
 #include <math.h>
 
 #include "pm_config.h"
@@ -33,39 +31,73 @@
 #include "pam.h"
 #include "pammap.h"
 
-enum methodForLargest {LARGE_NORM, LARGE_LUM};
+enum MethodForLargest {LARGE_NORM, LARGE_LUM};
 
-enum methodForRep {REP_CENTER_BOX, REP_AVERAGE_COLORS, REP_AVERAGE_PIXELS};
+enum MethodForRep {REP_CENTER_BOX, REP_AVERAGE_COLORS, REP_AVERAGE_PIXELS};
+
+enum MethodForSplit {SPLIT_MAX_PIXELS, SPLIT_MAX_COLORS, SPLIT_MAX_SPREAD};
+
+struct Box {
+/*----------------------------------------------------------------------------
+   A box contains an extent of a color frequency table, i.e. the colors
+   with some consecutive index values in the color frequency table.
+-----------------------------------------------------------------------------*/
+    unsigned int startIndex;
+        /* First index in the extent */
+    unsigned int colorCt;
+        /* Size of the extent (Number of colors in it -- at least 1) */
+    unsigned int sum;
+        /* Number of pixels of all colors in the extent */
+    unsigned int maxdim;
+        /* Which dimension has the largest spread.  RGB plane number. */
+        /* Meaningless if box contains only 1 color */
+    sample       spread;
+        /* spread in dimension 'maxdim' */
+        /* Meaningless if box contains only 1 color */
+};
 
-typedef struct box* boxVector;
-struct box {
-    int ind;
-    int colors;
-    int sum;
+struct BoxVector {
+    tupletable2 colorFreqTable;
+        /* The colors and their frequencies (number of pixels in the image of
+           that color), ordered into consecutive boxes, as defined by 'box'.
+        */
+    unsigned int colorDepth;
+        /* Number of planes in the tuples of 'colorFreqTable' */
+    struct Box * box;  /* malloc'ed array */
+        /* An array of boxes that contain consecutive extents of
+           'colorFreqTable'.  The list covers the entire table.
+        */
+    unsigned int boxCt;
+        /* Number of boxes in the above list */
+    unsigned int capacity;
+        /* Number of boxes the array is capable of containing */
 };
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    const char *inputFilespec;  /* Filespec of input file */
+    const char * inputFileNm;  /* Name of input file */
     unsigned int allcolors;  /* boolean: select all colors from the input */
     unsigned int newcolors;
         /* Number of colors argument; meaningless if allcolors true */
-    enum methodForLargest methodForLargest;
+    enum MethodForLargest methodForLargest;
         /* -spreadintensity/-spreadluminosity options */
-    enum methodForRep methodForRep;
+    enum MethodForRep methodForRep;
         /* -center/-meancolor/-meanpixel options */
+    enum MethodForSplit methodForSplit;
+        /* -splitpixelct/-splitcolorct/-splitspread options */
     unsigned int sort;
     unsigned int square;
     unsigned int verbose;
+    unsigned int debug;
 };
 
 
 
 static void
-parseCommandLine (int argc, char ** argv,
-                  struct cmdlineInfo *cmdlineP) {
+parseCommandLine (int argc, const 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.
@@ -85,6 +117,7 @@ parseCommandLine (int argc, char ** argv,
 
     unsigned int spreadbrightness, spreadluminosity;
     unsigned int center, meancolor, meanpixel;
+    unsigned int splitpixelct, splitcolorct, splitspread;
 
     MALLOCARRAY_NOFAIL(option_def, 100);
 
@@ -99,18 +132,26 @@ parseCommandLine (int argc, char ** argv,
             NULL,                       &meancolor,        0);
     OPTENT3(0,   "meanpixel",        OPT_FLAG,
             NULL,                       &meanpixel,        0);
+    OPTENT3(0,   "splitpixelct",     OPT_FLAG,
+            NULL,                       &splitpixelct,     0);
+    OPTENT3(0,   "splitcolorct",     OPT_FLAG,
+            NULL,                       &splitcolorct,     0);
+    OPTENT3(0,   "splitspread",      OPT_FLAG,
+            NULL,                       &splitspread,      0);
     OPTENT3(0, "sort",     OPT_FLAG,   NULL,
             &cmdlineP->sort,       0 );
     OPTENT3(0, "square",   OPT_FLAG,   NULL,
-            &cmdlineP->square,       0 );
+            &cmdlineP->square,     0 );
     OPTENT3(0, "verbose",   OPT_FLAG,   NULL,
-            &cmdlineP->verbose,       0 );
+            &cmdlineP->verbose,    0 );
+    OPTENT3(0, "debug",     OPT_FLAG,   NULL,
+            &cmdlineP->debug,      0 );
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
+    pm_optParseOptions3( &argc, (char **)argv, opt, sizeof(opt), 0 );
         /* Uses and sets argc, argv, and some of *cmdline_p and others. */
 
 
@@ -132,15 +173,24 @@ parseCommandLine (int argc, char ** argv,
     else
         cmdlineP->methodForRep = REP_CENTER_BOX;
 
+    if (splitpixelct)
+        cmdlineP->methodForSplit = SPLIT_MAX_PIXELS;
+    else if (splitcolorct)
+        cmdlineP->methodForSplit = SPLIT_MAX_COLORS;
+    else if (splitspread)
+        cmdlineP->methodForSplit = SPLIT_MAX_SPREAD;
+    else
+        cmdlineP->methodForSplit = SPLIT_MAX_PIXELS;
+
     if (argc-1 > 2)
         pm_error("Program takes at most two arguments: number of colors "
                  "and input file specification.  "
                  "You specified %d arguments.", argc-1);
     else {
         if (argc-1 < 2)
-            cmdlineP->inputFilespec = "-";
+            cmdlineP->inputFileNm = "-";
         else
-            cmdlineP->inputFilespec = argv[2];
+            cmdlineP->inputFileNm = argv[2];
 
         if (argc-1 < 1)
             pm_error("You must specify the number of colors in the "
@@ -185,8 +235,13 @@ compareplane(const void * const arg1,
     const struct tupleint * const * const comparandPP  = arg1;
     const struct tupleint * const * const comparatorPP = arg2;
 
-    return (*comparandPP)->tuple[compareplanePlane] -
-        (*comparatorPP)->tuple[compareplanePlane];
+    sample const comparandSample  = (*comparandPP) ->tuple[compareplanePlane];
+    sample const comparatorSample = (*comparatorPP)->tuple[compareplanePlane];
+
+    return
+        comparandSample < comparatorSample ? -1 :
+        comparandSample > comparatorSample ? 1 :
+        0;
 }
 
 
@@ -196,84 +251,105 @@ static qsort_comparison_fn sumcompare;
 #endif
 
 static int
-sumcompare(const void * const b1, const void * const b2) {
-    return(((boxVector)b2)->sum - ((boxVector)b1)->sum);
+sumcompare(const void * const arg1,
+           const void * const arg2) {
+
+    struct Box * const comparandP  = (struct Box *)arg1;
+    struct Box * const comparatorP = (struct Box *)arg2;
+
+    return
+        comparatorP->sum < comparandP->sum ? -1 :
+        comparatorP->sum > comparandP->sum ? 1 :
+        0;
 }
 
 
 
+#ifndef LITERAL_FN_DEF_MATCH
+static qsort_comparison_fn colcompare;
+#endif
 
-/*
-** Here is the fun part, the median-cut colormap generator.  This is based
-** on Paul Heckbert's paper "Color Image Quantization for Frame Buffer
-** Display", SIGGRAPH '82 Proceedings, page 297.
-*/
+static int
+colcompare(const void * const arg1,
+           const void * const arg2) {
 
-static tupletable2
-newColorMap(unsigned int const newcolors,
-            unsigned int const depth) {
+    struct Box * const comparandP  = (struct Box *)arg1;
+    struct Box * const comparatorP = (struct Box *)arg2;
 
-    tupletable2 colormap;
-    unsigned int i;
-    struct pam pam;
+    return
+        comparatorP->colorCt < comparandP->colorCt ? -1 :
+        comparatorP->colorCt > comparandP->colorCt ? 1 :
+        0;
+}
 
-    pam.depth = depth;
 
-    colormap.table = pnm_alloctupletable(&pam, newcolors);
 
-    for (i = 0; i < newcolors; ++i) {
-        unsigned int plane;
-        for (plane = 0; plane < depth; ++plane)
-            colormap.table[i]->tuple[plane] = 0;
-    }
-    colormap.size = newcolors;
+#ifndef LITERAL_FN_DEF_MATCH
+static qsort_comparison_fn spreadcompare;
+#endif
 
-    return colormap;
+static int
+spreadcompare(const void * const arg1,
+              const void * const arg2) {
+
+    struct Box * const comparandP  = (struct Box *)arg1;
+    struct Box * const comparatorP = (struct Box *)arg2;
+
+    return
+        comparatorP->spread < comparandP->spread ? -1 :
+        comparatorP->spread > comparandP->spread ? 1 :
+        0;
 }
 
 
 
-static boxVector
-newBoxVector(int const colors, int const sum, int const newcolors) {
+static void
+sortBoxes(struct BoxVector *  const boxVectorP,
+          enum MethodForSplit const methodForSplit) {
 
-    boxVector bv;
-    MALLOCARRAY(bv, newcolors);
-    if (bv == NULL)
-        pm_error("out of memory allocating box vector table");
+    qsort_comparison_fn * comparisonFn;
 
-    /* Set up the initial box. */
-    bv[0].ind = 0;
-    bv[0].colors = colors;
-    bv[0].sum = sum;
+    switch (methodForSplit){
+    case SPLIT_MAX_PIXELS: comparisonFn = &sumcompare;    break;
+    case SPLIT_MAX_COLORS: comparisonFn = &colcompare;    break;
+    case SPLIT_MAX_SPREAD: comparisonFn = &spreadcompare; break;
+    }
 
-    return bv;
+    qsort((char*) &boxVectorP->box[0], boxVectorP->boxCt, sizeof(struct Box),
+          comparisonFn);
 }
 
 
 
+/*
+** Here is the fun part, the median-cut colormap generator.  This is based
+** on Paul Heckbert's paper "Color Image Quantization for Frame Buffer
+** Display", SIGGRAPH '82 Proceedings, page 297.
+*/
+
 static void
-findBoxBoundaries(tupletable2  const colorfreqtable,
+findBoxBoundaries(tupletable2  const colorFreqTable,
                   unsigned int const depth,
                   unsigned int const boxStart,
                   unsigned int const boxSize,
                   sample             minval[],
                   sample             maxval[]) {
 /*----------------------------------------------------------------------------
-  Go through the box finding the minimum and maximum of each
-  component - the boundaries of the box.
+  Go through the box finding the minimum and maximum of each component - the
+  boundaries of the box.
 -----------------------------------------------------------------------------*/
     unsigned int plane;
     unsigned int i;
 
     for (plane = 0; plane < depth; ++plane) {
-        minval[plane] = colorfreqtable.table[boxStart]->tuple[plane];
+        minval[plane] = colorFreqTable.table[boxStart]->tuple[plane];
         maxval[plane] = minval[plane];
     }
 
     for (i = 1; i < boxSize; ++i) {
         unsigned int plane;
         for (plane = 0; plane < depth; ++plane) {
-            sample const v = colorfreqtable.table[boxStart + i]->tuple[plane];
+            sample const v = colorFreqTable.table[boxStart + i]->tuple[plane];
             if (v < minval[plane]) minval[plane] = v;
             if (v > maxval[plane]) maxval[plane] = v;
         }
@@ -282,57 +358,161 @@ findBoxBoundaries(tupletable2  const colorfreqtable,
 
 
 
-static unsigned int
-largestByNorm(sample minval[], sample maxval[], unsigned int const depth) {
-
-    unsigned int largestDimension;
+static void
+findPlaneWithLargestSpreadByNorm(sample         const minval[],
+                                 sample         const maxval[],
+                                 unsigned int   const depth,
+                                 unsigned int * const planeP,
+                                 sample *       const spreadP) {
+
+    unsigned int planeWithLargest;
+    sample       largestSpreadSoFar;
     unsigned int plane;
 
-    sample largestSpreadSoFar = 0;
-    largestDimension = 0;
-    for (plane = 0; plane < depth; ++plane) {
+    for (plane = 0, largestSpreadSoFar = 0; plane < depth; ++plane) {
+
         sample const spread = maxval[plane]-minval[plane];
         if (spread > largestSpreadSoFar) {
-            largestDimension = plane;
             largestSpreadSoFar = spread;
+            planeWithLargest   = plane;
         }
     }
-    return largestDimension;
+    *planeP  = planeWithLargest;
+    *spreadP = largestSpreadSoFar;
 }
 
 
 
-static unsigned int
-largestByLuminosity(sample minval[], sample maxval[],
-                    unsigned int const depth) {
+static void
+findPlaneWithLargestSpreadByLuminosity(sample         const minval[],
+                                       sample         const maxval[],
+                                       unsigned int   const depth,
+                                       unsigned int * const planeP,
+                                       sample *       const spreadP) {
 /*----------------------------------------------------------------------------
    This subroutine presumes that the tuple type is either
    BLACKANDWHITE, GRAYSCALE, or RGB (which implies pamP->depth is 1 or 3).
    To save time, we don't actually check it.
 -----------------------------------------------------------------------------*/
-    unsigned int retval;
-
-    if (depth == 1)
-        retval = 0;
-    else {
+    if (depth == 1){
+        *planeP  = 0;
+        *spreadP = 0;
+    } else {
         /* An RGB tuple */
-        unsigned int largestDimension;
+        unsigned int planeWithLargest;
+        sample       largestSpreadSoFar;
         unsigned int plane;
-        double largestSpreadSoFar;
 
-        largestSpreadSoFar = 0.0;
+        assert(depth >= 3);
 
-        for (plane = 0; plane < 3; ++plane) {
+        for (plane = 0, largestSpreadSoFar = 0; plane < 3; ++plane) {
             double const spread =
                 pnm_lumin_factor[plane] * (maxval[plane]-minval[plane]);
             if (spread > largestSpreadSoFar) {
-                largestDimension = plane;
                 largestSpreadSoFar = spread;
+                planeWithLargest   = plane;
             }
         }
-        retval = largestDimension;
+        *planeP  = planeWithLargest;
+        *spreadP = largestSpreadSoFar;
+    }
+}
+
+
+
+static void
+computeBoxSpread(const struct Box *    const boxP,
+                 tupletable2           const colorFreqTable,
+                 unsigned int          const depth,
+                 enum MethodForLargest const methodForLargest,
+                 unsigned int *        const planeWithLargestP,
+                 sample *              const spreadP
+                 ) {
+/*----------------------------------------------------------------------------
+  Find the spread in the dimension in which it is greatest.
+
+  Return as *planeWithLargestP the number of that plane and as *spreadP the
+  spread in that plane.
+-----------------------------------------------------------------------------*/
+    sample * minval;  /* malloc'ed array */
+    sample * maxval;  /* malloc'ed array */
+
+    MALLOCARRAY_NOFAIL(minval, depth);
+    MALLOCARRAY_NOFAIL(maxval, depth);
+
+    findBoxBoundaries(colorFreqTable, depth, boxP->startIndex, boxP->colorCt,
+                      minval, maxval);
+
+    switch (methodForLargest) {
+    case LARGE_NORM:
+        findPlaneWithLargestSpreadByNorm(minval, maxval, depth,
+                                         planeWithLargestP, spreadP);
+        break;
+    case LARGE_LUM:
+        findPlaneWithLargestSpreadByLuminosity(minval, maxval, depth,
+                                               planeWithLargestP, spreadP);
+        break;
     }
-    return retval;
+    free(minval); free(maxval);
+}
+
+
+
+static unsigned int
+freqTotal(tupletable2 const freqTable) {
+
+    unsigned int i;
+    unsigned int sum;
+
+    for (i = 0, sum = 0; i < freqTable.size; ++i)
+        sum += freqTable.table[i]->value;
+
+    return sum;
+}
+
+
+
+static struct BoxVector
+newBoxVector(tupletable2           const colorFreqTable,
+             unsigned int          const capacity,
+             unsigned int          const depth,
+             enum MethodForLargest const methodForLargest) {
+
+    unsigned int const colorCt = colorFreqTable.size;
+    unsigned int const sum     = freqTotal(colorFreqTable);
+
+    struct BoxVector boxVector;
+
+    boxVector.colorFreqTable = colorFreqTable;
+    boxVector.colorDepth     = depth;
+
+    MALLOCARRAY(boxVector.box, capacity);
+
+    if (!boxVector.box)
+        pm_error("out of memory allocating box vector table");
+
+    /* Set up the initial box. */
+    boxVector.box[0].startIndex = 0;
+    boxVector.box[0].colorCt    = colorCt;
+    boxVector.box[0].sum        = sum;
+
+    computeBoxSpread(&boxVector.box[0], colorFreqTable, depth,
+                     methodForLargest,
+                     &boxVector.box[0].maxdim,
+                     &boxVector.box[0].spread);
+
+    boxVector.boxCt    = 1;
+    boxVector.capacity = capacity;
+
+    return boxVector;
+}
+
+
+
+static void
+destroyBoxVector(struct BoxVector const boxVector) {
+
+    free(boxVector.box);
 }
 
 
@@ -340,7 +520,7 @@ largestByLuminosity(sample minval[], sample maxval[],
 static void
 centerBox(int          const boxStart,
           int          const boxSize,
-          tupletable2  const colorfreqtable,
+          tupletable2  const colorFreqTable,
           unsigned int const depth,
           tuple        const newTuple) {
 
@@ -350,10 +530,10 @@ centerBox(int          const boxStart,
         int minval, maxval;
         unsigned int i;
 
-        minval = maxval = colorfreqtable.table[boxStart]->tuple[plane];
+        minval = maxval = colorFreqTable.table[boxStart]->tuple[plane];
 
         for (i = 1; i < boxSize; ++i) {
-            int const v = colorfreqtable.table[boxStart + i]->tuple[plane];
+            int const v = colorFreqTable.table[boxStart + i]->tuple[plane];
             minval = MIN( minval, v);
             maxval = MAX( maxval, v);
         }
@@ -363,10 +543,34 @@ centerBox(int          const boxStart,
 
 
 
+static tupletable2
+newColorMap(unsigned int const colorCt,
+            unsigned int const depth) {
+
+    tupletable2 colormap;
+    unsigned int i;
+    struct pam pam;
+
+    pam.depth = depth;
+
+    colormap.table = pnm_alloctupletable(&pam, colorCt);
+
+    for (i = 0; i < colorCt; ++i) {
+        unsigned int plane;
+        for (plane = 0; plane < depth; ++plane)
+            colormap.table[i]->tuple[plane] = 0;
+    }
+    colormap.size = colorCt;
+
+    return colormap;
+}
+
+
+
 static void
 averageColors(int          const boxStart,
               int          const boxSize,
-              tupletable2  const colorfreqtable,
+              tupletable2  const colorFreqTable,
               unsigned int const depth,
               tuple        const newTuple) {
 
@@ -379,7 +583,7 @@ averageColors(int          const boxStart,
         sum = 0;
 
         for (i = 0; i < boxSize; ++i)
-            sum += colorfreqtable.table[boxStart+i]->tuple[plane];
+            sum += colorFreqTable.table[boxStart+i]->tuple[plane];
 
         newTuple[plane] = ROUNDDIV(sum, boxSize);
     }
@@ -390,7 +594,7 @@ averageColors(int          const boxStart,
 static void
 averagePixels(int          const boxStart,
               int          const boxSize,
-              tupletable2  const colorfreqtable,
+              tupletable2  const colorFreqTable,
               unsigned int const depth,
               tuple        const newTuple) {
 
@@ -402,7 +606,7 @@ averagePixels(int          const boxStart,
     /* Count the tuples in question */
     n = 0;  /* initial value */
     for (i = 0; i < boxSize; ++i)
-        n += colorfreqtable.table[boxStart + i]->value;
+        n += colorFreqTable.table[boxStart + i]->value;
 
 
     for (plane = 0; plane < depth; ++plane) {
@@ -412,8 +616,8 @@ averagePixels(int          const boxStart,
         sum = 0;
 
         for (i = 0; i < boxSize; ++i)
-            sum += colorfreqtable.table[boxStart+i]->tuple[plane]
-                * colorfreqtable.table[boxStart+i]->value;
+            sum += colorFreqTable.table[boxStart+i]->tuple[plane]
+                * colorFreqTable.table[boxStart+i]->value;
 
         newTuple[plane] = ROUNDDIV(sum, n);
     }
@@ -422,12 +626,9 @@ averagePixels(int          const boxStart,
 
 
 static tupletable2
-colormapFromBv(unsigned int      const newcolors,
-               boxVector         const bv,
-               unsigned int      const boxes,
-               tupletable2       const colorfreqtable,
-               unsigned int      const depth,
-               enum methodForRep const methodForRep) {
+colormapFromBv(unsigned int      const colorCt,
+               struct BoxVector  const boxVector,
+               enum MethodForRep const methodForRep) {
     /*
     ** Ok, we've got enough boxes.  Now choose a representative color for
     ** each box.  There are a number of possible ways to make this choice.
@@ -437,23 +638,29 @@ colormapFromBv(unsigned int      const newcolors,
     ** method is to average all the pixels in the box.
     */
     tupletable2 colormap;
-    unsigned int bi;
+    unsigned int boxIdx;
 
-    colormap = newColorMap(newcolors, depth);
+    colormap = newColorMap(colorCt, boxVector.colorDepth);
 
-    for (bi = 0; bi < boxes; ++bi) {
+    for (boxIdx = 0; boxIdx < boxVector.boxCt; ++boxIdx) {
         switch (methodForRep) {
         case REP_CENTER_BOX:
-            centerBox(bv[bi].ind, bv[bi].colors, colorfreqtable, depth,
-                      colormap.table[bi]->tuple);
+            centerBox(boxVector.box[boxIdx].startIndex,
+                      boxVector.box[boxIdx].colorCt,
+                      boxVector.colorFreqTable, boxVector.colorDepth,
+                      colormap.table[boxIdx]->tuple);
             break;
         case REP_AVERAGE_COLORS:
-            averageColors(bv[bi].ind, bv[bi].colors, colorfreqtable, depth,
-                          colormap.table[bi]->tuple);
+            averageColors(boxVector.box[boxIdx].startIndex,
+                          boxVector.box[boxIdx].colorCt,
+                          boxVector.colorFreqTable, boxVector.colorDepth,
+                          colormap.table[boxIdx]->tuple);
             break;
         case REP_AVERAGE_PIXELS:
-            averagePixels(bv[bi].ind, bv[bi].colors, colorfreqtable, depth,
-                          colormap.table[bi]->tuple);
+            averagePixels(boxVector.box[boxIdx].startIndex,
+                          boxVector.box[boxIdx].colorCt,
+                          boxVector.colorFreqTable, boxVector.colorDepth,
+                          colormap.table[boxIdx]->tuple);
             break;
         default:
             pm_error("Internal error: invalid value of methodForRep: %d",
@@ -465,153 +672,170 @@ colormapFromBv(unsigned int      const newcolors,
 
 
 
-static unsigned int
-freqTotal(tupletable2 const freqtable) {
-
-    unsigned int i;
-    unsigned int sum;
-
-    sum = 0;
-
-    for (i = 0; i < freqtable.size; ++i)
-        sum += freqtable.table[i]->value;
-
-    return sum;
-}
-
-
 static void
-splitBox(boxVector             const bv,
-         unsigned int *        const boxesP,
-         unsigned int          const bi,
-         tupletable2           const colorfreqtable,
-         unsigned int          const depth,
-         enum methodForLargest const methodForLargest) {
+splitBox(struct BoxVector *    const boxVectorP,
+         unsigned int          const boxIdx,
+         enum MethodForLargest const methodForLargest,
+         enum MethodForSplit   const methodForSplit) {
 /*----------------------------------------------------------------------------
-   Split Box 'bi' in the box vector bv (so that bv contains one more box
-   than it did as input).  Split it so that each new box represents about
-   half of the pixels in the distribution given by 'colorfreqtable' for
-   the colors in the original box, but with distinct colors in each of the
-   two new boxes.
+   Split Box 'boxIdx' in the box vector 'boxVector' (so that 'boxVector'
+   contains one more box than it did as input).  Split it so that each new box
+   represents about half of the pixels in the image for the colors in the
+   original box, but with distinct colors in each of the two new boxes.
 
    Assume the box contains at least two colors.
 -----------------------------------------------------------------------------*/
-    unsigned int const boxStart = bv[bi].ind;
-    unsigned int const boxSize  = bv[bi].colors;
-    unsigned int const sm       = bv[bi].sum;
-
-    sample * minval;  /* malloc'ed array */
-    sample * maxval;  /* malloc'ed array */
+    unsigned int const boxStart = boxVectorP->box[boxIdx].startIndex;
+    unsigned int const boxSize  = boxVectorP->box[boxIdx].colorCt;
+    unsigned int const sum      = boxVectorP->box[boxIdx].sum;
 
-    unsigned int largestDimension;
-        /* number of the plane with the largest spread */
     unsigned int medianIndex;
-    int lowersum;
+    unsigned int lowerSum;
         /* Number of pixels whose value is "less than" the median */
 
-    MALLOCARRAY_NOFAIL(minval, depth);
-    MALLOCARRAY_NOFAIL(maxval, depth);
-
-    findBoxBoundaries(colorfreqtable, depth, boxStart, boxSize,
-                      minval, maxval);
-
-    /* Find the largest dimension, and sort by that component.  I have
-       included two methods for determining the "largest" dimension;
-       first by simply comparing the range in RGB space, and second by
-       transforming into luminosities before the comparison.
-    */
-    switch (methodForLargest) {
-    case LARGE_NORM:
-        largestDimension = largestByNorm(minval, maxval, depth);
-        break;
-    case LARGE_LUM:
-        largestDimension = largestByLuminosity(minval, maxval, depth);
-        break;
-    }
 
-    /* TODO: I think this sort should go after creating a box,
-       not before splitting.  Because you need the sort to use
-       the REP_CENTER_BOX method of choosing a color to
-       represent the final boxes
+    /* Perhaps this sort should go after creating a box, not before splitting.
+       Because you need the sort to use the REP_CENTER_BOX method of choosing
+       a color to represent the final boxes
     */
 
     /* Set the gross global variable 'compareplanePlane' as a
        parameter to compareplane(), which is called by qsort().
     */
-    compareplanePlane = largestDimension;
-    qsort((char*) &colorfreqtable.table[boxStart], boxSize,
-          sizeof(colorfreqtable.table[boxStart]),
+    compareplanePlane = boxVectorP->box[boxIdx].maxdim;
+    qsort((char*) &boxVectorP->colorFreqTable.table[boxStart], boxSize,
+          sizeof(boxVectorP->colorFreqTable.table[boxStart]),
           compareplane);
 
     {
-        /* Now find the median based on the counts, so that about half
-           the pixels (not colors, pixels) are in each subdivision.  */
-
+        /* Find the median based on the counts, so that about half the pixels
+           (not colors, pixels) are in each subdivision.
+        */
         unsigned int i;
 
-        lowersum = colorfreqtable.table[boxStart]->value; /* initial value */
-        for (i = 1; i < boxSize - 1 && lowersum < sm/2; ++i) {
-            lowersum += colorfreqtable.table[boxStart + i]->value;
+        lowerSum = boxVectorP->colorFreqTable.table[boxStart]->value;
+            /* initial value */
+        for (i = 1; i < boxSize - 1 && lowerSum < sum/2; ++i) {
+            lowerSum += boxVectorP->colorFreqTable.table[boxStart + i]->value;
         }
         medianIndex = i;
     }
     /* Split the box, and sort to bring the biggest boxes to the top.  */
+    {
+        struct Box * const oldBoxP = &boxVectorP->box[boxIdx];
+
+        oldBoxP->colorCt = medianIndex;
+        oldBoxP->sum     = lowerSum;
+        computeBoxSpread(oldBoxP, boxVectorP->colorFreqTable,
+                         boxVectorP->colorDepth, methodForLargest,
+                         &oldBoxP->maxdim, &oldBoxP->spread);
+    }
+    {
+        struct Box * const newBoxP = &boxVectorP->box[boxVectorP->boxCt];
+
+        newBoxP->startIndex = boxStart + medianIndex;
+        newBoxP->colorCt    = boxSize - medianIndex;
+        newBoxP->sum        = sum - lowerSum;
+        computeBoxSpread(newBoxP, boxVectorP->colorFreqTable,
+                         boxVectorP->colorDepth, methodForLargest,
+                         &newBoxP->maxdim, &newBoxP->spread);
+        ++boxVectorP->boxCt;
+    }
 
-    bv[bi].colors = medianIndex;
-    bv[bi].sum = lowersum;
-    bv[*boxesP].ind = boxStart + medianIndex;
-    bv[*boxesP].colors = boxSize - medianIndex;
-    bv[*boxesP].sum = sm - lowersum;
-    ++(*boxesP);
-    qsort((char*) bv, *boxesP, sizeof(struct box), sumcompare);
+    sortBoxes(boxVectorP, methodForSplit);
+}
 
-    free(minval); free(maxval);
+
+
+static void
+reportBoxVector(struct BoxVector const boxVector) {
+
+    unsigned int i;
+
+    pm_message("All colors of image, sorted into %u boxes:", boxVector.boxCt);
+
+    for (i = 0; i < boxVector.boxCt; ++i) {
+        const struct Box * const boxP = &boxVector.box[i];
+
+        unsigned int j;
+
+        pm_message("Box %u, %u colors starting with index %u (%u pixels):",
+                   i, boxP->colorCt, boxP->startIndex, boxP->sum);
+        if (boxP->colorCt > 1)
+            pm_message("Largest spread is %lu, in plane %u",
+                       boxP->spread, boxP->maxdim);
+
+        for (j = 0; j < boxP->colorCt; ++j) {
+            unsigned int colorIdx = boxP->startIndex + j;
+
+            assert(colorIdx < boxVector.colorFreqTable.size);
+
+            tuple const color =
+                boxVector.colorFreqTable.table[colorIdx]->tuple;
+
+            pm_message("(%lu, %lu, %lu)",
+                       color[PAM_RED_PLANE],
+                       color[PAM_GRN_PLANE],
+                       color[PAM_BLU_PLANE]);
+        }
+    }
 }
 
 
 
 static void
-mediancut(tupletable2           const colorfreqtable,
+mediancut(tupletable2           const colorFreqTable,
           unsigned int          const depth,
-          int                   const newcolors,
-          enum methodForLargest const methodForLargest,
-          enum methodForRep     const methodForRep,
+          unsigned int          const newColorCt,
+          enum MethodForLargest const methodForLargest,
+          enum MethodForRep     const methodForRep,
+          enum MethodForSplit   const methodForSplit,
+          bool                  const wantBvReport,
           tupletable2 *         const colormapP) {
 /*----------------------------------------------------------------------------
-   Compute a set of only 'newcolors' colors that best represent an
+   Compute a set of only 'newColorCt' colors that best represent an
    image whose pixels are summarized by the histogram
-   'colorfreqtable'.  Each tuple in that table has depth 'depth'.
-   colorfreqtable.table[i] tells the number of pixels in the subject image
-   have a particular color.
+   'colorFreqTable'.  Each tuple in that table has depth 'depth'.
+   colorFreqTable.table[i] tells the number of pixels in the subject image
+   that have a particular color.
 
-   As a side effect, sort 'colorfreqtable'.
+   As a side effect, sort 'colorFreqTable'.
 -----------------------------------------------------------------------------*/
-    boxVector bv;
-    unsigned int bi;
-    unsigned int boxes;
+    struct BoxVector boxVector;
     bool multicolorBoxesExist;
         /* There is at least one box that contains at least 2 colors; ergo,
            there is more splitting we can do.
         */
 
-    bv = newBoxVector(colorfreqtable.size, freqTotal(colorfreqtable),
-                      newcolors);
-    boxes = 1;
-    multicolorBoxesExist = (colorfreqtable.size > 1);
+    boxVector = newBoxVector(colorFreqTable, newColorCt, depth,
+                             methodForLargest);
 
-    /* Main loop: split boxes until we have enough. */
-    while (boxes < newcolors && multicolorBoxesExist) {
-        /* Find the first splittable box. */
-        for (bi = 0; bi < boxes && bv[bi].colors < 2; ++bi);
-        if (bi >= boxes)
+    multicolorBoxesExist = (colorFreqTable.size > 1);
+
+    /* Split boxes until we have enough. */
+    while (boxVector.boxCt < newColorCt && multicolorBoxesExist) {
+        unsigned int boxIdx;
+
+        for (boxIdx = 0;
+             boxIdx < boxVector.boxCt && boxVector.box[boxIdx].colorCt < 2;
+             ++boxIdx);
+            /* Find the first splittable box. */
+
+        if (boxIdx >= boxVector.boxCt)
             multicolorBoxesExist = FALSE;
         else
-            splitBox(bv, &boxes, bi, colorfreqtable, depth, methodForLargest);
+            splitBox(&boxVector, boxIdx, methodForLargest, methodForSplit);
+                /* Side effect: sorts the extent of 'colorfreqTable' that is
+                   in the box
+                */
     }
-    *colormapP = colormapFromBv(newcolors, bv, boxes, colorfreqtable, depth,
-                                methodForRep);
 
-    free(bv);
+    if (wantBvReport)
+        reportBoxVector(boxVector);
+
+    *colormapP = colormapFromBv(newColorCt, boxVector, methodForRep);
+
+    destroyBoxVector(boxVector);
 }
 
 
@@ -673,7 +897,7 @@ static void
 computeHistogram(FILE *         const ifP,
                  int *          const formatP,
                  struct pam *   const freqPamP,
-                 tupletable2 *  const colorfreqtableP) {
+                 tupletable2 *  const colorFreqTableP) {
 /*----------------------------------------------------------------------------
   Make a histogram of the colors in the image stream in the file '*ifP'.
 
@@ -715,13 +939,13 @@ computeHistogram(FILE *         const ifP,
 
         pnm_nextimage(ifP, &eof);
     }
-    colorfreqtableP->table =
+    colorFreqTableP->table =
         pnm_tuplehashtotable(&firstPam, tuplehash, colorCount);
-    colorfreqtableP->size = colorCount;
+    colorFreqTableP->size = colorCount;
 
     pnm_destroytuplehash(tuplehash);
 
-    pm_message("%u colors found", colorfreqtableP->size);
+    pm_message("%u colors found", colorFreqTableP->size);
 
     freqPamP->size   = sizeof(*freqPamP);
     freqPamP->len    = PAM_STRUCT_SIZE(tuple_type);
@@ -738,9 +962,11 @@ computeHistogram(FILE *         const ifP,
 static void
 computeColorMapFromInput(FILE *                const ifP,
                          bool                  const allColors,
-                         int                   const reqColors,
-                         enum methodForLargest const methodForLargest,
-                         enum methodForRep     const methodForRep,
+                         unsigned int          const reqColors,
+                         enum MethodForLargest const methodForLargest,
+                         enum MethodForRep     const methodForRep,
+                         enum MethodForSplit   const methodForSplit,
+                         bool                  const wantBvReport,
                          int *                 const formatP,
                          struct pam *          const freqPamP,
                          tupletable2 *         const colormapP) {
@@ -763,23 +989,26 @@ computeColorMapFromInput(FILE *                const ifP,
    *formatP and *freqPamP.  (This information is not really
    relevant to our colormap mission; just a fringe benefit).
 -----------------------------------------------------------------------------*/
-    tupletable2 colorfreqtable;
+    tupletable2 colorFreqTable;
+        /* Table of all colors in the image, with the number of pixels of
+           each color.
+        */
 
-    computeHistogram(ifP, formatP, freqPamP, &colorfreqtable);
+    computeHistogram(ifP, formatP, freqPamP, &colorFreqTable);
 
     if (allColors) {
-        *colormapP = colorfreqtable;
+        *colormapP = colorFreqTable;
     } else {
-        if (colorfreqtable.size <= reqColors) {
-            pm_message("Image already has few enough colors (<=%d).  "
+        if (colorFreqTable.size <= reqColors) {
+            pm_message("Image already has few enough colors (<=%u).  "
                        "Keeping same colors.", reqColors);
-            *colormapP = colorfreqtable;
+            *colormapP = colorFreqTable;
         } else {
-            pm_message("choosing %d colors...", reqColors);
-            mediancut(colorfreqtable, freqPamP->depth,
+            pm_message("choosing %u colors...", reqColors);
+            mediancut(colorFreqTable, freqPamP->depth,
                       reqColors, methodForLargest, methodForRep,
-                      colormapP);
-            pnm_freetupletable2(freqPamP, colorfreqtable);
+                      methodForSplit, wantBvReport, colormapP);
+            pnm_freetupletable2(freqPamP, colorFreqTable);
         }
     }
 }
@@ -933,9 +1162,9 @@ colormapToImage(int                const format,
 
 
 int
-main(int argc, char * argv[] ) {
+main(int argc, const char * argv[] ) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     FILE * ifP;
     int format;
     struct pam colormapPam;
@@ -943,16 +1172,18 @@ main(int argc, char * argv[] ) {
     tuple ** colormapRaster;
     tupletable2 colormap;
 
-    pnm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
-    ifP = pm_openr(cmdline.inputFilespec);
+    ifP = pm_openr(cmdline.inputFileNm);
 
     computeColorMapFromInput(ifP,
                              cmdline.allcolors, cmdline.newcolors,
                              cmdline.methodForLargest,
                              cmdline.methodForRep,
+                             cmdline.methodForSplit,
+                             cmdline.debug,
                              &format, &colormapPam, &colormap);
 
     pm_close(ifP);
diff --git a/pm_config.in.h b/pm_config.in.h
index b30bccfe..7ba51454 100644
--- a/pm_config.in.h
+++ b/pm_config.in.h
@@ -167,6 +167,16 @@
 #define lstat stat
 #endif
 
+/* Mingw provides much of POSIX, but does not provide 'random' (and a
+   discussion on the Mingw mailing list in March 2021 shows that the
+   developers want it that way).  MSVCRT itself has a sufficient 'rand',
+   though, so we use that for 'random'.
+*/
+#if MSVCRT
+#define random rand
+#define srandom srand
+#endif
+
 /*  CONFIGURE: Netpbm uses __inline__ to declare functions that should
     be compiled as inline code.  GNU C recognizes the __inline__ keyword.
     If your compiler recognizes any other keyword for this, you can set
diff --git a/test/411toppm.test b/test/411toppm.test
index 98170c67..7a9e533c 100755
--- a/test/411toppm.test
+++ b/test/411toppm.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: 411toppm
 # Also requires:
 
diff --git a/test/Available-Testprog b/test/Available-Testprog
index 8176b57a..033c7eec 100755
--- a/test/Available-Testprog
+++ b/test/Available-Testprog
@@ -6,7 +6,6 @@ if [ "${CHECK_TYPE}" = "install" ]; then
 fi
 
 # Special case: no arguments were passed to this program
-# For all-in-place.test and legacy-names.test
 
 if [ $# = 0 ]; then
   exit 0
@@ -19,6 +18,10 @@ fi
 # each directory (for example converter/other/Makefile) for library
 # requirements and relevant variables.
 
+# Note that any variable used to determine whether a program exists
+# (BUILD_FIASCO, JASPERLIB, JBIGLIB, JPEGLIB, etc.)
+# must be in CHECK_VARS in GNUMakefile to be detected here. 
+
 for i in $@
     do
     case $i in
@@ -57,6 +60,9 @@ for i in $@
       svgtopam)
         [ "${XML2_LIBS}" = "NONE" ] && exit 1 ;;
 
+      ppmsvgalib)
+        [ "${LINUXSVGALIB}" = "NONE" ] && exit 1 ;;
+
       thinkjettopbm)
         [ -z "${LEX}" ] && exit 1 ;;
 
diff --git a/test/Execute-Tests b/test/Execute-Tests
index 7a65d51f..3c231d98 100755
--- a/test/Execute-Tests
+++ b/test/Execute-Tests
@@ -103,6 +103,10 @@ if [ ! -f ./testgrid.pbm ]
   then cp -v ${srcdir}/testgrid.pbm ./testgrid.pbm
 fi
 
+if [ ! -f ./maze.pbm ]
+  then cp -v ${srcdir}/maze.pbm ./maze.pbm
+fi
+
 if [ ! -f ./testimg.ppm ]
   then cp -v ${srcdir}/testimg.ppm  ./testimg.ppm 
 fi
@@ -178,12 +182,15 @@ elif [ $VALGRIND_TESTS = "on" ]
   mkdir $valdir
  
   vg_command_base="valgrind --trace-children=yes";
+  # You may want to add --track-origins=yes to the above.
 
-  for i in awk cat cksum cmp cp cut date dirname egrep fgrep file grep gs \
-    head iconv mkdir mktemp perl rm sed seq sh tee testrandom tr uniq \
-    Available-Testprog
+  for i in awk basename cat cksum cmp comm cp cut date dirname \
+           egrep fgrep file grep gs head iconv ls mkdir mktemp perl \
+           printf rm sed seq sh sort tail tee tr uniq wc \
+           testrandom Available-Testprog
 
     # Tell valgrind not to probe execution of the above programs.
+    # You may add programs in Netpbm to the above to speed up tests.
 
     do vg_skip=$vg_skip"/*/"$i","; done;
 
@@ -237,13 +244,15 @@ if [ $VALGRIND_TESTS = "on" ]
 fi
 
 # Execute a single test and test its result.
-# But first check if the .ok file exists.  (Some .ok files are
-# dynamically created.)  Then see if target programs and requirements
-# are in place.  If either of these conditions are not met, do
-# not execute the test and report "Not Testable".
+# But first check if the .ok file exists.
+# (In past versions certain .ok files were dynamically created.)
+# Then see if target programs and requirements are in place.  If
+# either of these conditions are not met, do not execute the test and
+# report "Not Testable".
 
 if [ ! -s ${srcdir}/${tname%.test}.ok ]
 then
+  echo "${tname%.test}.ok does not exist"
   let result=4;
 else
   ${srcdir}/Available-Testprog \
@@ -295,7 +304,7 @@ fi
 # (Do not erase them if we are working from the source directory.)
 
 if [ ! $PWD -ef ${srcdir} ]
-    then rm ./testimg.ppm ./testgrid.pbm
+    then rm ./testimg.ppm ./testgrid.pbm ./maze.pbm
 fi
 
 
diff --git a/test/Makefile b/test/Makefile
index c640dfff..732113f3 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -8,27 +8,14 @@ include $(BUILDDIR)/config.mk
 
 MERGE_OBJECTS =
 
-PROGS = testrandom
-
-OKSTOGENERATE = $(patsubst %.rand-ok, %.ok, $(wildcard *.rand-ok))
-
-all: $(PROGS) $(OKSTOGENERATE)
-
-testrandom.o: testrandom.c
-	$(CC_FOR_BUILD) -c -o $@ $(CFLAGS_FOR_BUILD) $<
-
-testrandom: testrandom.o
-	$(LD_FOR_BUILD) -o $@ $(LDFLAGS_FOR_BUILD) $<
-
-RAND_VARIETY ?= $(shell ./testrandom -x)
-
-$(OKSTOGENERATE): %.ok: %.rand-ok testrandom
-	sed -n "/^$(RAND_VARIETY)|/s/^$(RAND_VARIETY)|//p" $< > $@
+PROGS =
 
 OMIT_TEST_RULE = 1
 include $(SRCDIR)/common.mk
 
+all:
+
 distclean clean: cleanlocal
 .PHONY: cleanlocal
 cleanlocal:
-	rm -f $(PROGS) $(patsubst %.rand-ok,%.ok,$(wildcard *.rand-ok))
+
diff --git a/test/Test-Order b/test/Test-Order
index 49eaeff2..16eeaf8e 100644
--- a/test/Test-Order
+++ b/test/Test-Order
@@ -2,6 +2,7 @@
 
 all-in-place.test
 legacy-names.test
+random-generator.test
 
 # Generator tests
 
@@ -15,6 +16,8 @@ pbmtext.test
 pbmtext-bdf.test
 pbmtext-iso88591.test
 pbmtext-utf8.test
+pbmtextps-dump.test
+pbmtextps.test
 pbmupc.test
 pgmramp.test
 pamgauss.test
@@ -22,10 +25,15 @@ ppmcie.test
 ppmwheel.test
 pamcrater.test
 ppmpat.test
+ppmforge-parameters.test
 
 # Generators with random components
 
+pbmnoise1.test
+pbmnoise2.test
+pbmnoise-parameters.test
 pgmnoise.test
+pgmnoise-parameters.test
 ppmpat-random.test
 ppmforge.test
 ppmrough.test
@@ -40,10 +48,15 @@ ppmhist.test
 pamsumm.test
 pnmpsnr.test
 pbmminkowski.test
+pgmminkowski.test
+
+pnmcolormap.test
+pnmcolormap2.test
 
 # Basic (internal) converter tests
 
 pamtopam.test
+pbmtopgm.test
 pgmtopgm.test
 ppmtoppm.test
 pgmtoppm.test
@@ -52,24 +65,43 @@ pnmtopnm-plain.test
 
 # Editor tests
 
+pamdepth.test
+
 pamditherbw.test
+pamditherbw-random.test
+pamhue.test
 
 pbmclean.test
 pamcut.test
+pamcat1.test
+pamcat2.test
+pamcat3.test
 pnmcat.test
+pamdice.test
+pamundice.test
+
 pamflip1.test
 pamflip2.test
 pnminvert.test
 pamchannel.test
 ppmchange.test
 pambackground.test
+pnmpad-reportonly.test
 pnmpaste-pbm.test
 
+pamrestack.test
+pamshuffle.test
+ppmshift.test
+ppmspread.test
+
 pbmpscale.test
+pamrecolor.test
 pnmremap1.test
 pnmremap2.test
+pnmquant.test
 pnmquantall.test
 pnmtile.test
+pambrighten.test
 ppmbrighten.test
 ppmdither.test
 ppmrelief.test
@@ -78,6 +110,11 @@ ppmdim.test
 pnmshear.test
 pgmbentley.test
 
+pamfunc.test
+pamarith.test
+pamarith-compare-equal.test
+pamarith-multiple-input.test
+
 pamenlarge.test
 pamenlarge-pbm.test
 
@@ -89,6 +126,11 @@ pamenlarge-pamscale-point.test
 
 pamstretch.test
 
+pnmcrop1.test
+pnmcrop2.test
+pnmcrop3.test
+pnmcrop-blank.test
+
 ppmmix.test
 pammixmulti-identity.test
 
@@ -96,18 +138,41 @@ pammixmulti-identity.test
 
 symmetry.test
 
+# Standard input tests
+
+stdin-pbm1.test
+stdin-pbm2.test
+stdin-pgm1.test
+stdin-pgm2.test
+stdin-ppm1.test
+stdin-ppm2.test
+stdin-ppm3.test
+stdin-pnm1.test
+stdin-pnm2.test
+stdin-pam1.test
+stdin-pam2.test
+stdin-pam3.test
+
+pbm-misc-converters.test
+
 # Format converter tests
 
 pamtopdbimg.test
 pbmtog3.test
+ppmtoapplevol.test
 411toppm.test
 eyuvtoppm.test
+rawtoppm.test
 
-pbm-misc-converters.test
+gif-transparent1.test
 
 # Miscellaneous utility tests
 
 ppmdfont.test
+pamfix.test
+pamvalidate.test
+pamexec.test
+pbmlife.test
 
 # Round-trip tests : editors
 
@@ -115,8 +180,10 @@ pnm-plain-roundtrip.test
 pnm-pam-roundtrip.test
 pnminvert-roundtrip.test
 pamflip-roundtrip.test
+pamflip-pbm-roundtrip.test
 pamdepth-roundtrip.test
 pad-crop-roundtrip.test
+pbm-ppm-roundtrip.test
 cut-paste-roundtrip.test
 rgb3-roundtrip.test
 ppmchange-roundtrip.test
@@ -125,6 +192,13 @@ pamslice-roundtrip.test
 lookup-roundtrip.test
 enlarge-reduce-roundtrip.test
 cut-cat-roundtrip.test
+pamhue-roundtrip.test
+
+# Round-trip tests: miscellaneous utilities
+
+pamendian-roundtrip.test
+pamexec-roundtrip.test
+channel-stack-roundtrip.test
 
 # Round-trip tests : lossless converters
 
@@ -160,9 +234,11 @@ pi3-roundtrip.test
 pict-roundtrip.test
 png-roundtrip.test
 png-roundtrip2.test
+pj-roundtrip.test
 ps-roundtrip.test
 ps-flate-roundtrip.test
 ps-alt-roundtrip.test
+qoi-roundtrip.test
 sgi-roundtrip.test
 sbig-roundtrip.test
 st4-roundtrip.test
@@ -174,6 +250,7 @@ tiff-flate-lzw-roundtrip.test
 utahrle-roundtrip.test
 wbmp-roundtrip.test
 winicon-roundtrip.test
+winicon-roundtrip2.test
 xbm-roundtrip.test
 xpm-roundtrip.test
 xv-roundtrip.test
@@ -183,5 +260,6 @@ xwd-roundtrip.test
 
 fiasco-roundtrip.test
 jpeg-roundtrip.test
+lps-roundtrip.test
 tiffcmyk-roundtrip.test
 yuv-roundtrip.test
diff --git a/test/all-in-place.ok b/test/all-in-place.ok
index 2df9f392..31854728 100644
--- a/test/all-in-place.ok
+++ b/test/all-in-place.ok
@@ -41,6 +41,7 @@ pamarith: ok
 pambackground: ok
 pambayer: ok
 pambrighten: ok
+pamcat: ok
 pamchannel: ok
 pamcomp: ok
 pamcrater: ok
@@ -61,6 +62,7 @@ pamfunc: ok
 pamgauss: ok
 pamgetcolor: ok
 pamgradient: ok
+pamhomography: ok
 pamhue: ok
 pamlevels: ok
 pamlookup: ok
@@ -74,12 +76,14 @@ pamperspective: ok
 pampick: ok
 pampop9: ok
 pamrecolor: ok
+pamrestack: ok
 pamrubber: ok
 pamscale: ok
 pamseq: ok
 pamshadedrelief: ok
 pamsharpmap: ok
 pamsharpness: ok
+pamshuffle: ok
 pamsistoaglyph: ok
 pamslice: ok
 pamsplit: ok
@@ -106,6 +110,7 @@ pamtopdbimg: ok
 pamtopfm: ok
 pamtopng: ok
 pamtopnm: ok
+pamtoqoi: ok
 pamtosrf: ok
 pamtosvg: ok
 pamtotga: ok
@@ -124,6 +129,7 @@ pbmlife: ok
 pbmmake: ok
 pbmmask: ok
 pbmminkowski: ok
+pbmnoise: ok
 pbmpage: ok
 pbmpscale: ok
 pbmreduce: ok
@@ -197,7 +203,6 @@ pjtoppm: ok
 pktopbm: ok
 pngtopam: ok
 pnmalias: ok
-pnmcat: ok
 pnmcolormap: ok
 pnmconvol: ok
 pnmcrop: ok
@@ -238,11 +243,9 @@ pnmtosir: ok
 pnmtotiffcmyk: ok
 pnmtoxwd: ok
 ppm3d: ok
-ppmbrighten: ok
 ppmchange: ok
 ppmcie: ok
 ppmcolormask: ok
-ppmcolors: ok
 ppmdcfont: ok
 ppmddumpfont: ok
 ppmdim: ok
@@ -266,6 +269,7 @@ ppmrough: ok
 ppmshadow: ok
 ppmshift: ok
 ppmspread: ok
+ppmsvgalib: ok
 ppmtoacad: ok
 ppmtoapplevol: ok
 ppmtoarbtxt: ok
@@ -276,6 +280,7 @@ ppmtoicr: ok
 ppmtoilbm: ok
 ppmtoleaf: ok
 ppmtolj: ok
+ppmtompeg: ok
 ppmtomitsu: ok
 ppmtoneo: ok
 ppmtopcx: ok
@@ -298,6 +303,7 @@ ppmtv: ok
 ppmwheel: ok
 psidtopgm: ok
 pstopnm: ok
+qoitopam: ok
 qrttoppm: ok
 rasttopnm: ok
 rawtopgm: ok
diff --git a/test/all-in-place.test b/test/all-in-place.test
index 6cf677ef..386d2872 100755
--- a/test/all-in-place.test
+++ b/test/all-in-place.test
@@ -83,6 +83,7 @@ ordinary_testprogs="\
   pambackground \
   pambayer \
   pambrighten \
+  pamcat \
   pamchannel \
   pamcomp \
   pamcrater \
@@ -103,6 +104,7 @@ ordinary_testprogs="\
   pamgauss \
   pamgetcolor \
   pamgradient \
+  pamhomography \
   pamhue \
   pamlevels \
   pamlookup \
@@ -116,12 +118,14 @@ ordinary_testprogs="\
   pampick \
   pampop9 \
   pamrecolor \
+  pamrestack \
   pamrubber \
   pamscale \
   pamseq \
   pamshadedrelief \
   pamsharpmap \
   pamsharpness \
+  pamshuffle \
   pamsistoaglyph \
   pamslice \
   pamsplit \
@@ -148,6 +152,7 @@ ordinary_testprogs="\
   pamtopfm \
   pamtopng \
   pamtopnm \
+  pamtoqoi \
   pamtosrf \
   pamtosvg \
   pamtotga \
@@ -166,6 +171,7 @@ ordinary_testprogs="\
   pbmmake \
   pbmmask \
   pbmminkowski \
+  pbmnoise \
   pbmpage \
   pbmpscale \
   pbmreduce \
@@ -239,7 +245,6 @@ ordinary_testprogs="\
   pktopbm \
   pngtopam \
   pnmalias \
-  pnmcat \
   pnmcolormap \
   pnmconvol \
   pnmcrop \
@@ -280,11 +285,9 @@ ordinary_testprogs="\
   pnmtotiffcmyk \
   pnmtoxwd \
   ppm3d \
-  ppmbrighten \
   ppmchange \
   ppmcie \
   ppmcolormask \
-  ppmcolors \
   ppmdcfont \
   ppmddumpfont \
   ppmdim \
@@ -308,6 +311,7 @@ ordinary_testprogs="\
   ppmshadow \
   ppmshift \
   ppmspread \
+  ppmsvgalib \
   ppmtoacad \
   ppmtoapplevol \
   ppmtoarbtxt \
@@ -318,6 +322,7 @@ ordinary_testprogs="\
   ppmtoilbm \
   ppmtoleaf \
   ppmtolj \
+  ppmtompeg \
   ppmtomitsu \
   ppmtoneo \
   ppmtopcx \
@@ -340,6 +345,7 @@ ordinary_testprogs="\
   ppmwheel \
   psidtopgm \
   pstopnm \
+  qoitopam \
   qrttoppm \
   rasttopnm \
   rawtopgm \
@@ -431,3 +437,5 @@ testExitStatus anytopnm 0 $?
 
 manweb --help > /dev/null
     testExitStatus manweb 0 $?
+
+# We do not test vidtoppm.
diff --git a/test/atari-roundtrip.test b/test/atari-roundtrip.test
index 413438a1..809cbdb2 100755
--- a/test/atari-roundtrip.test
+++ b/test/atari-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmtopi1 pi1toppm ppmtoneo neotoppm
 # Also requires: pgmramp pamscale pbmmake pamenlarge rgb3toppm pamdepth
 
diff --git a/test/atk-roundtrip.ok b/test/atk-roundtrip.ok
index 845be5fb..b9437e7d 100644
--- a/test/atk-roundtrip.ok
+++ b/test/atk-roundtrip.ok
@@ -1 +1,7 @@
-2425386270 41
+Test 1. Should print 281226646 481
+281226646 481
+Test 2. Should print 1824220442 125013 twice, then 2146497872 1000013 twice
+241513515 125013
+241513515 125013
+2146497872 1000013
+2146497872 1000013
diff --git a/test/atk-roundtrip.test b/test/atk-roundtrip.test
index 6db3df6d..97ac1be7 100755
--- a/test/atk-roundtrip.test
+++ b/test/atk-roundtrip.test
@@ -1,7 +1,23 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pbmtoatk atktopbm
-# Also requires:
+# Also requires: pbmmake
 
+echo "Test 1. Should print 281226646 481"
+# cksum of maze.pbm
 
-# Should print 2425386270 41, cksum of testgrid.pbm
-pbmtoatk testgrid.pbm | atktopbm | cksum
+pbmtoatk maze.pbm | atktopbm | cksum
+
+tmpdir=${tmpdir:-/tmp}
+maxwidth_pbm=${tmpdir}/maxwidth.pbm
+maxheight_pbm=${tmpdir}/maxheight.pbm
+
+echo \
+ "Test 2. Should print 1824220442 125013 twice, then 2146497872 1000013 twice"
+
+pbmmake -g 1000000 1 | tee ${maxwidth_pbm} | cksum
+pbmtoatk ${maxwidth_pbm} | atktopbm | cksum
+
+pbmmake -b 1 1000000 | tee ${maxheight_pbm} | cksum
+pbmtoatk ${maxheight_pbm} | atktopbm | cksum
+
+rm ${maxwidth_pbm} ${maxheight_pbm}
diff --git a/test/avs-roundtrip.test b/test/avs-roundtrip.test
index 042ce91e..255226db 100755
--- a/test/avs-roundtrip.test
+++ b/test/avs-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamtoavs avstopam
 # Also requires: pamtopnm
 
diff --git a/test/bmp-quant-roundtrip.test b/test/bmp-quant-roundtrip.test
index 2c223b7c..9f1036d0 100755
--- a/test/bmp-quant-roundtrip.test
+++ b/test/bmp-quant-roundtrip.test
@@ -1,6 +1,6 @@
 #! /bin/bash
 # This script tests: bmptopnm ppmtobmp pnmquant
-# Also requires: ppmhist
+# Also requires:
 
 tmpdir=${tmpdir:-/tmp}
 quant_ppm=${tmpdir}/quant.ppm
diff --git a/test/bmp-roundtrip.ok b/test/bmp-roundtrip.ok
index 4f4f8367..217a54aa 100644
--- a/test/bmp-roundtrip.ok
+++ b/test/bmp-roundtrip.ok
@@ -1,14 +1,14 @@
-PBM
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-PPM
+Test 1 PBM.  Should print 281226646 481 four times
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+Test 2 PPM.  Should print 1926073387 101484 four times
 1926073387 101484
 1926073387 101484
 1926073387 101484
 1926073387 101484
-PGM
+Test 3 PGM.  Should print 1571496937 33838 nine times
 1571496937 33838
 1571496937 33838
 1571496937 33838
diff --git a/test/bmp-roundtrip.test b/test/bmp-roundtrip.test
index c9ef363a..340eee66 100755
--- a/test/bmp-roundtrip.test
+++ b/test/bmp-roundtrip.test
@@ -1,30 +1,24 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: bmptopnm ppmtobmp
 # Also requires: pamchannel pamtopnm pamseq
 
 tmpdir=${tmpdir:-/tmp}
 
-# Test 1.  Should print 2425386270 41 four times
-
-echo PBM
+echo "Test 1 PBM.  Should print 281226646 481 four times"
 
 for mode in "" "-bpp=1" "-windows" "-os2"
   do
-  ppmtobmp ${mode} testgrid.pbm | bmptopnm | cksum
+  ppmtobmp ${mode} maze.pbm | bmptopnm | cksum
   done
 
-# Test 2.  Should print 1926073387 101484 four times
-
-echo PPM
+echo "Test 2 PPM.  Should print 1926073387 101484 four times"
 
 for mode in "" "-bpp=24" "-windows" "-os2"
   do
   ppmtobmp ${mode} testimg.ppm | bmptopnm | cksum
   done
 
-# Test 3.  Should print 1571496937 33838 nine times
-
-echo PGM
+echo "Test 3 PGM.  Should print 1571496937 33838 nine times"
 
 red_pgm=${tmpdir}/red.pgm
 mapfile_pgm=${tmpdir}/mapfile.pgm
diff --git a/test/channel-stack-roundtrip.ok b/test/channel-stack-roundtrip.ok
new file mode 100644
index 00000000..708305f1
--- /dev/null
+++ b/test/channel-stack-roundtrip.ok
@@ -0,0 +1,11 @@
+Test 1: should print 1873848880 101532 twice, then 0
+1873848880 101532
+1873848880 101532
+1873848880 101532
+1873848880 101532
+1873848880 101532
+0
+Test 2: Should print 447072062 33892 three times
+447072062 33892
+447072062 33892
+447072062 33892
diff --git a/test/channel-stack-roundtrip.test b/test/channel-stack-roundtrip.test
new file mode 100755
index 00000000..14ac0d2e
--- /dev/null
+++ b/test/channel-stack-roundtrip.test
@@ -0,0 +1,34 @@
+#! /bin/sh
+# This script tests: pamchannel pamstack
+# Also requires: pamtopam pamtopnm
+
+tmpdir=${tmpdir:-/tmp}
+r_pam=${tmpdir}/testimg_r.pam
+g_pam=${tmpdir}/testimg_g.pam
+b_pam=${tmpdir}/testimg_b.pam
+rgb_pam=${tmpdir}/testimg_rgb.pam
+
+echo "Test 1: should print 1873848880 101532 twice, then 0"
+
+pamchannel -tupletype="GRAYSCALE" -infile testimg.ppm 0 > ${r_pam}
+pamchannel -tupletype="GRAYSCALE" -infile testimg.ppm 1 > ${g_pam}
+pamchannel -tupletype="GRAYSCALE" -infile testimg.ppm 2 > ${b_pam}
+
+pamtopam < testimg.ppm | pamstack -tupletype="RGB" - | cksum
+pamstack ${r_pam} ${g_pam} | \
+pamstack -tupletype="RGB" - ${b_pam} | cksum
+pamstack ${r_pam} | \
+pamstack -tupletype="RGB" - ${g_pam} ${b_pam} | cksum
+pamstack ${r_pam} ${b_pam} ${g_pam} ${b_pam} ${b_pam} ${b_pam} | \
+  pamchannel -tupletype="RGB" 0 2 4 | cksum 
+pamstack -tupletype="RGB" ${r_pam} ${g_pam} ${b_pam} | tee ${rgb_pam} | cksum
+pamtopnm ${rgb_pam} | cmp - testimg.ppm
+echo $?
+
+echo "Test 2: Should print 447072062 33892 three times"
+
+cat ${r_pam} | cksum
+pamstack -tupletype="GRAYSCALE" ${r_pam} | cksum
+pamstack ${r_pam} | pamchannel -tupletype="GRAYSCALE" 0 | cksum
+
+rm ${r_pam} ${g_pam} ${b_pam} ${rgb_pam}
diff --git a/test/cis-roundtrip.ok b/test/cis-roundtrip.ok
index da90078b..1bb50cb7 100644
--- a/test/cis-roundtrip.ok
+++ b/test/cis-roundtrip.ok
@@ -1,2 +1,5 @@
+Test 1. Should print 2631579683 1546 twice
 2631579683 1546
-2425386270 41
+2631579683 1546
+Test 2. Should print 281226646 481, cksum of maze.pbm
+281226646 481
diff --git a/test/cis-roundtrip.test b/test/cis-roundtrip.test
index 62fcc3b9..ad34173e 100755
--- a/test/cis-roundtrip.test
+++ b/test/cis-roundtrip.test
@@ -1,14 +1,20 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pbmtocis cistopbm
-# Also requires: pbmmake pamcut
+# Also requires: pbmmake pamcut pamfile
 
+tmpdir=${tmpdir:-/tmp}
+test_pbm=${tmpdir}/test.pbm
 
 # Output images produced by pbmtocis are of fixed size,
 # either 128x96 or 256x192.
 # Smaller input images are padded, larger ones are cropped.
 
-# Test 1. Should print 2631579683 1546
-pbmmake -g 128 96 | pbmtocis | cistopbm | cksum
+echo "Test 1. Should print 2631579683 1546 twice"
+pbmmake -g 128 96 | tee ${test_pbm} | cksum
+pbmtocis ${test_pbm} | cistopbm | cksum
 
-# Test 2. Should print 2425386270 41
-pbmtocis testgrid.pbm | cistopbm | pamcut 0 0 14 16 | cksum
+echo "Test 2. Should print 281226646 481, cksum of maze.pbm"
+size=$(pamfile -size maze.pbm | awk '{print "-width="$1,"-height="$2}')
+pbmtocis maze.pbm | cistopbm | pamcut -left=0 -top=0 ${size} | cksum
+
+rm ${test_pbm}
\ No newline at end of file
diff --git a/test/cmuw-roundtrip.ok b/test/cmuw-roundtrip.ok
index 845be5fb..4ec1a381 100644
--- a/test/cmuw-roundtrip.ok
+++ b/test/cmuw-roundtrip.ok
@@ -1 +1,2 @@
-2425386270 41
+Should print 281226646 481, cksum of maze.pbm
+281226646 481
diff --git a/test/cmuw-roundtrip.test b/test/cmuw-roundtrip.test
index e52adb70..8664a1e6 100755
--- a/test/cmuw-roundtrip.test
+++ b/test/cmuw-roundtrip.test
@@ -1,7 +1,6 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pbmtocmuwm cmuwmtopbm
 # Also requires:
 
-
-# Should print 2425386270 41, cksum of testgrid.pbm
-pbmtocmuwm testgrid.pbm | cmuwmtopbm | cksum
+echo "Should print 281226646 481, cksum of maze.pbm"
+pbmtocmuwm maze.pbm | cmuwmtopbm | cksum
diff --git a/test/cut-cat-roundtrip.ok b/test/cut-cat-roundtrip.ok
index bc9b8cb4..edf1de67 100644
--- a/test/cut-cat-roundtrip.ok
+++ b/test/cut-cat-roundtrip.ok
@@ -1,92 +1,54 @@
-Test 1.
-1926073387 101484
-1926073387 101484
-1926073387 101484
-1926073387 101484
-1926073387 101484
-1926073387 101484
-Test 2.
-3891261972 202953
-3891261972 202953
-3891261972 202953
-3891261972 202953
-3891261972 202953
-3891261972 202953
-Test 3.
-1926073387 101484
-1926073387 101484
-1926073387 101484
-1926073387 101484
-1926073387 101484
-Test 4.
-26789469 202953
-26789469 202953
-26789469 202953
-26789469 202953
-26789469 202953
-Test 5.
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-Test 6.
-1887700557 73
-1887700557 73
-1887700557 73
-1887700557 73
-1887700557 73
-1887700557 73
-1887700557 73
-1887700557 73
-1887700557 73
-1887700557 73
-1887700557 73
-1887700557 73
-1887700557 73
-1887700557 73
-1887700557 73
-Test 7.
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-Test 8.
-3221289196 73
-3221289196 73
-3221289196 73
-3221289196 73
-3221289196 73
-3221289196 73
-3221289196 73
-3221289196 73
-3221289196 73
-3221289196 73
-3221289196 73
-3221289196 73
-3221289196 73
-3221289196 73
-3221289196 73
-3221289196 73
-3221289196 73
+Test 1.  Should print 1926073387 101484 six times
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+Test 2.  Should print 3891261972 202953 1926073387 101484 six times
+3891261972 202953 1926073387 101484
+3891261972 202953 1926073387 101484
+3891261972 202953 1926073387 101484
+3891261972 202953 1926073387 101484
+3891261972 202953 1926073387 101484
+3891261972 202953 1926073387 101484
+Test 3.  Should print 1926073387 101484 five times
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+Test 4.  Should print 26789469 202953 1926073387 101484 five times
+26789469 202953 1926073387 101484
+26789469 202953 1926073387 101484
+26789469 202953 1926073387 101484
+26789469 202953 1926073387 101484
+26789469 202953 1926073387 101484
+Test 5.  Should print 281226646 481 six times
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+Test 6.  Should print 1748767123 895 281226646 481 six times
+1748767123 895 281226646 481
+1748767123 895 281226646 481
+1748767123 895 281226646 481
+1748767123 895 281226646 481
+1748767123 895 281226646 481
+1748767123 895 281226646 481
+Test 7.  Should print 281226646 481 seven times
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+Test 8.  Should print 1346655680 954 281226646 481 five times
+1346655680 954 281226646 481
+1346655680 954 281226646 481
+1346655680 954 281226646 481
+1346655680 954 281226646 481
+1346655680 954 281226646 481
diff --git a/test/cut-cat-roundtrip.test b/test/cut-cat-roundtrip.test
index 95ee5279..274cb865 100755
--- a/test/cut-cat-roundtrip.test
+++ b/test/cut-cat-roundtrip.test
@@ -1,128 +1,147 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamcut
-# Also requires: pnmcat pnmpad
+# Also requires: pamfile pamcat pnmpad pnmcrop
 
 tmpdir=${tmpdir:-/tmp}
-quant_ppm=${tmpdir}/quant.ppm
 
-right_pbm=${tmpdir}/right.pbm
-left_pbm=${tmpdir}/left.pbm
-right_ppm=${tmpdir}/right.ppm
 left_ppm=${tmpdir}/left.ppm
-bottom_pbm=${tmpdir}/bottom.pbm
-top_pbm=${tmpdir}/top.pbm
-bottom_ppm=${tmpdir}/bottom.ppm
+right_ppm=${tmpdir}/right.ppm
 top_ppm=${tmpdir}/top.ppm
+bottom_ppm=${tmpdir}/bottom.ppm
+padded_ppm=${tmpdir}/padded.ppm
+
+echo "Test 1.  Should print 1926073387 101484 six times"
 
+testimg_ppm_sum=`cksum < testimg.ppm`
+echo ${testimg_ppm_sum}
 
-# Test 1.  Should print 1926073387 101484 six times
-echo Test 1.
+imgsize=$(pamfile -size testimg.ppm)
+width=$(echo ${imgsize} | cut -d " " -f 1)
+height=$(echo ${imgsize} | cut -d " " -f 2)
 
-cat testimg.ppm | cksum
 for i in 0 1 128 224 225
   do
   pamcut -left=$((i+1)) testimg.ppm > ${right_ppm}
   pamcut -right=$i      testimg.ppm > ${left_ppm}
-  pnmcat -lr ${left_ppm} ${right_ppm} | \
-    pamcut -left=0 -width=227| cksum
+  pamcat -lr ${left_ppm} ${right_ppm} | \
+    pamcut -left=0 -width=${width} | cksum
   rm ${left_ppm} ${right_ppm}
   done
 
+echo "Test 2.  Should print 3891261972 202953 1926073387 101484 six times"
+# Padding added to right.
 
-# Test 2.  Should print 3891261972 202953 six times
-# Not roundtrip.  Padding added to right.
-echo Test 2.
+pnmpad -right=${width} -black testimg.ppm | cksum | tr '\n' ' '
+echo ${testimg_ppm_sum}
 
-pnmpad -right=227 -black testimg.ppm | cksum
-for i in  0 1 128 224 225
+for border in 0 1 128 224 225
   do
-  pamcut -left=$((i+1)) -width=227 -pad testimg.ppm > ${right_ppm}
-  pamcut -right=$i      -width=227 -pad testimg.ppm > ${left_ppm}
-  pnmcat -lr ${left_ppm} ${right_ppm} ${left_ppm} | \
-    pamcut -left=$((227-i-1))  -width=$((227*2)) | cksum
-  rm ${left_ppm} ${right_ppm}
+  pamcut -left=$((${border}+1)) -width=${width} -pad testimg.ppm > ${right_ppm}
+  pamcut -right=${border} -width=${width} -pad testimg.ppm > ${left_ppm}
+  pamcat -lr ${left_ppm} ${right_ppm} ${left_ppm} | \
+    pamcut -left=$((${width}-${border}-1))  -width=$((${width}*2)) | \
+    tee ${padded_ppm} | cksum | tr '\n' ' '
+  pnmcrop -black -right ${padded_ppm} | cksum
+  rm ${left_ppm} ${right_ppm} ${padded_ppm}
   done
 
 
-# Test 3.  Should print 1926073387 101484 five times
-echo Test 3.
+echo "Test 3.  Should print 1926073387 101484 five times"
 
-cat testimg.ppm | cksum
-for i in 0 1 70 147
+echo ${testimg_ppm_sum}
+for border in 0 1 70 147
   do
-  pamcut -top=$((i+1)) testimg.ppm > ${bottom_ppm}
-  pamcut -bottom=$i    testimg.ppm > ${top_ppm}
-  pnmcat -tb ${top_ppm} ${bottom_ppm} | \
-    pamcut -top=0 -height=149 | cksum
+  pamcut -top=$((${border}+1)) testimg.ppm > ${bottom_ppm}
+  pamcut -bottom=${border}     testimg.ppm > ${top_ppm}
+  pamcat -tb ${top_ppm} ${bottom_ppm} | \
+    pamcut -top=0 -height=${height} | cksum
   rm ${top_ppm} ${bottom_ppm}
   done
 
-# Test 4.  Should print 26789469 202953 five times
-# Not roundtrip.  Padding added to bottom.
-echo Test 4.
+echo "Test 4.  Should print 26789469 202953 1926073387 101484 five times"
+# Padding added to bottom.
 
-pnmpad -bottom=149 -black testimg.ppm | cksum
-for i in 0 1 70 147
+pnmpad -bottom=${height} -black testimg.ppm | cksum | tr '\n' ' '
+echo ${testimg_ppm_sum}
+for border in 0 1 70 147
   do
-  pamcut -top=$((i+1)) -height=149 -pad testimg.ppm > ${bottom_ppm}
-  pamcut -bottom=$i    -height=149 -pad testimg.ppm > ${top_ppm}
-  pnmcat -tb ${top_ppm} ${bottom_ppm} ${top_ppm} | \
-    pamcut -top=$((149-i-1))  -height=$((149*2)) | cksum
-  rm ${top_ppm} ${bottom_ppm}
+  pamcut -top=$((${border}+1)) -height=${height} -pad testimg.ppm \
+    > ${bottom_ppm}
+  pamcut -bottom=${border}     -height=${height} -pad testimg.ppm > ${top_ppm}
+  pamcat -tb ${top_ppm} ${bottom_ppm} ${top_ppm} | \
+    pamcut -top=$((${height}-${border}-1))  -height=$((${height}*2)) | \
+    tee ${padded_ppm} | cksum | tr '\n' ' 'cksum
+  pnmcrop -black -bottom ${padded_ppm} | cksum
+  rm ${top_ppm} ${bottom_ppm} ${padded_ppm}
   done
 
-# Test 5.  Should print 2425386270 41 fourteen times
-echo Test 5.
+left_pbm=${tmpdir}/left.pbm
+right_pbm=${tmpdir}/right.pbm
+top_pbm=${tmpdir}/top.pbm
+bottom_pbm=${tmpdir}/bottom.pbm
+padded_pbm=${tmpdir}/padded.pbm
+
+echo "Test 5.  Should print 281226646 481 six times"
+
+maze_pbm_sum=`cksum < maze.pbm`
+echo ${maze_pbm_sum}
+
+imgsize=$(pamfile -size maze.pbm)
+width=$(echo ${imgsize} | cut -d " " -f 1)
+height=$(echo ${imgsize} | cut -d " " -f 2)
 
-cat testgrid.pbm | cksum
-for i in `seq 0 12`
+for i in 0 1 10 30 50
   do
-  pamcut -left=$((i+1)) testgrid.pbm > ${right_pbm}
-  pamcut -right=$i      testgrid.pbm > ${left_pbm}
-  pnmcat -lr ${left_pbm} ${right_pbm} | \
-    pamcut -left=0 -width=14 | cksum
-  rm ${left_pbm} ${right_pbm}
+  pamcut -left=$((i+1)) maze.pbm > ${right_ppm}
+  pamcut -right=$i      maze.pbm > ${left_ppm}
+  pamcat -lr ${left_ppm} ${right_ppm} | \
+    pamcut -left=0 -width=${width} | cksum
+  rm ${left_ppm} ${right_ppm}
   done
 
 
-# Test 6.  Should print 1887700557 73 fifteen times
-# Not roundtrip.  Padding added to right.
-echo Test 6.
+echo "Test 6.  Should print 1748767123 895 281226646 481 six times"
+# Padding added to right.
+
+pnmpad -right=${width} -black maze.pbm | cksum | tr '\n' ' '
+echo ${maze_pbm_sum}
 
-pnmpad -right=14 -black testgrid.pbm | cksum
-for i in `seq 0 13`
+for border in 0 1 10 30 50
   do
-  pamcut -left=$((i+1)) -width=14 -pad testgrid.pbm > ${right_pbm}
-  pamcut -right=$i      -width=14 -pad testgrid.pbm > ${left_pbm}
-  pnmcat -lr ${left_pbm} ${right_pbm} ${left_pbm} | \
-    pamcut -left=$((14-i-1)) -width=28 | cksum
-  rm ${left_pbm} ${right_pbm}
+  pamcut -left=$((${border}+1)) -width=${width} -pad maze.pbm > ${right_ppm}
+  pamcut -right=${border} -width=${width} -pad maze.pbm > ${left_ppm}
+  pamcat -lr ${left_ppm} ${right_ppm} ${left_ppm} | \
+    pamcut -left=$((${width}-${border}-1))  -width=$((${width}*2)) | \
+    tee ${padded_ppm} | cksum | tr '\n' ' '
+  pnmcrop -black -right ${padded_ppm} | cksum
+  rm ${left_ppm} ${right_ppm} ${padded_ppm}
   done
 
-# Test 7.  Should print 2425386270 41 sixteen times
-echo Test 7.
 
-cat testgrid.pbm | cksum
-for i in `seq 0 14`
+echo "Test 7.  Should print 281226646 481 seven times"
+
+echo ${maze_pbm_sum}
+for border in 0 1 12 21 31 44
   do
-  pamcut -top=$((i+1)) testgrid.pbm > ${bottom_pbm}
-  pamcut -bottom=$i    testgrid.pbm > ${top_pbm}
-  pnmcat -tb ${top_pbm} ${bottom_pbm} | \
-    pamcut -top=0 -height=16 | cksum
-  rm ${top_pbm} ${bottom_pbm}
+  pamcut -top=$((${border}+1)) maze.pbm > ${bottom_ppm}
+  pamcut -bottom=${border}     maze.pbm > ${top_ppm}
+  pamcat -tb ${top_ppm} ${bottom_ppm} | \
+    pamcut -top=0 -height=${height} | cksum
+  rm ${top_ppm} ${bottom_ppm}
   done
 
-# Test 8.  Should print 3221289196 73 seventeen times
-# Not roundtrip.  Padding added to bottom.
-echo Test 8.
+echo "Test 8.  Should print 1346655680 954 281226646 481 five times"
+# Padding added to bottom.
 
-pnmpad -bottom=16 -black testgrid.pbm | cksum
-for i in `seq 0 15`
+pnmpad -bottom=${height} -black maze.pbm | cksum | tr '\n' ' '
+echo ${maze_pbm_sum}
+for border in 0 1 10 50
   do
-  pamcut -top=$((i+1)) -height=16 -pad testgrid.pbm > ${bottom_pbm}
-  pamcut -bottom=$i    -height=16 -pad testgrid.pbm > ${top_pbm}
-  pnmcat -tb ${top_pbm} ${bottom_pbm} ${top_pbm} | \
-    pamcut -top=$((16-i-1)) -height=32 | cksum
-  rm ${top_pbm} ${bottom_pbm}
+  pamcut -top=$((${border}+1)) -height=${height} -pad maze.pbm > ${bottom_ppm}
+  pamcut -bottom=${border}     -height=${height} -pad maze.pbm > ${top_ppm}
+  pamcat -tb ${top_ppm} ${bottom_ppm} ${top_ppm} | \
+    pamcut -top=$((${height}-${border}-1))  -height=$((${height}*2)) | \
+    tee ${padded_ppm} | cksum | tr '\n' ' 'cksum
+  pnmcrop -black -bottom ${padded_ppm} | cksum
+  rm ${top_ppm} ${bottom_ppm} ${padded_ppm}
   done
-
diff --git a/test/cut-paste-roundtrip.test b/test/cut-paste-roundtrip.test
index 1bb3a7c2..bec8baf5 100755
--- a/test/cut-paste-roundtrip.test
+++ b/test/cut-paste-roundtrip.test
@@ -1,7 +1,8 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamcut pnmpaste
 # Also requires: pbmmake pnmpad
 
+tmpdir=${tmpdir:-/tmp}
 base_ppm=${tmpdir}/base.ppm
 
 # Test 1. Should produce 2999529086 101484
diff --git a/test/enlarge-reduce-roundtrip.test b/test/enlarge-reduce-roundtrip.test
index 54b52c60..5d223cf1 100755
--- a/test/enlarge-reduce-roundtrip.test
+++ b/test/enlarge-reduce-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamenlarge pbmpscale pbmreduce
 # Also requires: pbmtext
 
diff --git a/test/eyuvtoppm.test b/test/eyuvtoppm.test
index b28b4539..6bbc2e7e 100755
--- a/test/eyuvtoppm.test
+++ b/test/eyuvtoppm.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: eyuvtoppm
 # Also requires:
 
diff --git a/test/facesaver-roundtrip.test b/test/facesaver-roundtrip.test
index f4b8f069..75fcf662 100755
--- a/test/facesaver-roundtrip.test
+++ b/test/facesaver-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pgmtofs fstopgm
 # Also requires: pamchannel pamtopnm
 
diff --git a/test/fiasco-roundtrip.test b/test/fiasco-roundtrip.test
index 8325a37d..8d5fdaa6 100755
--- a/test/fiasco-roundtrip.test
+++ b/test/fiasco-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pnmtofiasco fiascotopnm
 # Also requires: pnmpad pnmpsnr
 
diff --git a/test/fits-roundtrip.test b/test/fits-roundtrip.test
index e793df9a..030a519e 100755
--- a/test/fits-roundtrip.test
+++ b/test/fits-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamtofits fitstopnm
 # Also requires:
 
diff --git a/test/g3-roundtrip.ok b/test/g3-roundtrip.ok
index 603c9457..7140cc8b 100644
--- a/test/g3-roundtrip.ok
+++ b/test/g3-roundtrip.ok
@@ -1,6 +1,9 @@
+Test 1.  Should print 0 0 0 : 0 or 0 0 0 0 : 0 total three times
 0 0 0 : 0
 0 0 0 : 0
 0 0 0 0 : 0
+Test 2.  Should print 0 0 0 : 0 or 0 0 0 0 : 0 total seven times
+then 1777627284 265, 2985378006 3135, 3651878552 3135
 0 0 0 : 0
 0 0 0 : 0
 0 0 0 0 : 0
@@ -11,3 +14,9 @@
 1777627284 265
 2985378006 3135
 3651878552 3135
+Test 3.  Should print 0 0 0 : 0 twice
+then 356688157 17399694 twice
+0 0 0 : 0
+0 0 0 : 0
+356688157 17399694
+356688157 17399694
diff --git a/test/g3-roundtrip.test b/test/g3-roundtrip.test
index 6e31c587..2736c09a 100755
--- a/test/g3-roundtrip.test
+++ b/test/g3-roundtrip.test
@@ -1,23 +1,33 @@
 #! /bin/bash
 # This script tests: g3topbm pbmtog3
-# Also requires: pnmcrop
+# Also requires: pamfile pnmcrop pbmmake pbmpage pnmpad pamenlarge
 
 tmpdir=${tmpdir:-/tmp}
 complete256_pbm=${tmpdir}/complete256.pbm
 widew_pbm=${tmpdir}/widew.pbm
 wideb_pbm=${tmpdir}/wideb.pbm
+page_pbm=${tmpdir}/page.pbm
+pagemax_pbm=${tmpdir}/pagemax.pbm
 
-pbmtog3 -nofixedwidth testgrid.pbm | \
-g3topbm -width=14 | cmp -s - testgrid.pbm
+echo "Test 1.  Should print 0 0 0 : 0 or 0 0 0 0 : 0 total three times"
+
+width=$(pamfile -size maze.pbm | cut -d " " -f 1) 
+
+pbmtog3 -nofixedwidth maze.pbm | \
+g3topbm -width=${width} | cmp -s - maze.pbm
 echo ${PIPESTATUS[@]} ":" $?
 
-pbmtog3 -nofixedwidth -reversebits testgrid.pbm | \
-g3topbm -width=14 -reversebits | cmp -s - testgrid.pbm
+pbmtog3 -nofixedwidth -reversebits maze.pbm | \
+g3topbm -width=${width} -reversebits | cmp -s - maze.pbm
 echo ${PIPESTATUS[@]} ":" $?
 
-pbmtog3 testgrid.pbm | \
+pbmtog3 maze.pbm | \
 g3topbm  | pnmcrop -white -right -bottom | \
- cmp -s - testgrid.pbm ; echo ${PIPESTATUS[@]} ":" $?
+ cmp -s - maze.pbm ; echo ${PIPESTATUS[@]} ":" $?
+
+
+echo "Test 2.  Should print 0 0 0 : 0 or 0 0 0 0 : 0 total seven times"
+echo "then 1777627284 265, 2985378006 3135, 3651878552 3135"
 
 # works with gawk and mawk
 # produce all possible 8-bit patterns
@@ -27,7 +37,7 @@ LC_ALL=C awk 'BEGIN { print "P4";         # header
                       for (i=0;i<256;++i) # raster
                            printf("%c",i) }' > ${complete256_pbm}
 
-pbmtog3 -nofixedwidth  ${complete256_pbm} |  g3topbm -width=8 | \
+pbmtog3 -nofixedwidth  ${complete256_pbm} | g3topbm -width=8 | \
  cmp -s - ${complete256_pbm} ; echo ${PIPESTATUS[@]} ":" $?
 
 pbmtog3 -reverse -nofixedwidth ${complete256_pbm} | \
@@ -59,3 +69,20 @@ cat ${wideb_pbm} | cksum
 cat ${widew_pbm} | cksum
 
 rm ${complete256_pbm} ${wideb_pbm} ${widew_pbm}
+
+
+echo "Test 3.  Should print 0 0 0 : 0 twice"
+echo "then 356688157 17399694 twice"
+
+pbmpage 3 -a4 | pamenlarge 2 > ${page_pbm}
+pbmtog3 -nofixedwidth  ${page_pbm} | g3topbm | \
+ cmp -s - ${page_pbm} ; echo ${PIPESTATUS[@]} ":" $?
+
+pnmpad -width=1000 -height=1400 ${page_pbm} > ${pagemax_pbm}
+pbmtog3 -nofixedwidth  ${pagemax_pbm} | g3topbm  | \
+ cmp -s - ${pagemax_pbm} ; echo ${PIPESTATUS[@]} ":" $?
+
+cat ${page_pbm} | cksum
+cat ${pagemax_pbm} | cksum
+
+rm ${page_pbm} ${pagemax_pbm} 
\ No newline at end of file
diff --git a/test/gem-roundtrip.ok b/test/gem-roundtrip.ok
index 845be5fb..5168378d 100644
--- a/test/gem-roundtrip.ok
+++ b/test/gem-roundtrip.ok
@@ -1 +1 @@
-2425386270 41
+281226646 481
diff --git a/test/gem-roundtrip.test b/test/gem-roundtrip.test
index 0fce59db..d97a5cb9 100755
--- a/test/gem-roundtrip.test
+++ b/test/gem-roundtrip.test
@@ -1,7 +1,7 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pbmtogem gemtopnm
 # Also requires:
 
 
-# Should print 2425386270 41, cksum of testgrid.pbm
-pbmtogem testgrid.pbm | gemtopnm | cksum
+# Should print 281226646 481, cksum of maze.pbm
+pbmtogem maze.pbm | gemtopnm | cksum
diff --git a/test/gif-roundtrip.ok b/test/gif-roundtrip.ok
index 607ebd5c..27d1bb47 100644
--- a/test/gif-roundtrip.ok
+++ b/test/gif-roundtrip.ok
@@ -1,18 +1,23 @@
+Test 1. Should print 1926073387 101484
 1926073387 101484
+Test 2. Should produce 1571496937 33838 six times
 1571496937 33838
 1571496937 33838
 1571496937 33838
 1571496937 33838
 1571496937 33838
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
+1571496937 33838
+Test 3. Should produce 281226646 481 six times
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+Test 4. Should produce P1 4 1 0101
 P1 4 1 0101 
-4030 : 0 0 0 0 : 0 , 4030 : 0 0 0 0 : 0
-4031 : 0 0 0 0 : 0 , 4031 : 0 0 0 0 : 0
-4097 : 0 0 0 0 : 0 , 4097 : 0 0 0 0 : 0
+Test 5. Should produce: N : 0 0 0 0 : 0 , N : 0 0 0 0 : 0
+(N=238, 239, 240, 241, 255, 256, 257, 4030, 4031, 4097)
 238 : 0 0 0 0 : 0 , 238 : 0 0 0 0 : 0
 239 : 0 0 0 0 : 0 , 239 : 0 0 0 0 : 0
 240 : 0 0 0 0 : 0 , 240 : 0 0 0 0 : 0
@@ -20,3 +25,6 @@ P1 4 1 0101
 255 : 0 0 0 0 : 0 , 255 : 0 0 0 0 : 0
 256 : 0 0 0 0 : 0 , 256 : 0 0 0 0 : 0
 257 : 0 0 0 0 : 0 , 257 : 0 0 0 0 : 0
+4030 : 0 0 0 0 : 0 , 4030 : 0 0 0 0 : 0
+4031 : 0 0 0 0 : 0 , 4031 : 0 0 0 0 : 0
+4097 : 0 0 0 0 : 0 , 4097 : 0 0 0 0 : 0
diff --git a/test/gif-roundtrip.test b/test/gif-roundtrip.test
index 1e6c7760..13ff595e 100755
--- a/test/gif-roundtrip.test
+++ b/test/gif-roundtrip.test
@@ -7,7 +7,8 @@ tmpdir=${tmpdir:-/tmp}
 # Test 1. Break up input image into three monochrome planes,
 # maxval 255.  Transform each plane to gif and back to pgm.
 # Reassemble the planes.  Result should be identical to input.
-# Should print 1926073387 101484
+
+echo "Test 1. Should print 1926073387 101484"
 
 test_ppm=${tmpdir}/testimg.ppm
 
@@ -29,13 +30,11 @@ pamtogif ${test_blu} | giftopnm | \
 
 rm ${test_ppm} ${test_grn} ${test_blu} ${out_red} ${out_grn}
 
-
-# Test 2. Should produce 1571496937 33838
-# which is the result of cksum testimg.red
-# five times
+echo "Test 2. Should produce 1571496937 33838 six times"
 
 test_gif=${tmpdir}/testimg.gif
 
+cat ${test_red} | cksum
 pamtogif ${test_red} | giftopnm | cksum
 pamtogif -interlace ${test_red} | giftopnm | cksum
 pamtogif -noclear ${test_red} | giftopnm | cksum
@@ -46,22 +45,23 @@ echo "junk" >> ${test_gif} && \
 
 rm  ${test_gif} ${test_red}
 
+echo "Test 3. Should produce 281226646 481 six times"
+# maze.pbm is too small for -noclear to take effect 
 
-# Test 3. Should produce 2425386270 41 five times.
-# testgrid.pbm is too small for -noclear to take effect 
-
-pamtogif testgrid.pbm | giftopnm | cksum
-pamtogif -nolzw testgrid.pbm | giftopnm | cksum
-pamtogif -transparent=black testgrid.pbm | giftopnm | cksum
-pamtogif -alpha=testgrid.pbm testgrid.pbm | giftopnm | cksum
-pamtogif -transparent=white testgrid.pbm | giftopnm -alpha=- | \
+cat maze.pbm | cksum
+pamtogif maze.pbm | giftopnm | cksum
+pamtogif -nolzw maze.pbm | giftopnm | cksum
+pamtogif -transparent=black maze.pbm | giftopnm | cksum
+pamtogif -alpha=maze.pbm maze.pbm | giftopnm | cksum
+pamtogif -transparent=white maze.pbm | giftopnm -alpha=- | \
   pnminvert | cksum
 
 
 # Test 4.
 # In this gif file the code length changes after the last image data.
 # Image data: 3 bits, end code 4 bits.
-# Should produce P1 4 1 0 1 0 1
+
+echo "Test 4. Should produce P1 4 1 0101"
 
 pbmmake -g 4 1 | \
   pamtogif -verbose | giftopnm -plain | \
@@ -71,25 +71,18 @@ echo ""
 
 # Test 5.
 # Test whether saturated code tables are handled correctly.
-# Test input images which most use up the string code table or
+# Test input images which use up the string code table or
 # come close to doing so.
 
-# Should produce:
-# 4030 0 , 4030 0
-# 4031 0 , 4031 0
-# 4097 0 , 4097 0
-# 238 0 , 238 0
-# 239 0 , 239 0
-# 240 0 , 240 0
-# 241 0 , 241 0
-# 255 0 , 255 0
-# 256 0 , 256 0
-# 257 0 , 257 0
 
-test4097_pgm=${tmpdir}/testimg4097.pgm
+echo "Test 5. Should produce: N : 0 0 0 0 : 0 , N : 0 0 0 0 : 0"
+echo "(N=238, 239, 240, 241, 255, 256, 257, 4030, 4031, 4097)"
+
 test_pgm=${tmpdir}/testimg.pgm
 
-# The following awk script produces a PGM file with no repeated sequences.
+# The following awk scripts produce a PGM file with no repeated
+# sequences.  Obviously this cannot be compressed at all; the codes
+# are consumed without ever being used.  
 # Here is a smaller example with the same property:
 # P2
 # 8 8
@@ -103,7 +96,9 @@ test_pgm=${tmpdir}/testimg.pgm
 # 3 6 3 7 4 5 4 6
 # 4 7 5 6 5 7 6 7
 
-maxval=63
+test257_pgm=${tmpdir}/testimg257.pgm
+
+maxval=15
 awk -v maxval=${maxval} 'BEGIN \
 { print "P2"
          print "1 "(maxval+1) * (maxval+1) +1
@@ -115,26 +110,25 @@ awk -v maxval=${maxval} 'BEGIN \
              for (j=i+1; j<=maxval; ++j)
                  {print i; print j }
          print 0
-}' > ${test4097_pgm}
+}' >  ${test257_pgm}
 
-for size in 4030 4031 4097
+for size in 238 239 240 241 255 256 257
   do
-  pamcut -height ${size} ${test4097_pgm} > ${test_pgm} &&
+  pamcut -height=${size} ${test257_pgm} > ${test_pgm} &&
   pamtogif -verbose ${test_pgm} | giftopnm | pamdepth ${maxval} | \
     cmp - ${test_pgm}
-  # pamdepth ${maxval} is necessary because
-  # giftopnm output is maxval 255
-  echo -n ${size} ":" ${PIPESTATUS[@]} ":" $? ", "
-  pamtogif -nolzw ${test_pgm} | giftopnm | pamdepth ${maxval} | \
+  printf "${size} : ${PIPESTATUS[*]} : $? , "
+  pamtogif -nolzw -verbose ${test_pgm} | giftopnm | pamdepth ${maxval} | \
     cmp - ${test_pgm}
-  echo ${size} ":" ${PIPESTATUS[@]} ":" $?
+  printf "${size} : ${PIPESTATUS[*]} : $?\n"
   rm ${test_pgm}
   done 
 
-rm ${test4097_pgm}
-test257_pgm=${tmpdir}/testimg257.pgm
+rm ${test257_pgm}
 
-maxval=15
+test4097_pgm=${tmpdir}/testimg4097.pgm
+
+maxval=63
 awk -v maxval=${maxval} 'BEGIN \
 { print "P2"
          print "1 "(maxval+1) * (maxval+1) +1
@@ -146,18 +140,20 @@ awk -v maxval=${maxval} 'BEGIN \
              for (j=i+1; j<=maxval; ++j)
                  {print i; print j }
          print 0
-}' >  ${test257_pgm}
+}' > ${test4097_pgm}
 
-for size in 238 239 240 241 255 256 257
+for size in 4030 4031 4097
   do
-  pamcut -height=${size} ${test257_pgm} > ${test_pgm} &&
+  pamcut -height ${size} ${test4097_pgm} > ${test_pgm} &&
   pamtogif -verbose ${test_pgm} | giftopnm | pamdepth ${maxval} | \
     cmp - ${test_pgm}
-  echo -n ${size} ":" ${PIPESTATUS[@]} ":" $? ", "
-  pamtogif -nolzw -verbose ${test_pgm} | giftopnm | pamdepth ${maxval} | \
+  # pamdepth ${maxval} is necessary because
+  # giftopnm output is maxval 255
+  printf "${size} : ${PIPESTATUS[*]} : $? , "
+  pamtogif -nolzw ${test_pgm} | giftopnm | pamdepth ${maxval} | \
     cmp - ${test_pgm}
-  echo ${size} ":" ${PIPESTATUS[@]} ":" $?
+  printf "${size} : ${PIPESTATUS[*]} : $?\n"
   rm ${test_pgm}
   done 
 
-rm ${test257_pgm}
+rm ${test4097_pgm}
diff --git a/test/gif-transparent1.ok b/test/gif-transparent1.ok
new file mode 100644
index 00000000..a531329a
--- /dev/null
+++ b/test/gif-transparent1.ok
@@ -0,0 +1,99 @@
+Test 0.
+Should print 0 or 1 0.
+Image 1: 1 0
+Image 2: 1 0
+Image 3: 0
+Image 4: 0
+Image 5: 0
+Test 1.
+Should print 0 unless otherwise stated.
+Image 1
+a1: 1 (should print 1)
+a2: 0
+a3: 0
+b1: 1 (should print 1)
+b2: 0
+b3: 0
+c1: 0
+c2: 0
+c3: 0
+c4: 0
+d1: 0
+d2: 0
+Image 2
+a1: 1 (should print 1)
+a2: 0
+a3: 0
+b1: 1 (should print 1)
+b2: 0
+b3: 0
+c1: 0
+c2: 0
+c3: 0
+c4: 0
+d1: 0
+d2: 0
+Image 3
+a1: 1 (should print 1)
+a2: 0
+a3: 0
+b1: 1 (should print 1)
+b2: 0
+b3: 0
+c1: 0
+c2: 0
+c3: 0
+c4: 0
+d1: 0
+d2: 0
+Test 2.
+Should print 0 unless otherwise stated.
+Image 1
+cl1: 0
+cl2: 0
+op1: 1 (should print 1)
+op2: 0
+Image 2
+cl1: 0
+cl2: 0
+op1: 1 (should print 1)
+op2: 0
+Image 3
+cl1: 0
+cl2: 0
+op1: 1 (should print 1)
+op2: 0
+Test 3.
+Should print 0 in all cases.
+Image 1
+a2: 0
+a3: 0
+b2: 0
+b3: 0
+c4: 0
+Image 2
+a2: 0
+a3: 0
+b2: 0
+b3: 0
+c4: 0
+Image 3
+a2: 0
+a3: 0
+b2: 0
+b3: 0
+c4: 0
+Test 4.
+Should print 0 in all cases.
+color=rgb:0f/0f/0f
+0
+0
+0
+color=rgb:ff/00/00
+0
+0
+0
+color=rgb:00/ff/00
+0
+0
+0
diff --git a/test/gif-transparent1.test b/test/gif-transparent1.test
new file mode 100755
index 00000000..74496787
--- /dev/null
+++ b/test/gif-transparent1.test
@@ -0,0 +1,224 @@
+#! /bin/sh
+# This script tests: giftopnm pamtogif ppmtogif
+# Also requires: pamarith pamcomp pamdepth pamenlarge pamstack pbmmake
+# Also requires: pnminvert ppmchange ppmpat ppmtopgm ppmtoppm 
+
+tmpdir=${tmpdir:-/tmp}
+
+madras_ppm=${tmpdir}/madras.ppm
+gingham_ppm=${tmpdir}/gingham.ppm
+argyle_ppm=${tmpdir}/argyle.ppm
+
+alpha0_pbm=${tmpdir}/alpha0.pbm
+alpha1_pbm=${tmpdir}/alpha1.pbm
+clear_pbm=${tmpdir}/clear.pbm
+opaque_pbm=${tmpdir}/opaque.pbm
+alpha0_pam=${tmpdir}/alpha0.pam
+alpha1_pam=${tmpdir}/alpha1.pam
+clear_pam=${tmpdir}/clear.pam
+opaque_pam=${tmpdir}/opaque.pam
+
+image0_alpha_pam=${tmpdir}/image0.alpha.pam
+image1_alpha_pam=${tmpdir}/image1.alpha.pam
+
+out_pnm=${tmpdir}/out.pnm
+out0_ppm=${tmpdir}/out0.ppm
+out1_ppm=${tmpdir}/out1.ppm
+out2_ppm=${tmpdir}/out2.ppm
+a0_out_pbm=${tmpdir}/a0.out.pbm
+a1_out_pbm=${tmpdir}/a1.out.pbm
+
+# Make test images & alpha masks
+
+ppmpat -argyle2 \
+  -color=rgb:00/00/00,rgb:ff/ff/ff,rgb:ff/ff/ff 40 24 > ${argyle_ppm}
+ppmpat -gingham3 \
+  -color=rgb:3f/3f/3f,rgb:7f/7f/7f,rgb:ef/ef/ef 40 24 > ${gingham_ppm}
+ppmpat -madras \
+       -color=rgb:0f/0f/0f,rgb:ff/00/00,rgb:00/ff/00 40 24 > ${madras_ppm}
+
+pbmmake -g 5 3 | pamenlarge 8 | tee ${alpha0_pbm} | \
+  pamdepth 255 > ${alpha0_pam}
+pnminvert ${alpha0_pbm} | tee ${alpha1_pbm} | \
+  pamdepth 255 > ${alpha1_pam}
+
+pbmmake -w 40 24 | tee ${clear_pbm} | pamdepth 255 > ${clear_pam}
+pbmmake -b 40 24 | tee ${opaque_pbm} | pamdepth 255 > ${opaque_pam}
+
+
+echo "Test 0."
+echo "Should print 0 or 1 0."
+i=1
+for test_pnm in ${argyle_ppm} ${gingham_ppm} ${madras_ppm} \
+			      ${alpha0_pbm} ${alpha1_pbm}
+  do
+  printf "Image $i: "; i=$((i+1));
+  pamtogif ${test_pnm} | giftopnm | tee ${out_pnm} | \
+    cmp -s - ${test_pnm}; result=$?
+
+  if [ $result -eq 0 ];
+    then echo $?;
+  else
+    ppmtoppm < ${out_pnm} | cmp -s - ${test_pnm}; echo $result $?
+  fi
+  # madras, alpha, alpha1 : should match
+  # argyle: giftopnm produces PBM, gingham: giftopnm produces PGM
+  rm ${out_pnm}
+  done
+
+
+echo "Test 1."  # Color + alpha channel
+echo "Should print 0 unless otherwise stated."
+
+i=1
+for test_pnm in  ${argyle_ppm} ${gingham_ppm} ${madras_ppm}
+  do
+  echo "Image $i"; i=$((i+1));
+
+  pamstack -tupletype="RGB_ALPHA" ${test_pnm} ${alpha0_pam} > \
+    ${image0_alpha_pam}
+  pamstack -tupletype="RGB_ALPHA" ${test_pnm} ${alpha1_pam} > \
+    ${image1_alpha_pam}
+
+  pamtogif ${image0_alpha_pam} | giftopnm -alphaout=${a0_out_pbm} | \
+    ppmtoppm | tee ${out0_ppm} | \
+    cmp -s - ${test_pnm}; echo "a1:" $? "(should print 1)"
+  cmp -s ${alpha0_pbm} ${a0_out_pbm}; echo "a2:" $?  # Should match
+
+  pamarith -multiply ${test_pnm} ${alpha0_pbm} | \
+    cmp -s - ${out0_ppm}; echo "a3:" $? # Should match
+
+  pamtogif ${image1_alpha_pam} | giftopnm -alphaout=${a1_out_pbm} | \
+    ppmtoppm | tee ${out1_ppm} | \
+    cmp -s - ${test_pnm}; echo "b1:" $? "(should print 1)"
+
+  cmp -s ${alpha1_pbm} ${a1_out_pbm}; echo "b2:" $?  # Should match
+
+  pamarith -multiply ${test_pnm} ${alpha1_pam} | \
+    cmp -s - ${out1_ppm}; echo "b3:" $?    # Should match
+
+  pamarith -multiply ${test_pnm} ${alpha0_pbm} | \
+    cmp -s - ${out0_ppm}; echo "c1:" $?    # Should match
+
+  pamarith -multiply ${test_pnm} ${alpha1_pbm} | \
+    cmp -s - ${out1_ppm}; echo "c2:" $?    # Should match
+
+  pamcomp -alpha=${alpha0_pbm} ${out0_ppm} ${out1_ppm} | \
+    cmp -s - ${test_pnm}; echo "c3:" $?    # Should match
+
+  pamcomp -alpha=${alpha1_pbm} ${out1_ppm} ${out0_ppm} | \
+    cmp -s - ${test_pnm}; echo "c4:" $?    # Should match
+
+  pamtogif ${image0_alpha_pam} -alphacolor=rgb:00/00/80 | \
+    giftopnm  -alphaout=${a0_out_pbm} > /dev/null
+    cmp -s ${a0_out_pbm} ${alpha0_pbm}; echo "d1:" $?    # Should match
+
+  pamtogif ${image0_alpha_pam} -alphacolor=rgb:00/00/80 | \
+    giftopnm | ppmtoppm | \
+    ppmchange rgb:00/00/80 rgb:00/00/00 -remainder=rgb:ff/ff/ff | \
+    ppmtopgm | \
+    cmp -s - ${alpha0_pam}; echo "d2:" $?    # Should match
+
+  rm ${image0_alpha_pam} ${image1_alpha_pam}
+  rm ${out0_ppm} ${out1_ppm} # ${out0_pnm} ${out1_pnm}
+  rm ${a0_out_pbm} ${a1_out_pbm}
+
+  done
+
+echo "Test 2."  # clear/opaque alpha channel
+echo "Should print 0 unless otherwise stated."
+
+i=1
+for test_pnm in  ${argyle_ppm} ${gingham_ppm} ${madras_ppm}
+  do
+  echo "Image $i"; i=$((i+1));
+
+  pamstack -tupletype="RGB_ALPHA" ${test_pnm} ${clear_pam} > \
+    ${image0_alpha_pam}
+  pamstack -tupletype="RGB_ALPHA" ${test_pnm} ${opaque_pam} > \
+    ${image1_alpha_pam}
+
+  # clear
+  pamtogif ${image0_alpha_pam} | giftopnm -alphaout=${a0_out_pbm} | \
+    ppmtoppm | tee ${out0_ppm} | \
+    cmp -s - ${test_pnm}; echo "cl1:" $? # Should match
+  cmp -s ${clear_pbm} ${a0_out_pbm}; echo "cl2:" $?  # Should match
+
+  # opaque
+  pamtogif ${image1_alpha_pam} | giftopnm -alphaout=${a1_out_pbm} | \
+    tee ${out1_ppm} | \
+    cmp -s - ${test_pnm}; echo "op1:" $? "(should print 1)"
+
+  cmp -s ${opaque_pbm} ${a1_out_pbm}; echo "op2:" $?  # Should match
+
+  rm ${image0_alpha_pam} ${image1_alpha_pam}
+  rm ${out0_ppm} ${out1_ppm}
+  rm ${a0_out_pbm} ${a1_out_pbm}
+
+  done
+
+rm ${clear_pbm} ${clear_pam} ${opaque_pbm} ${opaque_pam}
+
+
+echo "Test 3."  # ppmtogif
+echo "Should print 0 in all cases."
+
+i=1
+for test_pnm in  ${argyle_ppm} ${gingham_ppm} ${madras_ppm}
+  do
+  echo "Image $i"; i=$((i+1));
+
+  ppmtogif -alpha=${alpha0_pbm} ${test_pnm} | \
+    giftopnm -alphaout=${a0_out_pbm} | \
+    ppmtoppm > ${out0_ppm}
+    cmp -s ${alpha0_pbm} ${a0_out_pbm}; echo "a2:" $?  # Should match
+  pamarith -multiply ${test_pnm} ${alpha0_pbm} | \
+    cmp -s - ${out0_ppm}; echo "a3:" $? # Should match
+
+  ppmtogif -alpha=${alpha1_pbm} ${test_pnm} | \
+    giftopnm -alphaout=${a1_out_pbm} | \
+    ppmtoppm > ${out1_ppm}
+    cmp -s ${alpha1_pbm} ${a1_out_pbm}; echo "b2:" $?  # Should match
+  pamarith -multiply ${test_pnm} ${alpha1_pam} | \
+    cmp -s - ${out1_ppm}; echo "b3:" $?    # Should match
+
+  pamcomp -alpha=${alpha1_pbm} ${out1_ppm} ${out0_ppm} | \
+    cmp -s - ${test_pnm}; echo "c4:" $?    # Should match
+
+  rm ${out0_ppm} ${out1_ppm}
+  rm ${a0_out_pbm} ${a1_out_pbm}
+
+  done
+
+rm ${alpha0_pbm} ${alpha1_pbm}
+rm ${alpha0_pam} ${alpha1_pam}
+rm ${argyle_ppm} ${gingham_ppm}
+
+
+echo "Test 4."
+echo "Should print 0 in all cases."
+# no separate alpha channel
+# designate colors which appear in madras as transparent 
+
+for color in "0f/0f/0f" "ff/00/00" "00/ff/00"
+  do
+  echo "color=rgb:"${color}
+  pamtogif -transparent=rgb:${color} ${madras_ppm} | \
+    giftopnm -alphaout=${a0_out_pbm} > ${out0_ppm}
+    cmp -s ${madras_ppm} ${out0_ppm}; echo $?   # Should match 
+
+  pbmmake -g 40 24 | pamdepth 255 | pamstack ${madras_ppm} - | 
+  pamtogif -transparent=rgb:${color} - | \
+    giftopnm -alphaout=${a1_out_pbm} > ${out1_ppm}
+    cmp -s ${madras_ppm} ${out1_ppm}; echo $?   # Should match 
+
+  ppmchange rgb:${color} rgb:00/00/00 \
+    -remainder=rgb:ff/ff/ff ${madras_ppm} > ${out2_ppm}
+
+  ppmtoppm < ${a0_out_pbm} | \
+    cmp -s ${out2_ppm} -; echo $?   # Should match 
+
+  rm ${out0_ppm} ${out1_ppm} ${out2_ppm} ${a0_out_pbm} ${a1_out_pbm}
+  done
+
+rm ${madras_ppm} 
diff --git a/test/hdiff-roundtrip.test b/test/hdiff-roundtrip.test
index a4a4a906..ec7afc2c 100755
--- a/test/hdiff-roundtrip.test
+++ b/test/hdiff-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: hdifftopam pamtohdiff
 # Also requires:
 
diff --git a/test/ilbm-roundtrip.ok b/test/ilbm-roundtrip.ok
index 54574a18..2d6fcff0 100644
--- a/test/ilbm-roundtrip.ok
+++ b/test/ilbm-roundtrip.ok
@@ -1,10 +1,18 @@
-829921912 685
-829921912 685
-829921912 685
-829921912 685
+Test 1.  Should produce 669206373 10102 four times
+669206373 10102
+669206373 10102
+669206373 10102
+669206373 10102
+Test 2.  Should produce 1926073387 101484 three times
 1926073387 101484
 1926073387 101484
 1926073387 101484
+Test 3.  Should print 984199586 101484
 984199586 101484
+Test 4.  Should print 2059976475 661 three times
 2059976475 661
 2059976475 661
+2059976475 661
+Test 5.  Should print 482756572 101484 twice
+482756572 101484
+482756572 101484
diff --git a/test/ilbm-roundtrip.test b/test/ilbm-roundtrip.test
index f62368ff..3d7d63ef 100755
--- a/test/ilbm-roundtrip.test
+++ b/test/ilbm-roundtrip.test
@@ -1,28 +1,58 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmtoilbm ilbmtoppm
-# Also requires: pamseq pamdepth pamtopnm pnmremap
+# Also requires: pamseq pamdepth pamtopnm pnmremap pnmcolormap
 
-#Test. 1  Should produce 829921912 685 four times
-#Output is PPM raw, 14 by 16  maxval 255
-ppmtoilbm testgrid.pbm | ilbmtoppm | cksum
-ppmtoilbm -aga testgrid.pbm | ilbmtoppm | cksum
-ppmtoilbm -ham6 testgrid.pbm | ilbmtoppm | cksum
-ppmtoilbm -ham8 testgrid.pbm | ilbmtoppm | cksum
+echo "Test 1.  Should produce 669206373 10102 four times"
+#Output is PPM raw, 57 by 59  maxval 255
 
+ppmtoilbm maze.pbm | ilbmtoppm | cksum
+ppmtoilbm -aga maze.pbm | ilbmtoppm | cksum
+ppmtoilbm -ham6 maze.pbm | ilbmtoppm | cksum
+ppmtoilbm -ham8 maze.pbm | ilbmtoppm | cksum
 
-#Test. 2  Should produce 1926073387 101484 three times
+
+echo "Test 2.  Should produce 1926073387 101484 three times"
 ppmtoilbm testimg.ppm | ilbmtoppm | cksum
 ppmtoilbm -24force testimg.ppm | ilbmtoppm | cksum
 ppmtoilbm -dcbits 8 8 8 -nocompress testimg.ppm | ilbmtoppm | cksum
 
+tmpdir=${tmpdir:-/tmp}
 
-#Test. 3  Should print 984199586 101484
-pamseq 3 5 -tupletype=RGB | pamdepth 255 | pamtopnm | \
+echo "Test 3.  Should print 984199586 101484"
+test_ppm=${tmpdir}/test.ppm
+pamseq 3 5 -tupletype=RGB | pamdepth 255 | pamtopnm | tee ${test_ppm} | \
   pnmremap -mapfile=- testimg.ppm | ppmtoilbm | ilbmtoppm | cksum
 
 
-#Test. 4 Should print 2059976475 661 twice
-pamseq 3 5 -tupletype=RGB | pamtopnm | \
-  ppmtoilbm -compress | ilbmtoppm | cksum
-pamseq 3 5 -tupletype=RGB | pamtopnm | \
-  ppmtoilbm -nocompress | ilbmtoppm | cksum
+echo "Test 4.  Should print 2059976475 661 three times"
+cat ${test_ppm} | cksum
+ppmtoilbm -compress ${test_ppm} | ilbmtoppm | cksum
+ppmtoilbm -nocompress ${test_ppm} | ilbmtoppm | cksum
+
+rm ${test_ppm}
+
+echo "Test 5.  Should print 482756572 101484 twice"
+mapfile=${tmpdir}/mapfile
+
+# The following was produced by running "pnmcolormap -plain 32 testimg.ppm"
+# We use a prefabricated mapfile because pnmcolormap is known to
+# produce slightly different output on different systems.
+
+cat > ${mapfile} << EOF
+P3
+32 1
+255
+106 82 80 46 43 34 128 62 46 189 68 63 209 41 43 209 65 46 241 62 72
+ 240 189 195 
+122 142 103 92 131 68 159 129 188 177 205 195 96 132 107 193 150 107
+ 242 253 238 241 73 108 
+121 75 67 182 67 47 98 88 48 237 36 47 66 45 42 68 84 43 182 45 41
+ 70 77 67 
+96 45 45 237 62 47 150 59 41 189 76 103 48 69 31 52 68 52 48 45 51
+ 105 80 130 
+EOF
+
+ppmtoilbm -map ${mapfile} testimg.ppm | ilbmtoppm | tee ${test_ppm} | cksum
+ppmtoilbm -map ${mapfile} ${test_ppm} | ilbmtoppm | cksum
+
+rm ${mapfile} ${test_ppm}
diff --git a/test/jbig-roundtrip.ok b/test/jbig-roundtrip.ok
index b98a694b..c9164120 100644
--- a/test/jbig-roundtrip.ok
+++ b/test/jbig-roundtrip.ok
@@ -1,2 +1,2 @@
-2425386270 41
+281226646 481
 1571496937 33838
diff --git a/test/jbig-roundtrip.test b/test/jbig-roundtrip.test
index 570d7336..11cd1778 100755
--- a/test/jbig-roundtrip.test
+++ b/test/jbig-roundtrip.test
@@ -1,9 +1,9 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pnmtojbig jbigtopnm
 # Also requires: pamchannel pamtopnm
 
-# Test 1.  Should print 2425386270 41
-pnmtojbig testgrid.pbm | jbigtopnm | cksum
+# Test 1.  Should print 281226646 481
+pnmtojbig maze.pbm | jbigtopnm | cksum
 
 # Test 2.  Should print 1571496937 33838
 pamchannel -infile=testimg.ppm -tupletype="GRAYSCALE" 0 | pamtopnm | \
diff --git a/test/jpeg-roundtrip.test b/test/jpeg-roundtrip.test
index 7cc0fc20..834c02e5 100755
--- a/test/jpeg-roundtrip.test
+++ b/test/jpeg-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pnmtojpeg jpegtopnm
 # Also requires: pnmpsnr
 
diff --git a/test/jpeg2k-roundtrip.test b/test/jpeg2k-roundtrip.test
index 0995849d..4a09201d 100755
--- a/test/jpeg2k-roundtrip.test
+++ b/test/jpeg2k-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamtojpeg2k jpeg2ktopam
 # Also requires:
 
diff --git a/test/leaf-roundtrip.test b/test/leaf-roundtrip.test
index 5628ed01..94b31092 100755
--- a/test/leaf-roundtrip.test
+++ b/test/leaf-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmtoleaf leaftoppm
 # Also requires:
 
diff --git a/test/legacy-names.ok b/test/legacy-names.ok
index 94ef875f..f491a1ff 100644
--- a/test/legacy-names.ok
+++ b/test/legacy-names.ok
@@ -12,6 +12,7 @@ pgmoil: ok
 pgmslice: ok
 pngtopnm: ok
 pnmarith: ok
+pnmcat: ok
 pnmcomp: ok
 pnmcut: ok
 pnmdepth: ok
@@ -26,14 +27,16 @@ pnmtofits: ok
 pnmtoplainpnm: ok
 pnmtopnm: ok
 pnmtotiff: ok
+ppmbrighten: ok
+ppmcolors: ok
 ppmnorm: ok
 ppmquant: ok
 ppmquantall: ok
 ppmtogif: ok
 ppmtojpeg: ok
 ppmtomap: ok
-ppmtompeg: ok
 ppmtotga: ok
 ppmtouil: ok
 hpcdtoppm: ok
 pcdovtoppm: ok
+pcdindex: ok
diff --git a/test/legacy-names.test b/test/legacy-names.test
index 5a65615f..9c0c5697 100755
--- a/test/legacy-names.test
+++ b/test/legacy-names.test
@@ -69,6 +69,7 @@ ordinary_testprogs="\
   pgmslice \
   pngtopnm \
   pnmarith \
+  pnmcat \
   pnmcomp \
   pnmcut \
   pnmdepth \
@@ -83,13 +84,14 @@ ordinary_testprogs="\
   pnmtoplainpnm \
   pnmtopnm \
   pnmtotiff \
+  ppmbrighten \
+  ppmcolors \
   ppmnorm \
   ppmquant \
   ppmquantall \
   ppmtogif \
   ppmtojpeg \
   ppmtomap \
-  ppmtompeg \
   ppmtotga \
   ppmtouil \
 "
@@ -125,10 +127,13 @@ for i in $ordinary_testprogs
 
 
 
-# Test hpcdtoppm and pcdovtoppm.  Simply confirm their existence.
+# Test hpcdtoppm, pcdovtoppm and pcdindex.  Simply confirm their existence.
 
 type -p hpcdtoppm > /dev/null
 testExitStatus hpcdtoppm 0 $?
 
 type -p pcdovtoppm > /dev/null
 testExitStatus pcdovtoppm 0 $?
+
+type -p pcdindex > /dev/null
+testExitStatus pcdindex 0 $?
diff --git a/test/lookup-roundtrip.test b/test/lookup-roundtrip.test
index 63ec0777..19ebd40a 100755
--- a/test/lookup-roundtrip.test
+++ b/test/lookup-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamlookup pamunlookup
 # Also requires: ppmhist
 
@@ -10,3 +10,5 @@ ppmhist testimg.ppm -map > ${mapfile}
 # Test.  Should produce 1926073387 101484
 pamunlookup -lookupfile=${mapfile} testimg.ppm |\
   pamlookup -lookupfile=${mapfile} | cksum
+
+rm ${mapfile}
\ No newline at end of file
diff --git a/test/lps-roundtrip.ok b/test/lps-roundtrip.ok
new file mode 100644
index 00000000..c2c8ab3b
--- /dev/null
+++ b/test/lps-roundtrip.ok
@@ -0,0 +1,4 @@
+Test 1.  Should print match
+match
+Test 2.  Should print 0
+0
diff --git a/test/lps-roundtrip.test b/test/lps-roundtrip.test
new file mode 100755
index 00000000..24076ef1
--- /dev/null
+++ b/test/lps-roundtrip.test
@@ -0,0 +1,33 @@
+#! /bin/sh
+# This script tests: pbmtolps pstopnm
+# Also requires: gs pamdepth pamscale pnmcrop pnmpsnr pamfile
+
+# The ordinary round-trip does not work because of the way ghostscript
+# renders: a line is considered wider than a single pixel and all pixels
+# it touches are set to black if the output is PBM.  To work around this,
+# we tell pstopnm to output PGM at a high resolution (=large dpi value).
+
+tmpdir=${tmpdir:-/tmp}
+test_pgm=${tmpdir}/test.pgm
+test_ps=${tmpdir}/test.ps
+
+echo "Test 1.  Should print match"
+
+xysize=$(pamfile -size testgrid.pbm | awk '{print "-xsize="$1,"-ysize="$2}')
+pamdepth 255 testgrid.pbm > ${test_pgm}
+  
+pbmtolps -dpi 72 testgrid.pbm | tee ${test_ps} | \
+    pstopnm -dpi $((72*12)) -stdout -pgm | \
+    pnmcrop -white | pamscale ${xysize}  | \
+    pnmpsnr -target=30 - ${test_pgm}
+
+    # ghostscript version 8.71: pnmpsnr lumina 33.14dB
+
+
+echo "Test 2.  Should print 0"
+
+pbmtolps -dpi 72 < testgrid.pbm | sed 's/noname/testgrid.pbm/' | \
+    cmp -s ${test_ps} -
+    echo $?
+  
+rm ${test_pgm} ${test_ps}
diff --git a/test/macp-roundtrip.ok b/test/macp-roundtrip.ok
index 9ff9d249..28c16ee0 100644
--- a/test/macp-roundtrip.ok
+++ b/test/macp-roundtrip.ok
@@ -1,5 +1,14 @@
-2425386270 41
-2425386270 41
+Test 1. Should produce 281226646 481 twice
+281226646 481
+281226646 481
+Test 2. Should produce 2329957971 51851
 2329957971 51851
+Test 3. Should produce 2907103393 5086 three times
 2907103393 5086
 2907103393 5086
+2907103393 5086
+Test 4. Should produce 3432623660 51851 four times
+3432623660 51851
+3432623660 51851
+3432623660 51851
+3432623660 51851
diff --git a/test/macp-roundtrip.test b/test/macp-roundtrip.test
index 4774a2c2..9def7c4c 100755
--- a/test/macp-roundtrip.test
+++ b/test/macp-roundtrip.test
@@ -1,31 +1,51 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pbmtomacp macptopbm
-# Also requires: pnmcrop pbmpage pbmupc pnmpad
+# Also requires: pnmcrop pbmpage pbmupc pnmpad pbmmake
 
 tmpdir=${tmpdir:-/tmp}
-temp1_pbm=${tmpdir}/temp1.ppm
-temp2_pbm=${tmpdir}/temp2.ppm
+temp1_pbm=${tmpdir}/temp1.pbm
+temp2_pbm=${tmpdir}/temp2.pbm
+tempupc_pbm=${tmpdir}/tempupc.pbm
+temp3_pbm=${tmpdir}/temp3.pbm
+temp3_macp=${tmpdir}/temp3.macp
 
-
-# Test 1. Should produce 2425386270 41 twice
-# Because Macpaint files are fixed size (576 x 720 pixels)
+# Macpaint files are fixed size (576 x 720 pixels)
 # pbmtomacp automatically adds padding when input is smaller.
 
-pbmtomacp testgrid.pbm | macptopbm | tee ${temp1_pbm} | \
+echo "Test 1. Should produce 281226646 481 twice"
+pbmtomacp maze.pbm | macptopbm | tee ${temp1_pbm} | \
     pnmcrop | cksum
 
 pbmtomacp ${temp1_pbm} | macptopbm | pnmcrop | cksum
 
+rm ${temp1_pbm}
 
-#Test 2. Should produce 2329957971 51851
+echo "Test 2. Should produce 2329957971 51851"
 pbmpage 1 | pbmtomacp | macptopbm | cksum
 
-
-#Test 3. Should produce 2907103393 5086 twice
-pbmupc 0 12345 67890 | pnmpad -black -t 44 -b 20 -l 100 -r 251 | pbmtomacp | macptopbm | \
+echo "Test 3. Should produce 2907103393 5086 three times"
+pbmupc 0 12345 67890 | tee ${tempupc_pbm} | \
+    pnmpad -black -t 44 -b 20 -l 100 -r 251 | \
+    pbmtomacp | macptopbm | \
     tee ${temp2_pbm} | \
     pnmcrop | pnmcrop | cksum
 
+pnmpad -black -t 44 -l 100 ${tempupc_pbm} | \
+    pbmtomacp|  macptopbm | pnmcrop -white | pnmcrop | cksum
+
 pbmtomacp ${temp2_pbm} | macptopbm | pnmcrop | pnmcrop | cksum
 
-rm ${temp1_pbm} ${temp2_pbm}
+rm ${temp2_pbm} ${tempupc_pbm}
+
+
+echo "Test 4. Should produce 3432623660 51851 four times"
+pbmmake -b 576 720 | tee ${temp3_pbm} | cksum
+
+pbmtomacp ${temp3_pbm} | tee ${temp3_macp} | macptopbm | cksum
+
+pbmtomacp -norle ${temp3_pbm} | macptopbm | cksum
+
+( head -c 128 /dev/zero ; cat ${temp3_macp} ) | \
+    macptopbm -extraskip 128 | cksum
+
+rm ${temp3_pbm} ${temp3_macp}
diff --git a/test/maze.pbm b/test/maze.pbm
new file mode 100644
index 00000000..9bdd80e1
--- /dev/null
+++ b/test/maze.pbm
Binary files differdiff --git a/test/mda-roundtrip.ok b/test/mda-roundtrip.ok
index ef27ffd0..ab449885 100644
--- a/test/mda-roundtrip.ok
+++ b/test/mda-roundtrip.ok
@@ -1,2 +1,5 @@
+Test 1.  Should print 1757803444 169 twice
 1757803444 169
-2425386270 41
+1757803444 169
+Test 2.  Should print 281226646 481
+281226646 481
diff --git a/test/mda-roundtrip.test b/test/mda-roundtrip.test
index 58376f3f..c47d433e 100755
--- a/test/mda-roundtrip.test
+++ b/test/mda-roundtrip.test
@@ -1,13 +1,15 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pbmtomda mdatopbm
-# Also requires: pbmmake pnmpad pamcut
+# Also requires: pbmmake pnmpad pamcut pamfile
 
 
 # Pbmtomda requires input width and height to be multiples of 8.
 
-# Test 1.  Should print 1757803444 169
+echo "Test 1.  Should print 1757803444 169 twice"
+pbmmake -g 32 40 | cksum
 pbmmake -g 32 40 | pbmtomda | mdatopbm | cksum
 
-# Test 2.  Should print 2425386270 41
-pnmpad -right 2 testgrid.pbm | \
-  pbmtomda | mdatopbm | pamcut 0 0 14 16 | cksum
+echo "Test 2.  Should print 281226646 481"
+size=$(pamfile -size maze.pbm | awk '{print "-width="$1,"-height="$2}')
+pnmpad -mwidth=8 -halign=0 -mheight=8 -valign=0 ${size} maze.pbm | \
+    pbmtomda | mdatopbm | pamcut -left=0 -top=0 ${size} | cksum
diff --git a/test/mgr-roundtrip.ok b/test/mgr-roundtrip.ok
index 845be5fb..0e845958 100644
--- a/test/mgr-roundtrip.ok
+++ b/test/mgr-roundtrip.ok
@@ -1 +1,7 @@
-2425386270 41
+Test 1.  Should print 281226646 481
+281226646 481
+Test 2.  Should print 429369764 1034, 448060073 4105 twice each
+429369764 1034
+429369764 1034
+448060073 4105
+448060073 4105
diff --git a/test/mgr-roundtrip.test b/test/mgr-roundtrip.test
index 252ae996..9fb6211c 100755
--- a/test/mgr-roundtrip.test
+++ b/test/mgr-roundtrip.test
@@ -1,7 +1,15 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pbmtomgr mgrtopbm
-# Also requires:
+# Also requires: pbmmake
 
+echo "Test 1.  Should print 281226646 481"
+pbmtomgr maze.pbm | mgrtopbm | cksum
+
+echo "Test 2.  Should print 429369764 1034, 448060073 4105 twice each"
+# Maximum width and height allowed
+
+pbmmake -g 4095 2 | cksum
+pbmmake -g 4095 2 | pbmtomgr | mgrtopbm | cksum
+pbmmake -g 1 4095 | cksum
+pbmmake -g 1 4095 | pbmtomgr | mgrtopbm | cksum
 
-# Should print 2425386270 41, cksum of testgrid.pbm
-pbmtomgr testgrid.pbm | mgrtopbm | cksum
diff --git a/test/mrf-roundtrip.ok b/test/mrf-roundtrip.ok
index 845be5fb..5168378d 100644
--- a/test/mrf-roundtrip.ok
+++ b/test/mrf-roundtrip.ok
@@ -1 +1 @@
-2425386270 41
+281226646 481
diff --git a/test/mrf-roundtrip.test b/test/mrf-roundtrip.test
index c9d8ce3a..5ce604e6 100755
--- a/test/mrf-roundtrip.test
+++ b/test/mrf-roundtrip.test
@@ -1,7 +1,7 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pbmtomrf mrftopbm
 # Also requires:
 
 
-# Should print 2425386270 41, cksum of testgrid.pbm
-pbmtomrf testgrid.pbm | mrftopbm | cksum
+# Should print 281226646 481, cksum of maze.pbm
+pbmtomrf maze.pbm | mrftopbm | cksum
diff --git a/test/pad-crop-roundtrip.ok b/test/pad-crop-roundtrip.ok
index 67f7a1fe..764cadfa 100644
--- a/test/pad-crop-roundtrip.ok
+++ b/test/pad-crop-roundtrip.ok
@@ -1,2 +1,4 @@
 1926073387 101484
-2425386270 41
+1926073387 101484
+281226646 481
+281226646 481
diff --git a/test/pad-crop-roundtrip.test b/test/pad-crop-roundtrip.test
index c7780d68..31e02c99 100755
--- a/test/pad-crop-roundtrip.test
+++ b/test/pad-crop-roundtrip.test
@@ -1,9 +1,26 @@
-#! /bin/bash
-# This script tests: pnmcrop pnmmargin
-# Also requires: pnmpad
+#! /bin/sh
+# This script tests: pnmcrop pnmmargin pnmpad
+# Also requires:
 
+# Test 1. Should produce 1926073387 101484, cksum of testimg.ppm
 
 pnmmargin -white 10 testimg.ppm | \
   pnmcrop | cksum
-pnmmargin -white 10 testgrid.pbm | \
+
+# Test 2. Should produce 1926073387 101484
+
+pnmpad -white -left 10 -top 10 testimg.ppm | \
+  pnmpad -white -right 10 -bottom 10 | \
+  pnmcrop -right -bottom | pnmcrop -left -top | cksum
+
+# Test 3. Should produce 281226646 481, cksum of maze.pbm
+
+pnmmargin -white 10 maze.pbm | \
   pnmcrop | cksum
+
+# Test 4. Should produce 281226646 481
+
+pnmpad -white -left 10 -top 10 maze.pbm | \
+  pnmpad -white -right 10 -bottom 10 | \
+  pnmcrop -left -right | pnmcrop -top -bottom | cksum
+
diff --git a/test/palm-roundtrip.ok b/test/palm-roundtrip.ok
index b9ea3056..d69c3a96 100644
--- a/test/palm-roundtrip.ok
+++ b/test/palm-roundtrip.ok
@@ -1,10 +1,10 @@
-Test 1
-584219238 236
-584219238 236
-584219238 236
-584219238 236
-584219238 236
-Test 2
+Test 1. Should print 2067616594 3375 five times
+2067616594 3375
+2067616594 3375
+2067616594 3375
+2067616594 3375
+2067616594 3375
+Test 2. Should print 0 0 0  : 0 four times
 0 0 0 : 0
 0 0 0 : 0
 0 0 0 : 0
diff --git a/test/palm-roundtrip.test b/test/palm-roundtrip.test
index b00454ca..20fcefa9 100755
--- a/test/palm-roundtrip.test
+++ b/test/palm-roundtrip.test
@@ -6,11 +6,9 @@ tmpdir=${tmpdir:-/tmp}
 test4bit_pgm=${tmpdir}/test4bit.pgm
 test256color_ppm=${tmpdir}/test256color.ppm
 
-# Test 1. Should print 584219238 236  5 times
+echo "Test 1. Should print 2067616594 3375 five times"
 
-echo "Test 1"
-
-pamdepth 15 testgrid.pbm | tee ${test4bit_pgm} | cksum
+pamdepth 15 maze.pbm | tee ${test4bit_pgm} | cksum
 
 for flags in "" \
              "-scanline_compression" \
@@ -21,9 +19,7 @@ for flags in "" \
 rm ${test4bit_pgm}
 
 
-# Test 2. Should print 0 4 times
-
-echo "Test 2"
+echo "Test 2. Should print 0 0 0  : 0 four times"
 
 pnmquant 256 testimg.ppm > ${test256color_ppm} || echo "pnmquant failed"
 
diff --git a/test/palm-roundtrip2.test b/test/palm-roundtrip2.test
index 4c94df8c..f0c9b7c8 100755
--- a/test/palm-roundtrip2.test
+++ b/test/palm-roundtrip2.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pnmtopalm palmtopnm
 # Also requires: pnmremap
 
diff --git a/test/pamarith-compare-equal.ok b/test/pamarith-compare-equal.ok
new file mode 100644
index 00000000..d6b1f624
--- /dev/null
+++ b/test/pamarith-compare-equal.ok
@@ -0,0 +1,74 @@
+Test 1
+1:P3
+1:8 8
+1:2
+8:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 
+1:P3
+1:8 8
+1:2
+1:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 0 0 0 2 2 2 0 0 
+1:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 2 2 2 0 0 0 2 2 
+1:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 0 0 0 2 2 2 0 0 
+1:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 2 2 2 0 0 0 2 2 
+1:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 0 0 0 2 2 2 0 0 
+1:0 2 2 2 0 0 0 2 2 2 0 0 0 2 2 1 1 1 1 1 1 1 1 1 
+1:2 0 0 0 2 2 2 0 0 0 2 2 2 0 0 1 1 1 1 1 1 1 1 1 
+1:0 2 2 2 0 0 0 2 2 2 0 0 0 2 2 1 1 1 1 1 1 1 1 1 
+1:P3
+1:8 8
+1:2
+5:0 0 2 0 0 2 0 0 2 0 0 2 0 0 2 2 0 2 2 0 2 2 0 2 
+3:2 0 2 2 0 2 2 0 2 2 0 2 2 0 2 2 0 0 2 0 0 2 0 0 
+Test 2
+1:P3
+1:8 8
+1:1
+8:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 
+1:P3
+1:8 8
+1:1
+5:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 
+3:0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 
+1:P3
+1:8 8
+1:1
+8:0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+Test 3
+1:P1
+1:35 33
+33:00000000000000000000000000000000000
+1:P1
+1:35 33
+33:11111111111111111111111111111111111
+1:P1
+1:14 16
+8:10101010101010 11111111111111
+1:P1
+1:14 16
+8:01010101010101 00000000000000
+Test 4
+1:P2
+1:35 33
+1:2
+33:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 
+1:P2
+1:14 16
+1:2
+8:0 2 0 2 0 2 0 2 0 2 0 2 0 2  0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+1:P2
+1:14 16
+1:2
+8:0 1 0 1 0 1 0 1 0 1 0 1 0 1  0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+1:P2
+1:14 16
+1:2
+8:1 2 1 2 1 2 1 2 1 2 1 2 1 2  1 1 1 1 1 1 1 1 1 1 1 1 1 1 
+Test 5
+Should produce 1285449498 54 four times
+1285449498 54
+1285449498 54
+1285449498 54
+1285449498 54
+Should produce 244506188 54 twice
+244506188 54
+244506188 54
diff --git a/test/pamarith-compare-equal.test b/test/pamarith-compare-equal.test
new file mode 100755
index 00000000..7d1062b7
--- /dev/null
+++ b/test/pamarith-compare-equal.test
@@ -0,0 +1,92 @@
+#! /bin/sh
+# This script tests: pamarith
+# Also requires: ppmpat pnminvert pamfile pbmmake pgmmake pamcut
+
+tmpdir=${tmpdir:-/tmp}
+input1_ppm=${tmpdir}/input1.ppm
+inputm_ppm=${tmpdir}/inputm.ppm
+input2_ppm=${tmpdir}/input2.ppm
+
+echo "Test 1"
+
+ppmpat -tartan -color=rgb:00/80/ff,rgb:80/ff/00,rgb:ff/00/80 \
+   8 8  > ${input1_ppm}
+ppmpat -tartan -color=rgb:00/80/ff,rgb:80/ff/00,rgb:ff/00/80 \
+   -mesh 8 8  > ${inputm_ppm}
+ppmpat -tartan -color=rgb:80/ff/00,rgb:ff/00/80,rgb:00/80/ff \
+   8 8  > ${input2_ppm}
+
+pamarith -compare -plain ${input1_ppm} ${input1_ppm} | \
+  uniq -c | sed -e 's/^ *//' -e 's/ /:/'
+pamarith -compare -plain ${input1_ppm} ${inputm_ppm} | \
+  uniq -c | sed -e 's/^ *//' -e 's/ /:/'
+pamarith -compare -plain ${input1_ppm} ${input2_ppm} | \
+  uniq -c | sed -e 's/^ *//' -e 's/ /:/'
+
+echo "Test 2"
+
+pamarith -equal -plain ${input1_ppm} ${input1_ppm} | \
+  uniq -c | sed -e 's/^ *//' -e 's/ /:/'
+pamarith -equal -plain ${input1_ppm} ${inputm_ppm} | \
+  uniq -c | sed -e 's/^ *//' -e 's/ /:/'
+pamarith -equal -plain ${input1_ppm} ${input2_ppm} | \
+  uniq -c | sed -e 's/^ *//' -e 's/ /:/'
+
+rm ${input1_ppm} ${inputm_ppm} ${input2_ppm}
+
+echo "Test 3"
+
+input3_pbm=${tmpdir}/input3.pbm
+pamcut maze.pbm -left=0 -top=0 -width=35 -height=33 > ${input3_pbm} 
+
+pamarith -equal -plain ${input3_pbm} ${input3_pbm}  | \
+  uniq -c | sed -e 's/^ *//' -e 's/ /:/'
+pnminvert ${input3_pbm} | pamarith -equal -plain ${input3_pbm} - | \
+  uniq -c | sed -e 's/^ *//' -e 's/ /:/'
+
+xysize=$(pamfile -size testgrid.pbm)
+
+pbmmake -w ${xysize} | pamarith -equal -plain testgrid.pbm - | \
+  awk '{printf("%s%c",$0, NR<3 || NR%2==0 ? "\n" : " ")}' | 
+  uniq -c | sed -e 's/^ *//' -e 's/ /:/'
+pbmmake -b ${xysize} | pamarith -equal -plain testgrid.pbm - | \
+  awk '{printf("%s%c",$0, NR<3 || NR%2==0 ? "\n" : " ")}' | 
+  uniq -c | sed -e 's/^ *//' -e 's/ /:/'
+
+echo "Test 4"
+
+
+pamarith -compare -plain ${input3_pbm} ${input3_pbm}  | \
+  uniq -c | sed -e 's/^ *//' -e 's/ /:/'
+
+pnminvert testgrid.pbm | pamarith -compare -plain testgrid.pbm - | \
+  awk '{printf("%s%c",$0, NR<4 || NR%2==1 ? "\n" : " ")}' | 
+  uniq -c | sed -e 's/^ *//' -e 's/ /:/'
+pbmmake -w ${xysize} | pamarith -compare -plain testgrid.pbm - | \
+  awk '{printf("%s%c",$0, NR<4 || NR%2==1 ? "\n" : " ")}' | 
+  uniq -c | sed -e 's/^ *//' -e 's/ /:/'
+pbmmake -b ${xysize} | pamarith -compare -plain testgrid.pbm - | \
+  awk '{printf("%s%c",$0, NR<4 || NR%2==1 ? "\n" : " ")}' | 
+  uniq -c | sed -e 's/^ *//' -e 's/ /:/'
+
+rm ${input3_pbm}
+
+echo "Test 5"
+# -closeness
+
+input40_pgm=${tmpdir}/input40.pgm
+input50_pgm=${tmpdir}/input50.pgm
+
+pgmmake -maxval=99 0.40 7 3 > ${input40_pgm}
+pgmmake -maxval=99 0.50 7 3 > ${input50_pgm}
+
+echo "Should produce 1285449498 54 four times"
+pamarith -equal -plain ${input40_pgm} ${input40_pgm} | cksum
+pamarith -equal -plain -closeness=10.2 ${input40_pgm} ${input50_pgm} | cksum
+pamarith -equal -plain -closeness=11 ${input40_pgm} ${input50_pgm} | cksum
+pamarith -equal -plain -closeness=90 ${input40_pgm} ${input50_pgm} | cksum
+echo "Should produce 244506188 54 twice"
+pamarith -equal -plain ${input40_pgm} ${input50_pgm} | cksum
+pamarith -equal -plain -closeness=09  ${input40_pgm} ${input50_pgm} | cksum
+
+rm ${input40_pgm} ${input50_pgm}
\ No newline at end of file
diff --git a/test/pamarith-multiple-input.ok b/test/pamarith-multiple-input.ok
new file mode 100644
index 00000000..3a333058
--- /dev/null
+++ b/test/pamarith-multiple-input.ok
@@ -0,0 +1,66 @@
+Test 1
+1:
+2881377455 188
+2881377455 188
+2:
+2161003541 188
+2161003541 188
+3:
+1352533811 188
+1352533811 188
+4:
+2079203209 188
+2079203209 188
+5:
+108934727 188
+108934727 188
+6:
+755904253 188
+755904253 188
+7:
+2719989180 188
+2719989180 188
+8:
+2305795334 188
+2305795334 188
+9:
+4110388424 188
+4110388424 188
+Test 2
+2285960269 1084
+-or
+2285960269 1084
+2285960269 1084
+2285960269 1084
+-and
+2285960269 1084
+2285960269 1084
+2285960269 1084
+-xor
+2285960269 1084
+2285960269 1084
+Test 3
+-add
+392744294 1084
+392744294 1084
+392744294 1084
+-and
+1732023142 1084
+1732023142 1084
+1732023142 1084
+-or
+549786223 1084
+549786223 1084
+549786223 1084
+-xor
+3485039940 1084
+3485039940 1084
+3485039940 1084
+-nand
+460693232 1084
+460693232 1084
+460693232 1084
+-nor
+1552687097 1084
+1552687097 1084
+1552687097 1084
diff --git a/test/pamarith-multiple-input.test b/test/pamarith-multiple-input.test
new file mode 100755
index 00000000..b9c09662
--- /dev/null
+++ b/test/pamarith-multiple-input.test
@@ -0,0 +1,61 @@
+#! /bin/sh
+# This script tests: pamarith
+# Also requires: pgmmake ppmpat pamfunc
+
+tmpdir=${tmpdir:-/tmp}
+
+input1_pgm=${tmpdir}/input1.pgm
+
+
+echo "Test 1"
+# Compare pamarith addition with pamfunc multiplication"
+
+pgmmake -maxval=99 0.01 16 11 > ${input1_pgm}
+
+add_command="pamarith -add "${input1_pgm}
+
+for i in 1 2 3 4 5 6 7 8 9 # for i in `seq 9`
+  do
+  echo ${i}":"
+  add_command=${add_command}" "${input1_pgm}
+  ${add_command} | cksum
+  pamfunc -multiplier=$((i+1)) ${input1_pgm} | cksum
+  done
+
+rm ${input1_pgm}
+
+g2_ppm=${tmpdir}/g2.ppm
+g3_ppm=${tmpdir}/g3.ppm
+
+# Produce test input images with ppmpat
+ppmpat -g2 -color=rgb:00/00/00,rgb:ff/ff/ff 17 21 > ${g2_ppm}
+ppmpat -g3 -color=rgb:ff/00/00,rgb:00/ff/00,rgb:00/00/ff 17 21 > ${g3_ppm}
+
+echo "Test 2"
+
+cat ${g2_ppm} | cksum
+echo "-or"
+pamarith -or   ${g2_ppm} ${g2_ppm} | cksum
+pamarith -or   ${g2_ppm} ${g2_ppm} ${g2_ppm} | cksum
+pamarith -or   ${g2_ppm} ${g2_ppm} ${g2_ppm} ${g2_ppm} | cksum
+echo "-and"
+pamarith -and  ${g2_ppm} ${g2_ppm} | cksum
+pamarith -and  ${g2_ppm} ${g2_ppm} ${g2_ppm} | cksum
+pamarith -and  ${g2_ppm} ${g2_ppm} ${g2_ppm} ${g2_ppm} | cksum
+echo "-xor"
+pamarith -xor  ${g2_ppm} ${g2_ppm} ${g2_ppm} | cksum
+pamarith -xor  ${g2_ppm} ${g2_ppm} ${g2_ppm} ${g2_ppm} ${g2_ppm} | cksum
+
+
+echo "Test 3"
+# Order does not matter
+
+for function in "-add" "-and" "-or" "-xor" "-nand" "-nor"
+  do
+  echo ${function}
+  pamarith ${function} ${g2_ppm} ${g2_ppm} ${g3_ppm} | cksum
+  pamarith ${function} ${g3_ppm} ${g2_ppm} ${g2_ppm} | cksum
+  pamarith ${function} ${g2_ppm} ${g3_ppm} ${g2_ppm} | cksum
+  done
+
+rm ${g2_ppm} ${g3_ppm}
diff --git a/test/pamarith.ok b/test/pamarith.ok
new file mode 100644
index 00000000..c2d34dea
--- /dev/null
+++ b/test/pamarith.ok
@@ -0,0 +1,277 @@
+Test 1
+P2
+16 2
+15
+0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 
+2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 
+-add
+P2 16 1 15 2 3 4 5 6 7 8 9 10 11 12 13 14 15 15 15  
+1927712885 59
+1927712885 59
+1927712885 59
+-subtract
+P2 16 1 15 0 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13  
+622443613 59
+622443613 59
+622443613 59
+-multiply
+P2 16 1 15 0 0 0 0 1 1 1 1 1 1 1 1 2 2 2 2  
+1589721418 59
+1589721418 59
+1589721418 59
+-divide
+P2 16 1 15 0 8 15 15 15 15 15 15 15 15 15 15 15 15 15 15  
+321546811 59
+321546811 59
+321546811 59
+-difference
+P2 16 1 15 2 1 0 1 2 3 4 5 6 7 8 9 10 11 12 13  
+590140907 59
+590140907 59
+590140907 59
+-minimum
+P2 16 1 15 0 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2  
+3746423180 59
+3746423180 59
+3746423180 59
+-maximum
+P2 16 1 15 2 2 2 3 4 5 6 7 8 9 10 11 12 13 14 15  
+201376294 59
+201376294 59
+201376294 59
+-mean
+P2 16 1 15 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9  
+1456675831 59
+1456675831 59
+1456675831 59
+-compare
+P2 16 1 2 0 0 1 2 2 2 2 2 2 2 2 2 2 2 2 2  
+196115582 58
+196115582 58
+196115582 58
+-equal
+P2 16 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0  
+4168278327 58
+4168278327 58
+4168278327 58
+-and
+P2 16 1 15 0 0 2 2 0 0 2 2 0 0 2 2 0 0 2 2  
+3660405045 59
+3660405045 59
+3660405045 59
+-or
+P2 16 1 15 2 3 2 3 6 7 6 7 10 11 10 11 14 15 14 15  
+157317791 59
+157317791 59
+157317791 59
+-nand
+P2 16 1 15 15 15 13 13 15 15 13 13 15 15 13 13 15 15 13 13  
+1625584307 59
+1625584307 59
+1625584307 59
+-nor
+P2 16 1 15 13 12 13 12 9 8 9 8 5 4 5 4 1 0 1 0  
+3014218009 59
+3014218009 59
+3014218009 59
+-xor
+P2 16 1 15 2 3 0 1 6 7 4 5 10 11 8 9 14 15 12 13  
+3227090877 59
+3227090877 59
+3227090877 59
+-shiftleft
+P2 16 1 15 0 4 8 12 0 4 8 12 0 4 8 12 0 4 8 12  
+952940636 59
+952940636 59
+952940636 59
+-shiftright
+P2 16 1 15 0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3  
+2898922266 59
+2898922266 59
+2898922266 59
+Test 2 PBM
+P1
+8 2
+01010101
+00001111
+-add
+P1 8 1 00000101 
+-subtract
+P1 8 1 11110101 
+-multiply
+P1 8 1 01011111 
+-divide
+P1 8 1 01010000 
+-difference
+P1 8 1 10100101 
+-minimum
+P1 8 1 01011111 
+-maximum
+P1 8 1 00000101 
+-mean
+P1 8 1 00000101 
+-compare
+P2 8 1 2 1 0 1 0 2 1 2 1  
+-equal
+P1 8 1 01011010 
+-and
+P1 8 1 01011111 
+-or
+P1 8 1 00000101 
+-nand
+P1 8 1 10100000 
+-nor
+P1 8 1 11111010 
+-xor
+P1 8 1 10100101 
+-shiftleft
+P1 8 1 11110101 
+-shiftright
+P1 8 1 11110101 
+Test 3
+-add
+2442291770 913
+2442291770 913
+2442291770 913
+-multiply
+3074858461 913
+3074858461 913
+3074858461 913
+-difference
+3788637303 913
+3788637303 913
+3788637303 913
+-minimum
+2046561746 913
+2046561746 913
+2046561746 913
+-maximum
+3724820523 913
+3724820523 913
+3724820523 913
+-mean
+5885382 913
+5885382 913
+5885382 913
+-equal
+780857755 911
+780857755 911
+780857755 911
+-and
+889537755 913
+889537755 913
+889537755 913
+-or
+2466056482 913
+2466056482 913
+2466056482 913
+-nand
+3743732043 913
+3743732043 913
+3743732043 913
+-nor
+2027723954 913
+2027723954 913
+2027723954 913
+-xor
+291709067 913
+291709067 913
+291709067 913
+-subtract
+3705429820 913
+3705429820 913
+-divide
+2136905608 913
+2136905608 913
+-compare
+1563790885 911
+1563790885 911
+-shiftleft
+51480286 913
+51480286 913
+-shiftright
+3072492814 913
+3072492814 913
+Test 4 (input = output)
+Prints 281226646 481 six times, then 2921940274 59 six times
+input image
+281226646 481
+-minimum
+281226646 481
+-maximum
+281226646 481
+-mean
+281226646 481
+-and
+281226646 481
+-or
+281226646 481
+input image
+2921940274 59
+-minimum
+2921940274 59
+-maximum
+2921940274 59
+-mean
+2921940274 59
+-and
+2921940274 59
+-or
+2921940274 59
+Test 5 (blank output)
+Prints 2247801875 481 three times, then 320101399 59 three times
+-subtract
+2247801875 481
+-difference
+2247801875 481
+-xor
+2247801875 481
+-subtract
+320101399 59
+-difference
+320101399 59
+-xor
+320101399 59
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
+Expected failure 7 1
+Expected failure 8 1
+Expected failure 9 1
+Expected failure 10 1
+Expected failure 11 1
+Expected failure 12 1
+Expected failure 13 1
+Expected failure 14 1
+Expected failure 15 1
+Expected failure 16 1
+Expected failure 17 1
+Expected failure 18 1
+Expected failure 19 1
+Expected failure 20 1
+Expected failure 21 1
+Expected failure 22 1
+Expected failure 23 1
+Expected failure 24 1
+Expected failure 25 1
+Expected failure 26 1
+Expected failure 27 1
+Expected failure 28 1
+Expected failure 29 1
+Expected failure 30 1
+Expected failure 31 1
+Expected failure 32 1
+Expected failure 33 1
+Expected failure 34 1
+Expected failure 35 1
+Expected failure 36 1
+Expected failure 37 1
+Expected failure 38 1
+Expected failure 39 1
+Expected failure 40 1
+Expected failure 41 1
+Expected failure 42 1
diff --git a/test/pamarith.test b/test/pamarith.test
new file mode 100755
index 00000000..061f9488
--- /dev/null
+++ b/test/pamarith.test
@@ -0,0 +1,378 @@
+#! /bin/sh
+# This script tests: pamarith
+# Also requires: pamtopnm rgb3toppm pamenlarge pamcat pamseq pbmmake pgmmake
+# Also requires: ppmpat pamchannel
+
+tmpdir=${tmpdir:-/tmp}
+input1_pgm=${tmpdir}/input1.pgm
+input2_pgm=${tmpdir}/input2.pgm
+output_pgm=${tmpdir}/output.pgm
+input1_ppm=${tmpdir}/input1.ppm
+input2_ppm=${tmpdir}/input2.ppm
+
+echo "Test 1"
+
+pamseq 1 15 | pamtopnm -assume > ${input1_pgm}
+pgmmake -maxval 15 0.15 16 1 > ${input2_pgm}
+
+rgb3toppm ${input1_pgm} ${input1_pgm} ${input1_pgm} > ${input1_ppm}
+rgb3toppm ${input2_pgm} ${input2_pgm} ${input2_pgm} > ${input2_ppm}
+
+pamcat -tb ${input1_pgm} ${input2_pgm} -plain
+
+for fn in "-add" "-subtract" "-multiply" "-divide" "-difference" \
+    "-minimum" "-maximum" "-mean" "-compare" "-equal" \
+    "-and" "-or" "-nand" "-nor"  "-xor" \
+    "-shiftleft" "-shiftright"
+  do
+  echo ${fn}
+  pamarith ${fn} -plain ${input1_pgm} ${input2_pgm} | tr '\n' ' '; echo
+  pamarith ${fn} ${input1_pgm} ${input2_pgm} > ${output_pgm}
+  rgb3toppm  ${output_pgm} ${output_pgm} ${output_pgm} | cksum
+  pamarith ${fn} ${input1_ppm} ${input2_pgm} | cksum
+  pamarith ${fn} ${input1_ppm} ${input2_ppm} | cksum
+  done
+
+rm ${input1_pgm} ${input2_pgm} ${output_pgm} ${input2_ppm}
+
+input1_pbm=${tmpdir}/input1.pbm
+input2_pbm=${tmpdir}/input2.pbm
+
+echo "Test 2 PBM"
+
+pbmmake -g 8 1 > ${input1_pbm}
+pbmmake -g 2 1 | pamenlarge -xscale=4 > ${input2_pbm}
+
+pamcat -tb -plain ${input1_pbm} ${input2_pbm}
+
+for fn in "-add" "-subtract" "-multiply" "-divide" "-difference" \
+    "-minimum" "-maximum" "-mean" "-compare" "-equal" \
+    "-and" "-or" "-nand" "-nor"  "-xor" \
+    "-shiftleft" "-shiftright"
+  do
+  echo ${fn}
+  pamarith ${fn} -plain ${input1_pbm} ${input2_pbm} | tr '\n' ' '; echo
+  done
+
+rm ${input1_pbm} ${input2_pbm}
+
+echo "Test 3"
+
+input3_ppm=${tmpdir}/input3.ppm
+input4_ppm=${tmpdir}/input4.ppm
+input4_pgm=${tmpdir}/input4.pgm
+
+ppmpat -tartan  -color=rgb:f0/f0/00,rgb:80/00/80,rgb:0f/00/0f 20 15 \
+  > ${input3_ppm}
+ppmpat -argyle2 -color=rgb:01/01/01,rgb:02/02/02,rgb:05/05/05 20 15 \
+  > ${input4_ppm}
+pamchannel -infile ${input4_ppm} 0 > ${input4_pgm}
+
+for fn in "-add" "-multiply" "-difference" \
+    "-minimum" "-maximum" "-mean" "-equal" \
+    "-and" "-or" "-nand" "-nor" "-xor"
+  do
+  echo ${fn}
+  pamarith ${fn} ${input3_ppm} ${input4_ppm} | cksum
+  pamarith ${fn} ${input4_ppm} ${input3_ppm} | cksum
+  pamarith ${fn} ${input3_ppm} ${input4_pgm} | pamtopnm | cksum
+  done
+
+for fn in "-subtract" "-divide" "-compare" "-shiftleft" "-shiftright"
+  do
+  echo ${fn}
+  pamarith ${fn} ${input3_ppm} ${input4_ppm} | cksum
+  pamarith ${fn} ${input3_ppm} ${input4_pgm} | pamtopnm | cksum
+  done
+
+rm ${input3_ppm} ${input4_ppm} ${input4_pgm}
+
+echo "Test 4 (input = output)"
+echo "Prints 281226646 481 six times, then 2921940274 59 six times"
+
+for image in maze.pbm ${input1_ppm}
+  do
+  echo "input image"
+  cat ${image} | cksum
+  for fn in "-minimum" "-maximum" "-mean" "-and" "-or"
+    do
+    echo ${fn}
+    pamarith ${fn} ${image} ${image} | cksum
+    done
+  done
+
+
+echo "Test 5 (blank output)"
+echo "Prints 2247801875 481 three times, then 320101399 59 three times"
+
+for image in maze.pbm ${input1_ppm}
+  do
+  for fn in "-subtract" "-difference" "-xor"
+    do
+    echo ${fn}
+    pamarith ${fn} ${image} ${image} | cksum
+    done
+  done
+
+rm ${input1_ppm}
+
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+echo "Test Invalid"
+
+test_out=${tmpdir}/test_out
+
+# multiple functions
+
+pamarith -add -subtract testimg.ppm testimg.ppm > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -multiply -divide testimg.ppm testimg.ppm > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -difference -minimum testimg.ppm testimg.ppm > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -maximum -mean testimg.ppm testimg.ppm > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -compare -and testimg.ppm testimg.ppm > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -compare -equal testimg.ppm testimg.ppm > ${test_out} || \
+  printf "Expected failure 6"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -or -nand testimg.ppm testimg.ppm > ${test_out} || \
+  printf "Expected failure 7"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -nor -xor testimg.ppm testimg.ppm > ${test_out} || \
+  printf "Expected failure 8"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -shiftleft -shiftright testimg.ppm testimg.ppm > ${test_out} || \
+  printf "Expected failure 9"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# -add does not take a value
+
+pamarith -add=1 testimg.ppm testimg.ppm > ${test_out} || \
+  printf "Expected failure 10"
+ test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# No function
+
+pamarith -plain testimg.ppm testimg.ppm > ${test_out} || \
+  printf "Expected failure 11"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith testimg.ppm testimg.ppm > ${test_out} || \
+  printf "Expected failure 12"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# Just one input image file
+
+pamarith -add testimg.ppm > ${test_out} || \
+  printf "Expected failure 13"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# No input image file
+
+pamarith -add > ${test_out} || \
+  printf "Expected failure 14"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# Input images with different depth (number of planes)
+
+pamchannel -infile testimg.ppm 0 1 | \
+  pamarith -add testimg.ppm - > ${test_out} || \
+  printf "Expected failure 15"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# Input images with different x/y dimensions
+
+pamarith -add testimg.ppm testgrid.pbm > ${test_out} || \
+  printf "Expected failure 16"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamenlarge -xscale=2 testgrid.pbm | \
+  pamarith -add testgrid.pbm - > ${test_out} || \
+  printf "Expected failure 17"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamenlarge -yscale=3 testgrid.pbm | \
+  pamarith -add testgrid.pbm - > ${test_out} || \
+  printf "Expected failure 18"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# Invalid usage of -closeness
+
+pamarith -equal -closeness=100.1 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 19"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -equal -closeness=-10 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 20"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -closeness -equal testgrid.pbm > ${test_out} || \
+  printf "Expected failure 21"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -compare -closeness=10 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 22"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# Bit string functions
+# Create PGM test input
+
+input3_pgm=${tmpdir}/input3.pgm
+input4_pgm=${tmpdir}/input4.pgm
+input5_pgm=${tmpdir}/input5.pgm
+
+pgmmake -maxval=4095 1.0 3 1 > ${input3_pgm}
+pgmmake -maxval=4096 1.0 3 1 > ${input4_pgm}
+pgmmake -maxval=8191 1.0 3 1 > ${input5_pgm}
+
+# Bit string functions - Maxval must match
+
+pamarith -and ${input3_pgm} ${input5_pgm} > ${test_out} || \
+  printf "Expected failure 23"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -or ${input3_pgm} ${input5_pgm} > ${test_out} || \
+  printf "Expected failure 24"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -nand ${input3_pgm} ${input5_pgm} > ${test_out} || \
+  printf "Expected failure 25"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -nor ${input3_pgm} ${input5_pgm} > ${test_out} || \
+  printf "Expected failure 26"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -xor ${input3_pgm} ${input5_pgm} > ${test_out} || \
+  printf "Expected failure 27"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# Bit string functions - Maxval must be 2^n -1
+
+pamarith -and ${input4_pgm} ${input4_pgm} > ${test_out} || \
+  printf "Expected failure 28"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -or ${input4_pgm} ${input4_pgm} > ${test_out} || \
+  printf "Expected failure 29"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -nand ${input4_pgm} ${input4_pgm} > ${test_out} || \
+  printf "Expected failure 30"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -nor ${input4_pgm} ${input4_pgm} > ${test_out} || \
+  printf "Expected failure 31"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -xor ${input4_pgm} ${input4_pgm} > ${test_out} || \
+  printf "Expected failure 32"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -shiftleft ${input4_pgm} ${input4_pgm} > ${test_out} || \
+  printf "Expected failure 33"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -shiftright ${input4_pgm} ${input4_pgm} > ${test_out} || \
+  printf "Expected failure 34"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+rm ${input3_pgm} ${input4_pgm} ${input5_pgm}
+
+# Functions that do not allow more than two input images.
+# Only the functions that are commutative and associative allow
+# three or more inputs.
+
+pamarith -subtract testimg.ppm testimg.ppm testimg.ppm > ${test_out} || \
+  printf "Expected failure 35"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -divide testimg.ppm testimg.ppm testimg.ppm > ${test_out} || \
+  printf "Expected failure 36"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -compare testimg.ppm testimg.ppm testimg.ppm > ${test_out} || \
+  printf "Expected failure 37"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -difference testimg.ppm testimg.ppm testimg.ppm > ${test_out} || \
+  printf "Expected failure 38"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -shiftleft testimg.ppm testimg.ppm testimg.ppm > ${test_out} || \
+  printf "Expected failure 39"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -shiftright testimg.ppm testimg.ppm testimg.ppm > ${test_out} || \
+  printf "Expected failure 40"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# Currently -equal and -mean do not allow more than two input images.
+# These two cases should be removed once improvements are made.
+
+pamarith -equal testgrid.pbm testgrid.pbm testgrid.pbm > ${test_out} || \
+  printf "Expected failure 41"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamarith -mean testgrid.pbm  testgrid.pbm testgrid.pbm > ${test_out} || \
+  printf "Expected failure 42"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pambackground.test b/test/pambackground.test
index 522f4823..eca9cc93 100755
--- a/test/pambackground.test
+++ b/test/pambackground.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pambackground
 # Also requires: pamgradient pamseq pbmmake pnmmargin pnmremap pnmtile pnmpad
 
diff --git a/test/pambrighten.ok b/test/pambrighten.ok
new file mode 100644
index 00000000..6c58b4c9
--- /dev/null
+++ b/test/pambrighten.ok
@@ -0,0 +1,96 @@
+Test 1
+P3
+8 1
+255
+0 0 0 0 0 100 0 100 0 0 100 100 100 0 0 100 0 100 100 100 0 100 100 100 
+
+P3
+8 1
+255
+0 0 0 0 0 110 0 110 0 0 110 110 110 0 0 110 0 110 110 110 0 110 110 110 
+
+P3
+8 1
+255
+0 0 0 0 0 90 0 90 0 0 90 90 90 0 0 90 0 90 90 90 0 90 90 90 
+
+P3
+8 1
+255
+0 0 0 0 0 200 0 200 0 0 200 200 200 0 0 200 0 200 200 200 0 200 200 200 
+
+P3
+8 1
+255
+0 0 0 0 0 255 0 255 0 0 255 255 255 0 0 255 0 255 255 255 0 255 255 255 
+
+P3
+8 1
+255
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+Test 2
+P3
+8 1
+255
+0 0 0 10 10 100 10 100 10 10 100 100 100 10 10 100 10 100 100 100 10 100 100 100 
+
+P3
+8 1
+255
+0 0 0 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 
+
+Test 3: Output invariant
+P3
+8 1
+255
+0 0 0 0 0 100 0 100 0 0 100 100 100 0 0 100 0 100 100 100 0 100 100 100 
+
+P3
+8 1
+255
+0 0 0 0 0 100 0 100 0 0 100 100 100 0 0 100 0 100 100 100 0 100 100 100 
+
+P3
+8 1
+255
+0 0 0 0 0 100 0 100 0 0 100 100 100 0 0 100 0 100 100 100 0 100 100 100 
+
+P3
+8 1
+255
+0 0 0 0 0 100 0 100 0 0 100 100 100 0 0 100 0 100 100 100 0 100 100 100 
+
+P3
+8 1
+255
+0 0 0 0 0 100 0 100 0 0 100 100 100 0 0 100 0 100 100 100 0 100 100 100 
+
+P3
+8 1
+255
+0 0 0 0 0 100 0 100 0 0 100 100 100 0 0 100 0 100 100 100 0 100 100 100 
+
+Test 4: Should print 3990234518 268 six times
+3990234518 268
+3990234518 268
+3990234518 268
+3990234518 268
+3990234518 268
+3990234518 268
+Test Error: Should print 1 six times
+1
+1
+1
+1
+1
+1
+Test Error: Should print 99 followed by 1, four times
+99
+1
+99
+1
+99
+1
+99
+1
diff --git a/test/pambrighten.test b/test/pambrighten.test
new file mode 100755
index 00000000..00e405dd
--- /dev/null
+++ b/test/pambrighten.test
@@ -0,0 +1,99 @@
+#! /bin/sh
+# This script tests: pambrighten
+# Also requires: pgmramp
+
+tmpdir=${tmpdir:-/tmp}
+
+input_ppm=${tmpdir}/input.ppm
+
+cat > ${input_ppm} << EOF
+P3
+8 1
+255
+0 0 0 0 0 100 0 100 0 0 100 100 100 0 0 100 0 100 100 100 0 100 100 100 
+EOF
+
+# Test 1
+
+echo "Test 1"
+pambrighten -v   0 -plain ${input_ppm}
+pambrighten -v +10 -plain ${input_ppm}
+pambrighten -v -10 -plain ${input_ppm}
+pambrighten -v +100 -plain ${input_ppm}
+pambrighten -v +200 -plain ${input_ppm}
+pambrighten -v -100 -plain ${input_ppm}
+
+echo "Test 2"
+pambrighten -s -10 -plain ${input_ppm}
+pambrighten -s -100 -plain ${input_ppm}
+
+echo "Test 3: Output invariant"
+pambrighten         -plain ${input_ppm}
+pambrighten -v   0  -plain ${input_ppm}
+pambrighten -s   0  -plain ${input_ppm}
+pambrighten -s +10  -plain ${input_ppm}
+pambrighten -s +100 -plain ${input_ppm}
+pambrighten -s +200 -plain ${input_ppm}
+
+rm ${input_ppm}
+
+echo "Test 4: Should print 3990234518 268 six times"
+
+input_pgm=${tmpdir}/input.pgm
+
+pgmramp -lr 255 1 | tee ${input_pgm} | cksum
+pambrighten -s -100 ${input_pgm} | cksum
+pambrighten -s -10  ${input_pgm} | cksum
+pambrighten -s +10  ${input_pgm} | cksum
+pambrighten -s +100 ${input_pgm} | cksum
+pambrighten -s +200 ${input_pgm} | cksum
+
+rm ${input_pgm}
+
+
+# Test 2
+# These should all fail.
+
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+echo "Test Error: Should print 1 six times"
+
+output_ppm=${tmpdir}/output.ppm
+
+pambrighten -v -120 testimg.ppm > ${output_ppm}
+echo $?
+test -s ${output_ppm}
+echo $?
+pambrighten -s -120 testimg.ppm > ${output_ppm}
+echo $?
+test -s ${output_ppm}
+echo $?
+pambrighten 10 testimg.ppm > ${output_ppm}
+echo $?
+test -s ${output_ppm}
+echo $?
+
+
+echo "Test Error: Should print 99 followed by 1, four times"
+
+pambrighten -s 1.20 testimg.ppm > ${output_ppm}
+echo $?
+test -s ${output_ppm}
+echo $?
+pambrighten -v 10.5 testimg.ppm > ${output_ppm}
+echo $?
+test -s ${output_ppm}
+echo $?
+pambrighten -v testimg.ppm > ${output_ppm}
+echo $?
+test -s ${output_ppm}
+echo $?
+pambrighten -s testimg.ppm > ${output_ppm}
+echo $?
+test -s ${output_ppm}
+echo $?
+
+
+rm -f ${output_ppm}
diff --git a/test/pamcat1.ok b/test/pamcat1.ok
new file mode 100644
index 00000000..4e23666f
--- /dev/null
+++ b/test/pamcat1.ok
@@ -0,0 +1,150 @@
+Test 1.  Should print 15135078 29, then 0 fourteen times
+15135078 29
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+Test 2.  Should print 1957849403 59, 0 six times, 1 once
+1957849403 59
+0
+0
+0
+0
+0
+0
+1
+Test 3.  Should print 2673197404 69, 0 six times, 1 once
+2673197404 69
+0
+0
+0
+0
+0
+0
+1
+Test 4.  Should print 2285402562 36, then 0 twelve times
+2285402562 36
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+Test 5.  Should print 1836757613 62, 0 six times, 1 once
+1836757613 62
+0
+0
+0
+0
+0
+0
+1
+Test 6.  Should print 3601245348 137, 0 six times, 1 once
+3601245348 137
+0
+0
+0
+0
+0
+0
+1
+Test 7.  Should print 1572996771 71, then 0 twelve times
+1572996771 71
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+Test 8.  Should print 270413826 252, 0 six times, 1 once
+270413826 252
+0
+0
+0
+0
+0
+0
+1
+Test 9.  Should print 2942772630 192, 0 six times, 1 once
+2942772630 192
+0
+0
+0
+0
+0
+0
+1
+Test 10.  Should print 2700536985 95, then 0 twelve times
+2700536985 95
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+Test 11.  Should print 2193235886 195, 0 eight times, 1 once
+2193235886 195
+0
+0
+0
+0
+0
+0
+0
+0
+1
+Test 12.  Should print 2773166369 245, 0 nine times, 1 once
+2773166369 245
+0
+0
+0
+0
+0
+0
+0
+0
+0
+1
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
+Expected failure 7 1
+Expected failure 8 1
+Expected failure 9 1
+Expected failure 10 1
+Expected failure 11 1
+Expected failure 12 1
+Expected failure 13 1
+Expected failure 14 1
diff --git a/test/pamcat1.test b/test/pamcat1.test
new file mode 100755
index 00000000..67d941cc
--- /dev/null
+++ b/test/pamcat1.test
@@ -0,0 +1,271 @@
+#! /bin/sh
+# This script tests: pamcat
+# Also requires: pbmmake pgmmake ppmmake pamseq pamrestack
+
+tmpdir=${tmpdir:-/tmp}
+check10x10_pbm=${tmpdir}/check10x10.pbm
+check40x10_pbm=${tmpdir}/check40x10.pbm
+check10x30_pbm=${tmpdir}/check10x30.pbm
+
+gray5x5_pgm=${tmpdir}/gray5x5.pgm
+gray10x5_pgm=${tmpdir}/gray10x5.pgm
+gray5x25_pgm=${tmpdir}/gray5x25.pgm
+
+yellow4x5_ppm=${tmpdir}/yellow4x5.ppm
+yellow16x5_ppm=${tmpdir}/yellow16x5.ppm
+yellow4x15_ppm=${tmpdir}/yellow4x15.ppm
+
+seq2_4h_pam=${tmpdir}/seq2_4h.pam
+seq2_4h4_pam=${tmpdir}/seq2_4h4.pam
+seq2_4v_pam=${tmpdir}/seq2_4v.pam
+seq2_4v3_pam=${tmpdir}/seq2_4v3.pam
+
+
+echo "Test 1.  Should print 15135078 29, then 0 fourteen times"
+
+pbmmake -g 10 10 | tee ${check10x10_pbm} | cksum
+for opt in "-leftright" "-lr" "-lr -jtop" "-lr -jcenter" "-lr -jbottom" \
+    "-lr -white" "-lr -black" \
+    "-topbottom" "-tb" "-tb -jleft"  "-tb -jcenter" "-tb --jright" \
+    "-tb -white" "-tb -black"
+  do
+  pamcat ${opt} ${check10x10_pbm} | cmp -s ${check10x10_pbm} - ; echo $?
+  done
+
+
+echo "Test 2.  Should print 1957849403 59, 0 six times, 1 once"
+pbmmake -g 40 10 | tee ${check40x10_pbm} | cksum
+for opt in "-leftright" "-lr -jtop" "-lr -jcenter" "-lr -jbottom" \
+    "-lr -white" "-lr -black" \
+    "-tb"
+  do
+  pamcat ${opt} ${check10x10_pbm} ${check10x10_pbm} \
+         ${check10x10_pbm} ${check10x10_pbm} | \
+  cmp -s ${check40x10_pbm} - ; echo $?
+  done
+
+
+echo "Test 3.  Should print 2673197404 69, 0 six times, 1 once"
+pbmmake -g 10 30 | tee ${check10x30_pbm} | cksum
+for opt in "-topbottom" "-tb -jleft"  "-tb -jcenter" "-tb --jright" \
+    "-tb -white" "-tb -black" \
+    "-lr"
+  do
+  pamcat ${opt} ${check10x10_pbm} ${check10x10_pbm} ${check10x10_pbm} |\
+  cmp -s ${check10x30_pbm} - ; echo $? 	
+  done
+
+rm ${check10x10_pbm} ${check40x10_pbm} ${check10x30_pbm}
+
+
+echo "Test 4.  Should print 2285402562 36, then 0 twelve times"
+
+pgmmake 0.125 5 5 | tee ${gray5x5_pgm} | cksum
+for opt in "-leftright" "-lr -jtop" "-lr -jcenter" "-lr -jbottom" \
+    "-lr -white" "-lr -black" \
+    "-topbottom" "-tb -jleft"  "-tb -jcenter" "-tb --jright" \
+    "-tb -white" "-tb -black"
+  do
+  pamcat ${opt} ${gray5x5_pgm} | cmp -s ${gray5x5_pgm} - ; echo $?
+  done
+
+
+echo "Test 5.  Should print 1836757613 62, 0 six times, 1 once"
+pgmmake 0.125 10 5 | tee ${gray10x5_pgm} | cksum
+for opt in "-leftright" "-lr -jtop" "-lr -jcenter" "-lr -jbottom" \
+    "-lr -white" "-lr -black" \
+    "-tb"
+  do
+  pamcat ${opt} ${gray5x5_pgm} ${gray5x5_pgm} |\
+  cmp -s ${gray10x5_pgm} - ; echo $?
+  done
+
+
+echo "Test 6.  Should print 3601245348 137, 0 six times, 1 once"
+pgmmake 0.125 5 25 | tee ${gray5x25_pgm} | cksum
+for opt in "-topbottom" "-tb -jleft"  "-tb -jcenter" "-tb --jright" \
+    "-tb -white" "-tb -black" \
+    "-lr"
+  do
+  pamcat ${opt} ${gray5x5_pgm} ${gray5x5_pgm} ${gray5x5_pgm} \
+	 ${gray5x5_pgm} ${gray5x5_pgm} |\
+  cmp -s ${gray5x25_pgm} - ; echo $?
+  done
+
+
+rm ${gray5x5_pgm} ${gray10x5_pgm} ${gray5x25_pgm}
+
+
+echo "Test 7.  Should print 1572996771 71, then 0 twelve times"
+ppmmake rgb:255/255/1 4 5 | tee ${yellow4x5_ppm} | cksum
+for opt in "-leftright" "-lr -jtop" "-lr -jcenter" "-lr -jbottom" \
+    "-lr -white" "-lr -black" \
+    "-topbottom" "-tb -jleft"  "-tb -jcenter" "-tb --jright" \
+    "-tb -white" "-tb -black"
+  do
+  pamcat ${opt} ${yellow4x5_ppm} |\
+  cmp -s ${yellow4x5_ppm} - ; echo $?
+  done
+
+
+echo "Test 8.  Should print 270413826 252, 0 six times, 1 once"
+ppmmake rgb:255/255/1 16 5 | tee ${yellow16x5_ppm} | cksum
+for opt in "-leftright" "-lr -jtop" "-lr -jcenter" "-lr -jbottom" \
+    "-lr -white" "-lr -black" \
+    "-tb"
+  do
+  pamcat ${opt} ${yellow4x5_ppm} ${yellow4x5_ppm} \
+         ${yellow4x5_ppm} ${yellow4x5_ppm} |\
+  cmp -s ${yellow16x5_ppm} - ; echo $?
+  done
+
+
+echo "Test 9.  Should print 2942772630 192, 0 six times, 1 once"
+ppmmake rgb:255/255/1 4 15 | tee ${yellow4x15_ppm} | cksum
+for opt in "-topbottom" "-tb -jleft"  "-tb -jcenter" "-tb --jright" \
+    "-tb -white" "-tb -black" \
+    "-lr"
+  do
+  pamcat ${opt} ${yellow4x5_ppm} ${yellow4x5_ppm} ${yellow4x5_ppm} |\
+  cmp -s ${yellow4x15_ppm} - ; echo $?
+  done
+
+rm ${yellow4x5_ppm} ${yellow16x5_ppm} ${yellow4x15_ppm}
+
+
+echo "Test 10.  Should print 2700536985 95, then 0 twelve times"
+pamseq 2 4 | tee ${seq2_4h_pam} | cksum
+for opt in "-leftright" "-lr -jtop" "-lr -jcenter" "-lr -jbottom" \
+    "-lr -white" "-lr -black" \
+    "-topbottom" "-tb -jleft"  "-tb -jcenter" "-tb --jright" \
+    "-tb -white" "-tb -black"
+  do
+  pamcat ${opt} ${seq2_4h_pam}  |\
+  cmp -s ${seq2_4h_pam} - ; echo $?
+  done
+
+
+echo "Test 11.  Should print 2193235886 195, 0 eight times, 1 once"
+pamrestack -width=1 ${seq2_4h_pam} | tee ${seq2_4v_pam} |\
+  pamenlarge -xscale=3 |\
+  tee ${seq2_4v3_pam} | cksum
+pamcat -lr ${seq2_4v_pam} ${seq2_4v_pam} | pamcat -lr - ${seq2_4v_pam} |\
+  cmp -s ${seq2_4v3_pam} - ; echo $?
+pamcat -lr ${seq2_4v_pam} | pamcat -lr - ${seq2_4v_pam}  ${seq2_4v_pam} |\
+  cmp -s ${seq2_4v3_pam} - ; echo $?
+for opt in "-leftright" "-lr -jtop" "-lr -jcenter" "-lr -jbottom" \
+    "-lr -white" "-lr -black" \
+    "-topbottom"
+  do
+  pamcat ${opt} ${seq2_4v_pam} ${seq2_4v_pam} ${seq2_4v_pam} |\
+  cmp -s ${seq2_4v3_pam} - ; echo $?
+  done
+
+
+echo "Test 12.  Should print 2773166369 245, 0 nine times, 1 once"
+pamenlarge -yscale 4 ${seq2_4h_pam} | tee ${seq2_4h4_pam} | cksum
+pamcat -tb ${seq2_4h_pam} |\
+    pamcat -tb - ${seq2_4h_pam} ${seq2_4h_pam} ${seq2_4h_pam} |\
+    cmp -s ${seq2_4h4_pam} - ; echo $?
+pamcat -tb ${seq2_4h_pam} ${seq2_4h_pam} |\
+    pamcat -tb - ${seq2_4h_pam} ${seq2_4h_pam} |\
+    cmp -s ${seq2_4h4_pam} - ; echo $?
+pamcat -tb ${seq2_4h_pam} ${seq2_4h_pam} ${seq2_4h_pam}|\
+    pamcat -tb - ${seq2_4h_pam} |\
+    cmp -s ${seq2_4h4_pam} - ; echo $?
+for opt in "-topbottom" "-tb -jleft"  "-tb -jcenter" "-tb --jright" \
+    "-tb -white" "-tb -black" \
+    "-leftright"
+  do
+  pamcat ${opt} ${seq2_4h_pam} ${seq2_4h_pam} ${seq2_4h_pam} ${seq2_4h_pam} |\
+  cmp -s ${seq2_4h4_pam} - ; echo $?
+  done
+
+rm ${seq2_4h_pam} ${seq2_4v_pam} ${seq2_4v3_pam} ${seq2_4h4_pam}
+
+
+
+echo "Test Invalid"
+
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+# direction not specified
+pamcat testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# both directions specified
+pamcat -topbottom -leftright testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# both pad colors specified
+pamcat -topbottom -white -black testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# justification parameters overspecified
+pamcat -lr -jtop -jbottom testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamcat -lr -jtop -jcenter testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamcat -lr -jcenter -jbottom testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 6"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamcat -tb -jleft -jright testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 7"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamcat -tb -jleft -jcenter testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 8"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamcat -tb -jcenter -jright testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 9"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# justification parameter in the wrong direction
+pamcat -lr -jleft    testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 10"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamcat -lr -jright   testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 11"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamcat -tb -jtop     testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 12"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamcat -tb -jbottom  testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 13"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# more than one input image from standard input
+cat testgrid.pbm | pamcat -lr - - testimg.ppm > ${test_out} || \
+  printf "Expected failure 14"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pamcat2.ok b/test/pamcat2.ok
new file mode 100644
index 00000000..549fe97a
--- /dev/null
+++ b/test/pamcat2.ok
@@ -0,0 +1,93 @@
+Test 1.
+P1
+1 1
+0
+P1
+1 1
+0
+P1
+1 1
+1
+P1
+1 1
+0
+Test 2.
+P1
+7 5
+0000000
+1000001
+1000001
+1000001
+1000001
+P1
+7 5
+1000001
+1000001
+0000000
+1000001
+1000001
+P1
+7 5
+1000001
+1000001
+1000001
+1000001
+0000000
+P1
+7 5
+1000001
+1000001
+0000000
+1000001
+1000001
+P1
+5 7
+01111
+00000
+00000
+00000
+00000
+00000
+01111
+P1
+5 7
+11011
+00000
+00000
+00000
+00000
+00000
+11011
+P1
+5 7
+11110
+00000
+00000
+00000
+00000
+00000
+11110
+P1
+5 7
+11011
+00000
+00000
+00000
+00000
+00000
+11011
+Test 3.
+1715060535 12
+1715060535 12
+3621575043 12
+3621575043 12
+Test 4.
+1972597727 14
+1972597727 14
+Test 5.
+2175144709 10456
+2175144709 10456
+2175144709 10456
+609107534 10444
+609107534 10444
+609107534 10444
diff --git a/test/pamcat2.test b/test/pamcat2.test
new file mode 100755
index 00000000..ecc7ee5e
--- /dev/null
+++ b/test/pamcat2.test
@@ -0,0 +1,64 @@
+#! /bin/sh
+# This script tests: pamcat
+# Also requires: pbmmake pamflip
+
+tmpdir=${tmpdir:-/tmp}
+dotw_pbm=${tmpdir}/dotw.pbm
+dotb_pbm=${tmpdir}/dotb.pbm
+check5x5_pbm=${tmpdir}/check5x5.pbm
+dot_ppm=${tmpdir}/dot.ppm
+
+echo "Test 1."
+pbmmake -w 1 1 | tee ${dotw_pbm} | pamcat -tb -plain
+pamcat -lr -plain ${dotw_pbm}
+pbmmake -b 1 1 | tee ${dotb_pbm} | pamcat -tb -plain
+pamcat -tb -plain ${dotw_pbm}
+
+echo "Test 2."
+
+pbmmake -w 5 5 > ${check5x5_pbm}
+
+pamcat -lr -jt -black ${dotw_pbm} ${check5x5_pbm} ${dotw_pbm} -plain
+pamcat -lr -jc -black ${dotw_pbm} ${check5x5_pbm} ${dotw_pbm} -plain
+pamcat -lr -jb -black ${dotw_pbm} ${check5x5_pbm} ${dotw_pbm} -plain
+pamcat -lr     -black ${dotw_pbm} ${check5x5_pbm} ${dotw_pbm} -plain
+
+pamcat -tb -jl -black ${dotw_pbm} ${check5x5_pbm} ${dotw_pbm} -plain
+pamcat -tb -jc -black ${dotw_pbm} ${check5x5_pbm} ${dotw_pbm} -plain
+pamcat -tb -jr -black ${dotw_pbm} ${check5x5_pbm} ${dotw_pbm} -plain
+pamcat -tb     -black ${dotw_pbm} ${check5x5_pbm} ${dotw_pbm} -plain
+
+rm ${dotw_pbm}
+
+echo "Test 3."
+pbmmake -b 1 1 > ${dotb_pbm}
+
+pamcat -lr -jt -white ${dotb_pbm} ${check5x5_pbm} ${dotb_pbm} | cksum
+pamcat -lr -jb -white ${dotb_pbm} ${check5x5_pbm} ${dotb_pbm} |\
+  pamflip -tb | cksum
+pamcat -tb -jl -white ${dotb_pbm} ${check5x5_pbm} ${dotb_pbm} |\
+  pamflip -ccw | cksum
+pamcat -tb -jr -white ${dotb_pbm} ${check5x5_pbm} ${dotb_pbm} |\
+  pamflip -cw | cksum
+
+rm ${dotb_pbm}
+rm ${check5x5_pbm}
+
+
+echo "Test 4."
+ppmmake rgb:20/40/d0 1 1 | tee ${dot_ppm} | pamcat -lr | cksum
+pamcat -tb  ${dot_ppm} | cksum
+
+echo "Test 5."
+for just in -jtop -jcenter -jbottom
+do
+pamcat -lr ${just} ${dot_ppm} maze.pbm ${dot_ppm} | cksum
+done
+
+for just in -jleft -jcenter -jright
+do
+pamcat -tb ${just} ${dot_ppm} maze.pbm ${dot_ppm} | cksum
+done
+
+rm ${dot_ppm}
+
diff --git a/test/pamcat3.ok b/test/pamcat3.ok
new file mode 100644
index 00000000..5dbb2cbc
--- /dev/null
+++ b/test/pamcat3.ok
@@ -0,0 +1,19 @@
+Test 1.   Should print 585134073 133221 four times
+585134073 133221
+585134073 133221
+585134073 133221
+585134073 133221
+Test 2.   Should print 1331083756 152559 three times
+1331083756 152559
+1331083756 152559
+1331083756 152559
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
+Expected failure 7 1
+Expected failure 8 1
+Expected failure 9 1
diff --git a/test/pamcat3.test b/test/pamcat3.test
new file mode 100755
index 00000000..3aed0131
--- /dev/null
+++ b/test/pamcat3.test
@@ -0,0 +1,97 @@
+#! /bin/sh
+# This script tests: pamcat
+# Also requires:
+
+tmpdir=${tmpdir:-/tmp}
+list=${tmpdir}/list
+list2=${tmpdir}/list2
+list3=${tmpdir}/list3
+liste1=${tmpdir}/liste1
+liste2=${tmpdir}/liste2
+liste3=${tmpdir}/liste3
+files="maze.pbm testgrid.pbm testimg.ppm"
+
+ls ${files} | tee ${list} | awk '{print ""; print $0; print ""}' > ${list3}
+sed 's/maze.pbm/-/' ${list} > ${list2}
+
+echo "Test 1.   Should print 585134073 133221 four times"
+pamcat -lr -jt ${files} | cksum
+pamcat -lr -jt -listfile=${list} | cksum
+cat maze.pbm | pamcat -lr -jt -listfile=${list2} | cksum
+pamcat -lr -jt -listfile=${list3} | cksum
+
+echo "Test 2.   Should print 1331083756 152559 three times"
+pamcat -tb -jl ${files} | cksum
+pamcat -tb -jl -listfile=${list} | cksum
+cat ${list} | pamcat -tb -jl -listfile=- | cksum
+
+echo "Test Invalid"
+
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line argument combinations & listfile content." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+# listfile not specified
+pamcat -lr -listfile > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# listfile does not exist
+pamcat -lr -listfile=`mktemp -u` > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# listfile empty
+pamcat -lr -listfile=/dev/null > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# listfile from stdin, empty
+cat /dev/null | pamcat -lr -listfile=- > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# Files provided from command line in addition to listfile
+pamcat -lr -listfile=${list} testgrid.pbm testgrid.pbm > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# "-" (stdin) provided from command line in addition to listfile
+pamcat -lr -listfile=${list} - > ${test_out} || \
+  printf "Expected failure 6"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# listfile has nothing but blank lines
+sed 's/^.*$//' ${list3} > ${liste1}  
+pamcat -lr -listfile=${liste1} > ${test_out} || \
+  printf "Expected failure 7"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out} ${liste1}
+
+# Non-existing file in listfile
+( cat ${list} ; mktemp -u ) > ${liste2}
+pamcat -lr -listfile=${liste2} > ${test_out} || \
+  printf "Expected failure 8"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out} ${liste2}
+
+# Multiple instances of "-" in listfile
+( echo "-"; cat ${list}; echo "-"; echo "-" ) > ${liste3}
+pamcat -lr -listfile=${liste3} > ${test_out} || \
+  printf "Expected failure 9"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out} ${liste3}
+
+
+rm ${list} ${list2} ${list3}
+
+
diff --git a/test/pamchannel.ok b/test/pamchannel.ok
index 79317f03..91629202 100644
--- a/test/pamchannel.ok
+++ b/test/pamchannel.ok
@@ -1,3 +1,12 @@
+Test 1:red-channel  Should produce 1571496937 33838
 1571496937 33838
+Test 2:green-channel  Should produce 394856971 33838
 394856971 33838
+Test 3:blue-channel  Should produce 3164158573 33838
 3164158573 33838
+Test 4:single-channel  Should produce 281226646 481
+281226646 481
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
diff --git a/test/pamchannel.test b/test/pamchannel.test
index 3529f4fe..f2662706 100755
--- a/test/pamchannel.test
+++ b/test/pamchannel.test
@@ -1,7 +1,6 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamchannel
-# Also requires: pamtopnm
-
+# Also requires: pamtopam pamtopnm
 
 # Extract planes one by one.
 # Convert output to pgm to make it identical to ppmtorgb3 output.
@@ -13,20 +12,47 @@
 # 3164158573 33838 testimg.blu
 
 
-# Test 1. red channel
-# Should produce 1571496937 33838
-
+echo "Test 1:red-channel  Should produce 1571496937 33838"
 pamchannel -infile testimg.ppm 0 | \
   pamtopnm --assume | cksum
 
-# Test 2. green channel
-# Should produce  394856971 33838
-
+echo "Test 2:green-channel  Should produce 394856971 33838"
 pamchannel -infile testimg.ppm -tupletype="GRAYSCALE" 1 | \
   pamtopnm | cksum
 
-# Test 3. blue channel
-# Should produce 3164158573 33838
+echo "Test 3:blue-channel  Should produce 3164158573 33838"
 
 pamchannel -infile testimg.ppm 2 | \
   pamtopnm --assume | cksum
+
+echo "Test 4:single-channel  Should produce 281226646 481"
+pamchannel -infile maze.pbm 0 | \
+  pamtopnm --assume | cksum
+
+# Test invalid: specified channel does not exist
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+echo "Test Invalid"
+
+pamchannel  -infile testgrid.pbm 1 > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamchannel  -infile testimg.ppm 3 > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamtopam testimg.ppm | pamchannel -infile=- 4 > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
diff --git a/test/pamcrater.ok b/test/pamcrater.ok
index cfb186a6..a5571f35 100644
--- a/test/pamcrater.ok
+++ b/test/pamcrater.ok
@@ -1,6 +1,13 @@
+Test 1.
 4
 4
 4
+Test 2.
 2
 2
 2
+Test Invalid.
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
diff --git a/test/pamcrater.test b/test/pamcrater.test
index 4d3858b9..e0c98afb 100755
--- a/test/pamcrater.test
+++ b/test/pamcrater.test
@@ -1,10 +1,10 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamcrater pamshadedrelief
 # Also requires: pamstack pamvalidate pamcut pamflip
 
 
-# We use the undocumented --test and --radius options of pamcrater.
-# pamcrater --test --radius=N
+# We use the undocumented -test and -radius options of pamcrater.
+# pamcrater -test -radius=N
 # The above draws a single crater of radius N.
 # The resulting image should be symmetric.
 
@@ -18,11 +18,12 @@ test100_pam=${tmpdir}/test100.pam
 test150_pam=${tmpdir}/test150.pam
 
 # Test 1.  Should print 4 three times
+echo "Test 1."
 
-pamcrater --test --radius=10 > $test10_pam
-pamcrater --test --radius=50 > $test50_pam
-pamcrater --test --radius=100 > $test100_pam
-pamcrater --test --radius=150 > $test150_pam
+pamcrater -test -radius=10 > $test10_pam
+pamcrater -test -radius=50 > $test50_pam
+pamcrater -test -radius=100 > $test100_pam
+pamcrater -test -radius=150 > $test150_pam
 
 pamstack ${test10_pam} ${test50_pam} ${test100_pam} ${test150_pam} |
   pamvalidate > ${test_pam}
@@ -39,6 +40,7 @@ for i in 1 10 70
 rm ${test_pam} ${test10_pam} ${test50_pam}
 
 # Test 2.  Should print 2 three times
+echo "Test 2."
 
 pamshadedrelief ${test100_pam} > ${testshaded_pam}
 
@@ -50,4 +52,33 @@ pamshadedrelief ${test100_pam} > ${testshaded_pam}
   pamcut -top=$((128 - 99)) -height=1  ${testshaded_pam} | cksum
 ) | uniq -c | awk '{print $1}'
 
-rm ${testshaded_pam} ${test100_pam}
+rm ${testshaded_pam} ${test100_pam} ${test150_pam}
+
+echo "Test Invalid."
+
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "------------------------------" 1>&2
+
+pamcrater -width 0 > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamcrater -height 0 > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamcrater -number 0 > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamcrater -test -radius=10 | pamshadedrelief -gamma 0 > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pamcut.ok b/test/pamcut.ok
index b08bc531..fc4dc3de 100644
--- a/test/pamcut.ok
+++ b/test/pamcut.ok
@@ -1,19 +1,36 @@
-Test 1.
+Test 1.  Should print 2958909756 124815
 2958909756 124815
-Test 2.
+Test 2.  Should print 1550940962 10933
 1550940962 10933
-Test 3.
+Test 3.  Should print 708474423 14 twice
 708474423 14
 708474423 14
-Test 4.
+Test 4.  Should print 659346598 80124 four times
 659346598 80124
 659346598 80124
 659346598 80124
 659346598 80124
-Test 5.
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-Test 6.
+Test 5. Should print 281226646 481 five times
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+Test 6.  Should print 3412257956 129
 3412257956 129
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
+Expected failure 7 1
+Expected failure 8 1
+Expected failure 9 1
+Expected failure 6 1
+Expected failure 10 1
+Expected failure 11 1
+Expected failure 12 1
+Expected failure 13 1
+Expected failure 14 1
diff --git a/test/pamcut.test b/test/pamcut.test
index 9971b1a5..a489635a 100755
--- a/test/pamcut.test
+++ b/test/pamcut.test
@@ -1,28 +1,23 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamcut pbmmake
-# Also requires:
+# Also requires: pamfile
 
-# Test 1.  Should print 2958909756 124815
-echo Test 1.
+echo "Test 1.  Should print 2958909756 124815"
 
 pamcut -top 0 -left 0 -width 260 -height 160 \
   -pad testimg.ppm | cksum
 
-# Test 2.  Should print 1550940962 10933
-echo Test 2.
+echo "Test 2.  Should print 1550940962 10933"
 
 pamcut -top 200 -left 120 -width 40 -height 40 \
   -pad testimg.ppm | cksum
 
-# Test 3.  Should print 708474423 14 twice
-echo Test 3.
+echo "Test 3.  Should print 708474423 14 twice"
 
 pamcut -top 5 -left 5 -bottom 5 -right 5 testimg.ppm | cksum
 pamcut -width 1 -height 1 -bottom 5 -right 5 testimg.ppm | cksum
 
-
-# Test 4.  Should print 659346598 80124 four times
-echo Test 4.
+echo "Test 4.  Should print 659346598 80124 four times"
 
 pamcut -croptop 10 -cropleft 10 -cropbottom 10 -cropright 10 testimg.ppm | \
   cksum
@@ -30,18 +25,110 @@ pamcut -top 10 -left 10 -bottom 138 -right 216 testimg.ppm | cksum
 pamcut -top 10 -left 10 -bottom -11 -right -11 testimg.ppm | cksum
 pamcut -top 10 -left 10 -width 207 -height 129 testimg.ppm | cksum
 
+echo "Test 5. Should print 281226646 481 five times"
 
-# Test 5. Should print 2425386270 41 four times
-echo Test 5.
-
-pamcut -croptop 0 -cropleft 0 -cropbottom 0 -cropright 0 testgrid.pbm | \
+mazesize=$(pamfile -size maze.pbm)
+width=$(echo ${mazesize} | cut -d " " -f 1)
+height=$(echo ${mazesize} | cut -d " " -f 2)
+ 
+pamcut -croptop 0 -cropleft 0 -cropbottom 0 -cropright 0 maze.pbm | \
   cksum
-pamcut -top 0 -left 0 -bottom 15 -right 13 testgrid.pbm | cksum
-pamcut -top 0 -left 0 -bottom -1 -right -1 testgrid.pbm | cksum
-pamcut -top 0 -left 0 -width 14 -height 16 testgrid.pbm | cksum
+pamcut -top 0 -left 0 -bottom $((${height} -1)) -right $((${width} -1)) \
+  maze.pbm | cksum
+pamcut -top 0 -left 0 -bottom -1 -right -1 maze.pbm | cksum
+pamcut -top 0 -left 0 -width ${width} -height ${height} maze.pbm | cksum
+pamcut maze.pbm | cksum
+ 
+echo "Test 6.  Should print 3412257956 129"
+
+pbmmake -g 50 50 | pamcut 5 5 30 30 | cksum
 
 
-# Test 6.  Should print 3412257956 129
-echo Test 6.
+echo "Test Invalid"
 
-pbmmake -g 50 50 | pamcut 5 5 30 30 | cksum
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+# overspecification
+pamcut -left=1 -right=1 -width=14 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamcut -top=1 -bottom=1 -height=16 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamcut -right=1 -cropright=1 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamcut -top=1 -croptop=1 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamcut -bottom=1 -cropbottom=1 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamcut -left=1 -cropleft=1 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 6"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# excessive cropping
+pamcut -cropleft=7 -cropright=8 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 7"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamcut -left=7 -right=6 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 8"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamcut -croptop=8 -cropbottom=8 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 9"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamcut -top=10 -bottom=9 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 6"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# pad absent
+pamcut -cropleft=1 -width=14 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 10"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamcut -croptop=1  -height=16 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 11"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# legacy style: insufficient number of positional parameters
+pamcut 5 testimg.ppm > ${test_out} || \
+  printf "Expected failure 12"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamcut 5 4 testimg.ppm > ${test_out} || \
+  printf "Expected failure 13"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamcut 5 5 30 testimg.ppm > ${test_out} || \
+  printf "Expected failure 14"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pamdepth-roundtrip.ok b/test/pamdepth-roundtrip.ok
index 89db1a57..28db2ee1 100644
--- a/test/pamdepth-roundtrip.ok
+++ b/test/pamdepth-roundtrip.ok
@@ -5,4 +5,4 @@
 1926073387 101484
 1926073387 101484
 1926073387 101484
-2425386270 41
+281226646 481
diff --git a/test/pamdepth-roundtrip.test b/test/pamdepth-roundtrip.test
index 0c7cb8b0..6da9a612 100755
--- a/test/pamdepth-roundtrip.test
+++ b/test/pamdepth-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamdepth pgmtopbm
 # Also requires:
 
@@ -9,5 +9,5 @@ pamdepth $i testimg.ppm | \
   pamdepth 255 | cksum
 done
 
-pamdepth 255 testgrid.pbm | pamdepth 1 | \
+pamdepth 255 maze.pbm | pamdepth 1 | \
   pgmtopbm -th -val=0.5 | cksum
diff --git a/test/pamdepth.ok b/test/pamdepth.ok
new file mode 100644
index 00000000..1bd897ac
--- /dev/null
+++ b/test/pamdepth.ok
@@ -0,0 +1,14 @@
+Test 1
+538848130 235
+stdin: PGM RAW 14 16 1 1 GRAYSCALE
+538848130 235
+stdin: PGM RAW 14 16 1 1 GRAYSCALE
+831461512 289
+stdin: PAM RAW 14 16 1 1 GRAYSCALE
+831461512 289
+stdin: PAM RAW 14 16 1 1 GRAYSCALE
+Test 2
+0 0 : 0
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
diff --git a/test/pamdepth.test b/test/pamdepth.test
new file mode 100755
index 00000000..7ff73f41
--- /dev/null
+++ b/test/pamdepth.test
@@ -0,0 +1,40 @@
+#! /bin/bash
+# This script tests: pamdepth
+# Also requires: pbmtopgm pamtopam pamfile
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+# Test 1
+echo "Test 1"
+pamdepth 1 testgrid.pbm | tee ${test_out} | cksum
+  cat ${test_out} | pamfile -machine
+pbmtopgm 1 1 testgrid.pbm | pamdepth 1 | tee ${test_out} | cksum
+  cat ${test_out} | pamfile -machine
+pamdepth 1 testgrid.pbm | pamtopam | tee ${test_out} | cksum
+  cat ${test_out} | pamfile -machine
+pbmtopgm 1 1 testgrid.pbm | pamtopam | pamdepth 1 | tee ${test_out} | cksum
+  cat ${test_out} | pamfile -machine
+
+# Test 2
+echo "Test 2"
+pamdepth 255 testimg.ppm | cmp -s - testimg.ppm
+  echo ${PIPESTATUS[@]} ":" $?
+
+# Test Invalid
+echo "Test Invalid"
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pamdepth 0 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamdepth 65536 testimg.ppm > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pamdice-roundtrip.ok b/test/pamdice-roundtrip.ok
index 82eac5a8..9f648fd0 100644
--- a/test/pamdice-roundtrip.ok
+++ b/test/pamdice-roundtrip.ok
@@ -1 +1,16 @@
+Test 1.  Should print 281226646 481
+281226646 481
+Test 2.  Should print 281226646 481
+281226646 481
+Test 3.  Should print 281226646 481
+281226646 481
+Test 4.  Should print 281226646 481
+281226646 481
+Test 5.  Should print 1926073387 101484 five times
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+Test 6.  Should print 1926073387 101484
 1926073387 101484
diff --git a/test/pamdice-roundtrip.test b/test/pamdice-roundtrip.test
index 28997742..4d3fba19 100755
--- a/test/pamdice-roundtrip.test
+++ b/test/pamdice-roundtrip.test
@@ -1,12 +1,60 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamdice pamundice
-# Also requires:
-
+# Also requires: pamfile
 
 tmpdir=${tmpdir:-/tmp}
-fname_stem=${tmpdir}/a
+fname_stem=${tmpdir}/pamdice_part
+
+mazesize=$(pamfile -size maze.pbm)
+mw=$(echo ${mazesize} | cut -d " " -f 1)
+mh=$(echo ${mazesize} | cut -d " " -f 2)
+
+echo "Test 1.  Should print 281226646 481"
+
+pamdice maze.pbm -outstem=${fname_stem}
+pamundice ${fname_stem}_%1d_%1a.pbm -down=1 -across=1 | cksum
+rm ${fname_stem}_0_0.pbm
+
+echo "Test 2.  Should print 281226646 481"
+
+width=10
+tiles=$(( (${mw}+${width}-1) / ${width} ))
+
+
+pamdice maze.pbm -outstem=${fname_stem} -width=${width}
+pamundice ${fname_stem}_%1d_%1a.pbm -across=${tiles} | cksum
+rm ${fname_stem}_*_*.pbm
+
+echo "Test 3.  Should print 281226646 481"
+
+width=5
+tiles=$(( (${mw}+${width}-1) / ${width} ))
+
+pamdice maze.pbm -outstem=${fname_stem} -width=${width}
+pamundice ${fname_stem}_%1d_%2a.pbm -across=${tiles} | cksum
+rm ${fname_stem}_*_*.pbm
+
+
+echo "Test 4.  Should print 281226646 481"
+
+height=10
+tiles=$(( (${mh}+${height}-1) / ${height} ))
+
+pamdice maze.pbm -outstem=${fname_stem} -height=${height}
+pamundice ${fname_stem}_%1d_%1a.pbm -down=${tiles} | cksum
+rm ${fname_stem}_*_*.pbm
+
+echo "Test 5.  Should print 1926073387 101484 five times"
+
+for option in "" "-hoverlap=0" "-hoverlap=2" "-voverlap=0" "-voverlap=2"
+  do
+  pamdice testimg.ppm -outstem=${fname_stem} -width=50 -height=40
+  pamundice ${fname_stem}_%1d_%1a.ppm -down=4 -across=5 | cksum
+  rm ${fname_stem}_?_?.ppm
+  done
 
-pamdice testimg.ppm -outstem=${fname_stem} -width=50 -height=40
-pamundice ${fname_stem}_%1d_%1a.ppm -down=4 -across=5 | cksum
+echo "Test 6.  Should print 1926073387 101484"
 
-rm ${fname_stem}_?_?.ppm
+pamdice testimg.ppm -outstem=${fname_stem} -width=20 -height=10
+ls ${fname_stem}*.ppm | pamundice -listfile=- -across=12 -down=15 | cksum
+rm ${fname_stem}_??_??.ppm
\ No newline at end of file
diff --git a/test/pamdice.ok b/test/pamdice.ok
new file mode 100644
index 00000000..9e978168
--- /dev/null
+++ b/test/pamdice.ok
@@ -0,0 +1,26 @@
+Test 1.
+10 P1@1 1@0@
+Test 2.
+P1@1 1@0@
+P1@1 1@1@
+P1@1 1@1@
+P1@1 1@0@
+P1@1 1@0@
+P1@1 1@1@
+P1@1 1@1@
+P1@1 1@0@
+P1@1 1@0@
+P1@1 1@1@
+Test Invalid
+Expected failure 1
+Expected failure 1.rm
+Expected failure 2
+Expected failure 2.rm
+Expected failure 3
+Expected failure 3.rm
+Expected failure 4
+Expected failure 4.rm
+Expected failure 5
+Expected failure 5.rm
+Expected failure 6
+Expected failure 6.rm
diff --git a/test/pamdice.test b/test/pamdice.test
new file mode 100755
index 00000000..04dd4d78
--- /dev/null
+++ b/test/pamdice.test
@@ -0,0 +1,79 @@
+#! /bin/sh
+# This script tests: pamdice
+# Also requires: pbmmake
+
+tmpdir=${tmpdir:-/tmp}
+fname_stem=${tmpdir}/pamdice_part
+
+# Test 1.
+echo "Test 1."
+
+pbmmake -w 2 5 | pamdice -height=1 -width=1 -outstem=${fname_stem} -plain
+ls ${fname_stem}*.pbm | while read file
+  do
+  cat ${file} | tr '\n'  '@' ; echo
+  done | sort | uniq -c | sed 's/^ *//'
+
+rm ${fname_stem}*.pbm
+
+# Test 1.
+echo "Test 2."
+
+pbmmake -g 2 5 | pamdice -height=1 -width=1 -outstem=${fname_stem} -plain
+ls ${fname_stem}*.pbm | while read file
+  do
+  cat ${file} | tr '\n'  '@' ; echo
+  done
+
+rm ${fname_stem}*.pbm
+
+
+# Test Invalid.
+echo "Test Invalid"
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+# No output files should be producd.  With nothing to remove,
+# the rm commands should always fail.
+
+# No input file
+pamdice -width=10 -height=10  -outstem=${fname_stem} /dev/null || \
+echo "Expected failure 1"
+rm ${fname_stem}* ||
+echo "Expected failure 1.rm"
+
+# No -outstem
+pamdice -width=10 -height=10 testgrid.pbm || \
+echo "Expected failure 2"
+rm ${fname_stem}* ||
+echo "Expected failure 2.rm"
+
+# -width=0
+pamdice -width=0 -height=10 -outstem=${fname_stem} testgrid.pbm || \
+echo "Expected failure 3"
+rm ${fname_stem}* ||
+echo "Expected failure 3.rm"
+
+# -height=0
+pamdice -width=10 -height=0 -outstem=${fname_stem} testgrid.pbm || \
+echo "Expected failure 4"
+rm ${fname_stem}* ||
+echo "Expected failure 4.rm"
+
+# -hoverlap larger than width
+pamdice -width=10 -height=10 -hoverlap=11 \
+  -outstem=${fname_stem} testgrid.pbm || \
+echo "Expected failure 5"
+rm ${fname_stem}* ||
+echo "Expected failure 5.rm"
+
+
+# -voverlap larger than height
+pamdice -width=10 -height=10 -voverlap=11 \
+  -outstem=${fname_stem} testgrid.pbm || \
+echo "Expected failure 6"
+rm ${fname_stem}* ||
+echo "Expected failure 6.rm"
diff --git a/test/pamditherbw-random.ok b/test/pamditherbw-random.ok
new file mode 100755
index 00000000..d21e3613
--- /dev/null
+++ b/test/pamditherbw-random.ok
@@ -0,0 +1,6 @@
+Test: Floyd-Steinberg
+Should print 3849876047 33894
+3849876047 33894
+Test: Atkinson
+Should print 2887295695 33894
+2887295695 33894
diff --git a/test/pamditherbw-random.test b/test/pamditherbw-random.test
new file mode 100755
index 00000000..7a5de7bd
--- /dev/null
+++ b/test/pamditherbw-random.test
@@ -0,0 +1,23 @@
+#! /bin/sh
+# This script tests: pamditherbw
+# Also requires: pamchannel pamtopnm
+
+tmpdir=${tmpdir:-/tmp}
+test_red=${tmpdir}/testimg.red
+
+# Test 1.  Floyd-Steinberg
+echo "Test: Floyd-Steinberg"
+echo "Should print 3849876047 33894"
+
+pamchannel -infile=testimg.ppm -tupletype="GRAYSCALE" 0 | pamtopnm | \
+  tee ${test_red} | \
+  pamditherbw -fs -randomseed=1 | cksum
+
+
+# Test 2. Atkinson
+echo "Test: Atkinson"
+echo "Should print 2887295695 33894"
+
+pamditherbw -atkinson -randomseed=1 ${test_red} | cksum
+
+rm ${test_red}
\ No newline at end of file
diff --git a/test/pamditherbw.ok b/test/pamditherbw.ok
index e8186c24..02200d0f 100644
--- a/test/pamditherbw.ok
+++ b/test/pamditherbw.ok
@@ -1,4 +1,28 @@
+Test: simple threshold
 1316122660 33894
+Test: Hilbert
 3342429190 33894
+2905156049 33894
+339841328 33894
+1633267750 33894
+Test: Dither-8
 3325147568 33894
+Test: Cluster-3
 4124728025 33894
+Test: Cluster-4
+4124728025 33894
+Test: Cluster-8
+3493215477 33894
+Test: Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
+Expected failure 7 1
+Expected failure 8 1
+Expected failure 9 1
+Expected failure 10 1
+Expected failure 11 1
+Expected failure 12 1
diff --git a/test/pamditherbw.test b/test/pamditherbw.test
index 3f377f81..be560089 100755
--- a/test/pamditherbw.test
+++ b/test/pamditherbw.test
@@ -1,32 +1,109 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamditherbw
 # Also requires: pamchannel pamtopnm
 
-
 tmpdir=${tmpdir:-/tmp}
 test_red=${tmpdir}/testimg.red
 
 # Test 1.  Simple threshold
+echo "Test: simple threshold"
+
 pamchannel -infile=testimg.ppm -tupletype="GRAYSCALE" 0 | pamtopnm | \
   tee ${test_red} | \
   pamditherbw -threshold -val=0.5 | cksum
 
-# Test 2.  Floyd-Steinberg
-#pamditherbw -floyd -val=0.5 ${test_red} | cksum
-
-# Test 3. Atkinson
-#pamditherbw -atkinson -val=0.5 ${test_red} | cksum
 
-# Test 4. Hilbert
+# Test 2. Hilbert
+echo "Test: Hilbert"
 pamditherbw -hilbert ${test_red} | cksum
+pamditherbw -hilbert -clump=4   ${test_red} | cksum
+pamditherbw -hilbert -clump=16  ${test_red} | cksum
+pamditherbw -hilbert -clump=100 ${test_red} | cksum
 
-# Test 5. Dither-8
+# Test 3. Dither-8
+echo "Test: Dither-8"
 pamditherbw -dither8 ${test_red} | cksum
 
-# Test 6. Cluster4
+# Test 4. Cluster-3
+echo "Test: Cluster-3"
 pamditherbw -cluster4 ${test_red} | cksum
 
-# Test 7. Atkinson
-#pamditherbw -atkinson -val=0.5 ${test_red} | cksum
+# Test 5. Cluster-4
+echo "Test: Cluster-4"
+pamditherbw -cluster4 ${test_red} | cksum
+
+# Test 6. Cluster-8
+echo "Test: Cluster-8"
+pamditherbw -cluster8 ${test_red} | cksum
+
+
+echo "Test: Invalid"
+
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pamditherbw -fs -atkinson       ${test_red} > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamditherbw -floyd -atkinson    ${test_red} > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamditherbw -dither8  -cluster3 ${test_red} > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamditherbw -cluster3 -cluster4 ${test_red} > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamditherbw -cluster3 -cluster8 ${test_red} > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamditherbw -cluster4 -cluster8 ${test_red} > ${test_out} || \
+  printf "Expected failure 6"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamditherbw -hilbert -threshold ${test_red} > ${test_out} || \
+  printf "Expected failure 7"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamditherbw -clump=8            ${test_red} > ${test_out} || \
+  printf "Expected failure 8"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamditherbw -fs -clump=8        ${test_red} > ${test_out} || \
+  printf "Expected failure 9"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamditherbw -hilbert -clump=1   ${test_red} > ${test_out} || \
+  printf "Expected failure 10"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamditherbw -th -value=-1       ${test_red} > ${test_out} || \
+  printf "Expected failure 11"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamditherbw -th -value=1.1      ${test_red} > ${test_out} || \
+  printf "Expected failure 12"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
 
 rm ${test_red}
diff --git a/test/pamedge.test b/test/pamedge.test
index c63b30cc..8121f858 100755
--- a/test/pamedge.test
+++ b/test/pamedge.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamedge
 # Also requires: pbmpscale pbmtext pgmtopbm pgmtopgm ppmtopgm
 
diff --git a/test/pamendian-roundtrip.ok b/test/pamendian-roundtrip.ok
new file mode 100644
index 00000000..6245abb9
--- /dev/null
+++ b/test/pamendian-roundtrip.ok
@@ -0,0 +1,5 @@
+Test 1.  Should print '0 0 0 : 0'
+0 0 0 : 0
+Test 2.  Should print '0 0 0 0 0 : 0' twice
+0 0 0 0 0 : 0
+0 0 0 0 0 : 0
diff --git a/test/pamendian-roundtrip.test b/test/pamendian-roundtrip.test
new file mode 100755
index 00000000..b060b704
--- /dev/null
+++ b/test/pamendian-roundtrip.test
@@ -0,0 +1,26 @@
+#! /bin/bash
+# This script tests: pamendian
+# Also requires: pamdepth pgmtopbm pamseq
+
+echo "Test 1.  Should print '0 0 0 : 0'" 
+
+tmpdir=${tmpdir:-/tmp}
+test0_pam=${tmpdir}/test0.pam
+
+pamseq 1 65535 > ${test0_pam}
+pamendian < ${test0_pam} | pamendian |\
+  cmp -s ${test0_pam} -
+  echo ${PIPESTATUS[@]} ":" $?
+
+rm ${test0_pam}
+
+
+echo "Test 2.  Should print '0 0 0 0 0 : 0' twice" 
+
+pamdepth 65535 testgrid.pbm | pamendian | pamendian | \
+  pgmtopbm -th -val=0.5 | cmp -s - testgrid.pbm
+  echo ${PIPESTATUS[@]} ":" $?
+
+pamdepth 4095 maze.pbm | pamendian | pamendian | \
+  pgmtopbm -th -val=0.5 | cmp -s - maze.pbm
+  echo ${PIPESTATUS[@]} ":" $?
\ No newline at end of file
diff --git a/test/pamenlarge-pamscale-point.test b/test/pamenlarge-pamscale-point.test
index 08b34bb7..f0f0948b 100755
--- a/test/pamenlarge-pamscale-point.test
+++ b/test/pamenlarge-pamscale-point.test
@@ -29,8 +29,8 @@ enlarge_pbm=${tmpdir}/enlarge.pbm
 for option in "6 -nomix" "15 -nomix -linear" "24 -nomix"
   do
   scale=${option%% *}
-  pamenlarge $scale testgrid.pbm > ${enlarge_pbm}
-  pamscale   $option testgrid.pbm | cmp -s - ${enlarge_pbm}  
+  pamenlarge $scale maze.pbm > ${enlarge_pbm}
+  pamscale   $option maze.pbm | cmp -s - ${enlarge_pbm}  
   echo $option ${PIPESTATUS[@]} ":" $?
   rm  ${enlarge_pbm}
   done
diff --git a/test/pamenlarge-pbm.test b/test/pamenlarge-pbm.test
index 10c00ba0..bea740c6 100755
--- a/test/pamenlarge-pbm.test
+++ b/test/pamenlarge-pbm.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamenlarge
 # Also requires: pbmmake pnmpad
 
@@ -18,22 +18,26 @@ LC_ALL=C awk 'BEGIN { print "P4";         # header
 # Test 1.
 echo "test 1"
  
-for xs in `seq 23`
+for xs in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
+  # for xs in `seq 23`
   do
-  pamenlarge -xscale=$xs ${complete256_pbm} | cksum
+  pamenlarge -xscale=${xs} ${complete256_pbm} | cksum
   done
 
 # Test 2.
 echo "test 2"
 
-for xs1 in `seq 15`
+for xs1 in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+  # for xs1 in `seq 15`
   do
-  xs2=$((30-$xs1))
-  pamenlarge -xscale=$xs1 ${complete256_pbm} | pamenlarge -xscale=$xs2 | cksum
-  if [ $xs1 != $xs2 ]; then
-  pamenlarge -xscale=$xs2 ${complete256_pbm} | pamenlarge -xscale=$xs1 | cksum
+  xs2=$((30-${xs1}))
+  pamenlarge -xscale=${xs1} ${complete256_pbm} | \
+    pamenlarge -xscale=${xs2} | cksum
+  if [ ${xs1} != ${xs2} ]; then
+  pamenlarge -xscale=${xs2} ${complete256_pbm} | \
+    pamenlarge -xscale=${xs1} | cksum
   fi
-  pamenlarge -xscale=$(($xs1 * $xs2)) ${complete256_pbm} | cksum
+  pamenlarge -xscale=$((${xs1} * ${xs2})) ${complete256_pbm} | cksum
   done
 
 rm ${complete256_pbm}
@@ -43,19 +47,19 @@ echo "test 3"
 
 test3_pbm=${tmpdir}/test3.pbm
 
-for width in `seq 16`
+for width in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16  # for width in `seq 16`
   do
   pbmmake -g ${width} 1 | pnmpad -top=1 -white | \
       pnmpad -bottom=1 -black > ${test3_pbm}.${width}
   done
  
-  for xscale in `seq 16`
-    do echo -n ${xscale} " "
-    for width in `seq 16`
+  for xscale in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16  # for xscale in `seq 16`
+    do printf "%d  " ${xscale}
+    for width in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16  # for width in `seq 16` 
       do pamenlarge -xscale=${xscale} ${test3_pbm}.${width} ; done | cksum
       #
       # unlike most other tests we take the cksum of a composite PBM file
       #
     done
 
-rm ${test3_pbm}.[1-9]  ${test3_pbm}.1[1-6]
\ No newline at end of file
+rm ${test3_pbm}.[1-9]  ${test3_pbm}.1[0-6]
diff --git a/test/pamenlarge.ok b/test/pamenlarge.ok
index a2408871..9107e870 100644
--- a/test/pamenlarge.ok
+++ b/test/pamenlarge.ok
@@ -1,4 +1,10 @@
+Test 1.  Should print 3424505894 913236
 3424505894 913236
+Test 2.  Should print 3763267672 304422
 3763267672 304422
-3342398172 297
+Test 3.  Should print 3748791794 3905
+3748791794 3905
+Test 4.  Should print 1618994486 1194
+1618994486 1194
+Test 5.  Should print 398497872 6806
 398497872 6806
diff --git a/test/pamenlarge.test b/test/pamenlarge.test
index 3820f47e..7c46881d 100755
--- a/test/pamenlarge.test
+++ b/test/pamenlarge.test
@@ -1,14 +1,15 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamenlarge
 # Also requires: pamchannel pamseq pamtopnm
 
-
-# Test 1.  Should print 3424505894 913236
+echo "Test 1.  Should print 3424505894 913236"
 pamenlarge 3 testimg.ppm | cksum
-# Test 2.  Should print 3763267672 304422
+echo "Test 2.  Should print 3763267672 304422"
 pamchannel -infile=testimg.ppm -tupletype="GRAYSCALE" 0 | pamtopnm | \
   pamenlarge 3 | cksum
-# Test 3.  Should print 3342398172 297
-pamenlarge 3 testgrid.pbm | cksum
-# Test 4.  Should print 398497872 6806
+echo "Test 3.  Should print 3748791794 3905"
+pamenlarge 3 maze.pbm | cksum
+echo "Test 4.  Should print 1618994486 1194"
+pamenlarge -xscale=21 -yscale=2 testgrid.pbm | cksum
+echo "Test 5.  Should print 398497872 6806"
 pamseq 3 4 | pamtopnm -assume | pamenlarge 3 -plain | cksum
diff --git a/test/pamexec-roundtrip.ok b/test/pamexec-roundtrip.ok
new file mode 100644
index 00000000..604ab5de
--- /dev/null
+++ b/test/pamexec-roundtrip.ok
@@ -0,0 +1,10 @@
+Test 1: should print stdin: PPM RAW 17 22 3 255 RGB six times
+stdin: PPM RAW 17 22 3 255 RGB
+stdin: PPM RAW 17 22 3 255 RGB
+stdin: PPM RAW 17 22 3 255 RGB
+stdin: PPM RAW 17 22 3 255 RGB
+stdin: PPM RAW 17 22 3 255 RGB
+stdin: PPM RAW 17 22 3 255 RGB
+Test 2: should print '0 0 : 0' twice
+0 0 : 0
+0 0 : 0
diff --git a/test/pamexec-roundtrip.test b/test/pamexec-roundtrip.test
new file mode 100755
index 00000000..fce7b6b5
--- /dev/null
+++ b/test/pamexec-roundtrip.test
@@ -0,0 +1,25 @@
+#! /bin/bash
+# This script tests: pamexec
+# Also requires: ppmpat ppmmake pamfile
+
+tmpdir=${tmpdir:-/tmp}
+test_ppm=${tmpdir}/test_ppm
+
+echo "Test 1: should print stdin: PPM RAW 17 22 3 255 RGB six times"
+
+( ppmmake rgb:0/255/127 17 22
+  ppmpat -g2 --color=rgb:143/188/143,rgb:161/161/161 17 22
+  ppmpat -g3 --color=rgb:224/255/255,rgb:255/130/171,rgb:255/48/48 17 22
+  ppmpat -madras --color=rgb:181/181/181,rgb:51/62/99,rgb:205/193/197 17 22
+  ppmpat -tartan --color=rgb:238/233/191,rgb:84/84/84,rgb:255/160/122 17 22
+  ppmpat -argyle2 --color=rgb:205/104/57,rgb:119/136/153,rgb:255/255/255 17 22
+) | tee ${test_ppm} | pamfile -all -machine
+
+echo "Test 2: should print '0 0 : 0' twice"
+
+pamexec "ppmtoppm " ${test_ppm} | cmp -s ${test_ppm} -  
+  echo ${PIPESTATUS[@]} ":" $?
+pamexec "cat " ${test_ppm} | cmp -s ${test_ppm} -  
+  echo ${PIPESTATUS[@]} ":" $?
+
+rm ${test_ppm}
diff --git a/test/pamexec.ok b/test/pamexec.ok
new file mode 100644
index 00000000..23e4268e
--- /dev/null
+++ b/test/pamexec.ok
@@ -0,0 +1,10 @@
+Test 1 : Should print 10 stdin: PBM RAW 21 24 1 1 BLACKANDWHITE twice
+10 stdin: PBM RAW 21 24 1 1 BLACKANDWHITE
+10 stdin: PBM RAW 21 24 1 1 BLACKANDWHITE
+Test 2: Should print 1791121103 989 twice
+1791121103 989
+1791121103 989
+Test 3: Should print 2983705297 810 twice
+2983705297 810
+2983705297 810
+Test Invalid: Should not print anything
diff --git a/test/pamexec.test b/test/pamexec.test
new file mode 100755
index 00000000..7c2bf054
--- /dev/null
+++ b/test/pamexec.test
@@ -0,0 +1,42 @@
+#! /bin/sh
+# This script tests: pamexec
+# Also requires: pbmtext pamfile pbmminkowski pbmtog3 g3topbm
+
+tmpdir=${tmpdir:-/tmp}
+test_pbm=${tmpdir}/test.pbm
+combined_pbm=${tmpdir}/combined.pbm
+
+for i in 0 1 2 3 4 5 6 7 8 9  # for i in `seq 0 9`
+  do echo ${i} | pbmtext -builtin=fixed > ${test_pbm}${i}
+  done
+cat ${test_pbm}[0123456789] > ${combined_pbm}
+
+echo "Test 1 : Should print 10 stdin: PBM RAW 21 24 1 1 BLACKANDWHITE twice"
+
+cat ${combined_pbm} | pamfile -all -mach | uniq -c | sed 's/^ *//' 
+pamexec "pamfile -mach" ${combined_pbm}  | uniq -c | sed 's/^ *//' 
+
+echo "Test 2: Should print 1791121103 989 twice"
+
+for i in 0 1 2 3 4 5 6 7 8 9  # for i in `seq 0 9`
+  do pbmminkowski ${test_pbm}${i}; done | cksum
+pamexec "pbmminkowski" ${combined_pbm} | cksum
+
+rm ${test_pbm}[0123456789]
+
+echo "Test 3: Should print 2983705297 810 twice"
+
+pamexec "pbmtog3 -no | g3topbm" ${combined_pbm}  | cksum
+cat ${combined_pbm}  | cksum
+
+echo "Invalid command" 1>&2
+echo "Executes quietly." 1>&2
+echo "Errors message should not appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+echo "Test Invalid: Should not print anything"
+
+pamexec "false" ${combined_pbm}
+pamexec "pamfile | false" ${combined_pbm}
+
+rm ${combined_pbm}
diff --git a/test/pamfile.ok b/test/pamfile.ok
index c0d80c28..e222592c 100644
--- a/test/pamfile.ok
+++ b/test/pamfile.ok
@@ -1,12 +1,19 @@
+Test 1
 testimg.ppm:	PPM raw, 227 by 149  maxval 255
 testgrid.pbm:	PBM raw, 14 by 16
 stdin:	PGM raw, 227 by 149  maxval 255
 stdin:	PAM, 227 by 149 by 1 maxval 255
     Tuple type: GRAYSCALE
+Test 2
 stdin:	3 images
 stdin:	Image 0:	PBM raw, 14 by 16
 stdin:	Image 1:	PBM raw, 14 by 16
 stdin:	Image 2:	PBM raw, 14 by 16
+Test 3
 227 149
 testimg.ppm: PPM RAW 227 149 3 255 RGB
 stdin: PBM RAW 14 16 1 1 BLACKANDWHITE
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
diff --git a/test/pamfile.test b/test/pamfile.test
index 545a2289..260d0b27 100755
--- a/test/pamfile.test
+++ b/test/pamfile.test
@@ -1,16 +1,46 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamfile
 # Also requires: pamchannel pamtopnm
 
+echo "Test 1"
 
 pamfile testimg.ppm
 pamfile testgrid.pbm
 pamchannel -infile=testimg.ppm -tupletype="GRAYSCALE" 0 | pamtopnm | pamfile
 pamchannel -tupletype="GRAYSCALE" -infile=testimg.ppm 0 | pamfile
 
+echo "Test 2"
+
 cat testgrid.pbm testgrid.pbm testgrid.pbm | pamfile -count
 cat testgrid.pbm testgrid.pbm testgrid.pbm | pamfile -allimages
 
+echo "Test 3"
+
 pamfile -size testimg.ppm
 pamfile -machine testimg.ppm
 cat testgrid.pbm testimg.ppm testgrid.pbm | pamfile -machine
+
+echo "Test Invalid"
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pamfile -size -machine  testimg.ppm > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfile -count -machine testimg.ppm > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+head -n1 testimg.ppm | pamfile > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pamfind.ok b/test/pamfind.ok
index dc0f95ed..de53166e 100644
--- a/test/pamfind.ok
+++ b/test/pamfind.ok
@@ -20,6 +20,14 @@ Locations containing tuple (210/57/41)/255:
 (101, 77)
 (101, 78)
 (102, 72)
+118 195
+137 176
+137 177
+137 178
+138 183
+139 205
+140 188
+144 199
 Test 2
 Locations containing tuple (1)/1:
 (0, 1)
@@ -78,6 +86,179 @@ Locations containing tuple (1)/1:
 (14, 9)
 (14, 11)
 (14, 13)
+00 00
+00 02
+00 04
+00 06
+00 08
+00 10
+00 12
+01 00
+01 01
+01 02
+01 03
+01 04
+01 05
+01 06
+01 07
+01 08
+01 09
+01 10
+01 11
+01 12
+01 13
+02 00
+02 02
+02 04
+02 06
+02 08
+02 10
+02 12
+03 00
+03 01
+03 02
+03 03
+03 04
+03 05
+03 06
+03 07
+03 08
+03 09
+03 10
+03 11
+03 12
+03 13
+04 00
+04 02
+04 04
+04 06
+04 08
+04 10
+04 12
+05 00
+05 01
+05 02
+05 03
+05 04
+05 05
+05 06
+05 07
+05 08
+05 09
+05 10
+05 11
+05 12
+05 13
+06 00
+06 02
+06 04
+06 06
+06 08
+06 10
+06 12
+07 00
+07 01
+07 02
+07 03
+07 04
+07 05
+07 06
+07 07
+07 08
+07 09
+07 10
+07 11
+07 12
+07 13
+08 00
+08 02
+08 04
+08 06
+08 08
+08 10
+08 12
+09 00
+09 01
+09 02
+09 03
+09 04
+09 05
+09 06
+09 07
+09 08
+09 09
+09 10
+09 11
+09 12
+09 13
+10 00
+10 02
+10 04
+10 06
+10 08
+10 10
+10 12
+11 00
+11 01
+11 02
+11 03
+11 04
+11 05
+11 06
+11 07
+11 08
+11 09
+11 10
+11 11
+11 12
+11 13
+12 00
+12 02
+12 04
+12 06
+12 08
+12 10
+12 12
+13 00
+13 01
+13 02
+13 03
+13 04
+13 05
+13 06
+13 07
+13 08
+13 09
+13 10
+13 11
+13 12
+13 13
+14 00
+14 02
+14 04
+14 06
+14 08
+14 10
+14 12
+15 00
+15 01
+15 02
+15 03
+15 04
+15 05
+15 06
+15 07
+15 08
+15 09
+15 10
+15 11
+15 12
+15 13
 Test 3
 okay
 okay
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
diff --git a/test/pamfind.test b/test/pamfind.test
index 39cb1437..9165fbdf 100755
--- a/test/pamfind.test
+++ b/test/pamfind.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamfind
 # Also requires:
 
@@ -7,26 +7,58 @@ sorted0_res=${tmpdir}/pamfind_sorted0.res
 sorted1_res=${tmpdir}/pamfind_sorted1.res
 
 # Test 1
-echo Test 1
-pamfind -color=grey17     testimg.ppm 
+echo "Test 1"
+pamfind -color=grey17     testimg.ppm
 pamfind -target=210,57,41 testimg.ppm
+pamfind -target=50,55,49 -machine testimg.ppm
 
 # Test 2
-echo Test 2
+echo "Test 2"
 pamfind -target=1 testgrid.pbm
+pamfind -target=0 -machine testgrid.pbm
 
 # Test 3
 # The two outputs should be disjoint
-echo Test 3
+echo "Test 3"
 pamfind -target=0 testgrid.pbm | sort > ${sorted0_res}
 pamfind -target=1 testgrid.pbm | sort > ${sorted1_res}
 comm -3 ${sorted0_res}  ${sorted1_res}  |
   awk 'END {if (NR==226) print  "okay";
             else printf("failure (line count=%d)\n", NR)}'
-comm -12 ${sorted0_res}  ${sorted1_res} | 
+comm -12 ${sorted0_res}  ${sorted1_res} |
   awk '{print}; END { if(NR == 0) print  "okay";
             else printf("failure (line count=%d)\n", NR)}'
 
 rm ${sorted0_res} ${sorted1_res}
 
+# Test 4
 
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+echo "Test Invalid"
+
+pamfind -color=black -target=1,1,1 testimg.ppm > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfind -target=0,0 testimg.ppm > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfind -target=0,0,0,0 testimg.ppm > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfind testimg.ppm > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pamfix.ok b/test/pamfix.ok
new file mode 100644
index 00000000..7302f91e
--- /dev/null
+++ b/test/pamfix.ok
@@ -0,0 +1,68 @@
+Test 1
+P1
+5 5
+01010
+10101
+01010
+10101
+01010
+P1
+5 4
+01010
+10101
+01010
+00001
+P1
+5 4
+01010
+10101
+01010
+00001
+P1
+5 1
+01010
+Test 2
+P2
+3 3
+7
+0 1 2 
+3 4 5 
+6 7 0 
+P2
+3 2
+7
+0 1 2 
+3 4 5 
+P2
+3 2
+7
+0 1 2 
+3 4 5 
+P2
+3 3
+8
+0 1 2 
+3 4 5 
+6 7 8 
+P2
+3 3
+7
+0 1 2 
+3 4 5 
+6 7 7 
+P2
+3 3
+8
+0 1 2 
+3 4 8 
+0 0 0 
+P2
+3 3
+7
+0 1 2 
+3 4 7 
+0 0 0 
+Test invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
diff --git a/test/pamfix.test b/test/pamfix.test
new file mode 100755
index 00000000..a18cae10
--- /dev/null
+++ b/test/pamfix.test
@@ -0,0 +1,69 @@
+#! /bin/sh
+# This script tests: pamfix
+# Also requires: pbmmake
+
+tmpdir=${tmpdir:-/tmp}
+
+# Test 1.
+echo "Test 1"
+
+pbmmake -g 5 5 | pamfix -truncate -plain
+
+printf "P1\n5 5\n01010\n10101\n01010\n00001\n1\n" |\
+  pamfix -truncate -plain
+
+printf "P1\n5 5\n01010\n10101\n01010\n0000\n1\n" |\
+  pamfix -truncate -plain
+
+printf "P1\n5 5\n01010\n10102\n01010\n00001\n1\n" |\
+  pamfix -truncate -plain
+
+# Test 2
+
+echo "Test 2"
+
+printf "P2\n3 3\n7\n0 1 2\n3 4 5\n6 7 0\n" |\
+  pamfix -truncate -plain
+
+printf "P2\n3 3\n7\n0 1 2\n3 4 5\n6 7\n" |\
+  pamfix -truncate -plain
+printf "P2\n3 3\n7\n0 1 2\n3 4 5\n6 7 8\n" |\
+  pamfix -truncate -plain
+
+printf "P2\n3 3\n7\n0 1 2\n3 4 5\n6 7 8\n" |\
+  pamfix -change -plain
+
+printf "P2\n3 3\n7\n0 1 2\n3 4 5\n6 7 8\n" |\
+ pamfix -clip -plain
+
+printf "P2\n3 3\n7\n0 1 2\n3 4 8\n0 0 0\n" |\
+  pamfix -change -truncate -plain
+
+printf "P2\n3 3\n7\n0 1 2\n3 4 8\n0 0 0\n" |\
+  pamfix -clip -truncate -plain
+
+# Test Invalid
+
+echo "Test invalid"
+
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line combination, invalid input" 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+printf "P2\n3 2\n7\n0 1 2\n6 7 8\n" | pamfix -change -clip > ${test_out} || \
+  printf "Expected failure 1";
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+printf "P1\n5 5\n" | pamfix -truncate -plain > ${test_out} || \
+  printf "Expected failure 2";
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+printf "P2\n3 3\255\n" | pamfix -truncate -plain > ${test_out} || \
+  printf "Expected failure 3";
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pamflip-pbm-roundtrip.ok b/test/pamflip-pbm-roundtrip.ok
new file mode 100644
index 00000000..c72e40d6
--- /dev/null
+++ b/test/pamflip-pbm-roundtrip.ok
@@ -0,0 +1,122 @@
+Test 1.  Should print 281226646 481 seven times
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+Test 2.  Should print 1576602925 8 fourteen times
+1576602925 8
+1576602925 8
+1576602925 8
+1576602925 8
+1576602925 8
+1576602925 8
+1576602925 8
+1576602925 8
+1576602925 8
+1576602925 8
+1576602925 8
+1576602925 8
+1576602925 8
+1576602925 8
+Test 3.  Should print N : 0 thirty-two times
+1 : 0
+2 : 0
+3 : 0
+4 : 0
+5 : 0
+6 : 0
+7 : 0
+8 : 0
+9 : 0
+10 : 0
+11 : 0
+12 : 0
+13 : 0
+14 : 0
+15 : 0
+16 : 0
+17 : 0
+18 : 0
+19 : 0
+20 : 0
+21 : 0
+22 : 0
+23 : 0
+24 : 0
+25 : 0
+26 : 0
+27 : 0
+28 : 0
+29 : 0
+30 : 0
+31 : 0
+32 : 0
+Test 4.  Should print N : 0 thirty-two times
+1 : 0
+2 : 0
+3 : 0
+4 : 0
+5 : 0
+6 : 0
+7 : 0
+8 : 0
+9 : 0
+10 : 0
+11 : 0
+12 : 0
+13 : 0
+14 : 0
+15 : 0
+16 : 0
+17 : 0
+18 : 0
+19 : 0
+20 : 0
+21 : 0
+22 : 0
+23 : 0
+24 : 0
+25 : 0
+26 : 0
+27 : 0
+28 : 0
+29 : 0
+30 : 0
+31 : 0
+32 : 0
+Test 5.  Should print N : 0 thirty-two times
+1 : 0
+2 : 0
+3 : 0
+4 : 0
+5 : 0
+6 : 0
+7 : 0
+8 : 0
+9 : 0
+10 : 0
+11 : 0
+12 : 0
+13 : 0
+14 : 0
+15 : 0
+16 : 0
+17 : 0
+18 : 0
+19 : 0
+20 : 0
+21 : 0
+22 : 0
+23 : 0
+24 : 0
+25 : 0
+26 : 0
+27 : 0
+28 : 0
+29 : 0
+30 : 0
+31 : 0
+32 : 0
diff --git a/test/pamflip-pbm-roundtrip.test b/test/pamflip-pbm-roundtrip.test
new file mode 100755
index 00000000..02a342cb
--- /dev/null
+++ b/test/pamflip-pbm-roundtrip.test
@@ -0,0 +1,74 @@
+#! /bin/sh
+# This script tests: pamflip
+# Also requires: pbmmake pbmnoise
+
+tmpdir=${tmpdir:-/tmp}
+dot_pbm=${tmpdir}/dot.pbm
+noise_pbm=${tmpdir}/noise.pbm
+
+echo "Test 1.  Should print 281226646 481 seven times"
+
+pamflip -null maze.pbm | cksum
+pamflip -lr maze.pbm | pamflip -lr | cksum
+pamflip -tb maze.pbm | pamflip -tb | cksum
+pamflip -r180 maze.pbm | pamflip -r180 | cksum
+pamflip -xy maze.pbm | pamflip -xy | cksum
+pamflip -r90 maze.pbm | pamflip -r90 | pamflip -r90 | pamflip -r90 | cksum
+pamflip -r270 maze.pbm | pamflip -r270 | pamflip -r270 | pamflip -r270 | cksum
+
+echo "Test 2.  Should print 1576602925 8 fourteen times"
+
+pbmmake -b 1 1 | tee ${dot_pbm} | cksum
+pamflip -null ${dot_pbm} | cksum
+
+# the next six aren't round-trip
+pamflip -lr ${dot_pbm} | cksum
+pamflip -tb ${dot_pbm} | cksum
+pamflip -r180 ${dot_pbm} | cksum
+pamflip -xy ${dot_pbm} | cksum
+pamflip -r90 ${dot_pbm} | cksum
+pamflip -r270 ${dot_pbm} | cksum
+
+pamflip -lr ${dot_pbm} | pamflip -lr | cksum
+pamflip -tb ${dot_pbm} | pamflip -tb | cksum
+pamflip -r180 ${dot_pbm} | pamflip -r180 | cksum
+pamflip -xy ${dot_pbm} | pamflip -xy | cksum
+pamflip -r90 ${dot_pbm} | pamflip -r90 | pamflip -r90 | pamflip -r90 | cksum
+pamflip -r270 ${dot_pbm} | pamflip -r270 | \
+    pamflip -r270 | pamflip -r270 | cksum
+
+rm ${dot_pbm}
+
+echo "Test 3.  Should print N : 0 thirty-two times"
+
+for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 \
+         20 21 22 23 24 25 26 27 28 29 30 31 32 
+  do
+  pbmnoise -randomseed=${i} -pack ${i} 3 > ${noise_pbm} && \
+    pamflip -lr ${noise_pbm} | pamflip -lr | cmp -s - ${noise_pbm}
+  echo $i : $?
+  rm ${noise_pbm}
+  done
+
+echo "Test 4.  Should print N : 0 thirty-two times"
+
+for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 \
+         20 21 22 23 24 25 26 27 28 29 30 31 32 
+  do
+  pbmnoise -randomseed=${i} -pack 7 ${i} > ${noise_pbm} && \
+    pamflip -tb ${noise_pbm} | pamflip -tb | cmp -s - ${noise_pbm}
+  echo $i : $?
+  rm ${noise_pbm}
+  done
+
+
+echo "Test 5.  Should print N : 0 thirty-two times"
+
+for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 \
+         20 21 22 23 24 25 26 27 28 29 30 31 32 
+  do
+  pbmnoise -randomseed=${i} -pack ${i} ${i} > ${noise_pbm} && \
+    pamflip -xy ${noise_pbm} | pamflip -xy | cmp -s - ${noise_pbm}
+  echo $i : $?
+  rm ${noise_pbm}
+  done
diff --git a/test/pamflip-roundtrip.ok b/test/pamflip-roundtrip.ok
index 653ab007..70ed6424 100644
--- a/test/pamflip-roundtrip.ok
+++ b/test/pamflip-roundtrip.ok
@@ -1,12 +1,65 @@
-1926073387 101484
-1926073387 101484
-1926073387 101484
-1926073387 101484
-1926073387 101484
-1926073387 101484
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
+Test 1.  Should print 1988581932 2989 fifteen times
+1988581932 2989
+1988581932 2989
+1988581932 2989
+1988581932 2989
+1988581932 2989
+1988581932 2989
+1988581932 2989
+1988581932 2989
+1988581932 2989
+1988581932 2989
+1988581932 2989
+1988581932 2989
+1988581932 2989
+1988581932 2989
+1988581932 2989
+Test 2.  Should print 2729474106 27 nine times
+2729474106 27
+2729474106 27
+2729474106 27
+2729474106 27
+2729474106 27
+2729474106 27
+2729474106 27
+2729474106 27
+2729474106 27
+Test 3.  Should print 1849343241 27 nine times
+1849343241 27
+1849343241 27
+1849343241 27
+1849343241 27
+1849343241 27
+1849343241 27
+1849343241 27
+1849343241 27
+1849343241 27
+Test 4.  Should print a single pixel PPM image maxval 65535 in 
+plain (ascii) format; then print 2434897823 19 fifteen times
+P3
+1 1
+65535
+1 10000 65535 
+2434897823 19
+2434897823 19
+2434897823 19
+2434897823 19
+2434897823 19
+2434897823 19
+2434897823 19
+2434897823 19
+2434897823 19
+2434897823 19
+2434897823 19
+2434897823 19
+2434897823 19
+2434897823 19
+2434897823 19
+Test 5.  Should print 281226646 481 seven times
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
diff --git a/test/pamflip-roundtrip.test b/test/pamflip-roundtrip.test
index c5a34ad9..6103f6fb 100755
--- a/test/pamflip-roundtrip.test
+++ b/test/pamflip-roundtrip.test
@@ -1,35 +1,115 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamflip
-# Also requires:
+# Also requires: ppmpat pamseq pamtopnm
 
+tmpdir=${tmpdir:-/tmp}
+tartan_ppm=${tmpdir}/test.ppm
+test1_pgm=${tmpdir}/test1.pgm
+test2_pgm=${tmpdir}/test2.pgm
+dot_ppm=${tmpdir}/dot.ppm
 
-pamflip -lr testimg.ppm | pamflip -lr | cksum
-pamflip -tb testimg.ppm | pamflip -tb | cksum
-pamflip -r180 testimg.ppm | \
-  pamflip -r180 | cksum
-pamflip -xy testimg.ppm | pamflip -xy | cksum
-pamflip -r90 testimg.ppm | \
-  pamflip -r90 | \
-  pamflip -r90 | \
-  pamflip -r90 | cksum
-pamflip -r270 testimg.ppm | \
-  pamflip -r270 | \
-  pamflip -r270 | \
-  pamflip -r270 | cksum
-
-pamflip -lr testgrid.pbm | \
-  pamflip -lr | cksum
-pamflip -tb testgrid.pbm | \
-  pamflip -tb | cksum
-pamflip -r180 testgrid.pbm | \
+echo "Test 1.  Should print 1988581932 2989 fifteen times"
+
+ppmpat -tartan -mesh \
+       -color=rgb:0/0/0,rgb:ff/00/ff,rgb:80/90/20 31 32 > ${tartan_ppm}
+
+pamflip -null ${tartan_ppm} | cksum
+pamflip -lr ${tartan_ppm} | pamflip -lr | cksum
+pamflip -tb ${tartan_ppm} | pamflip -tb | cksum
+pamflip -r180 ${tartan_ppm} | \
   pamflip -r180 | cksum
-pamflip -xy testgrid.pbm | \
-  pamflip -xy | cksum
-pamflip -r90 testgrid.pbm | \
-  pamflip -r90 | \
-  pamflip -r90 | \
-  pamflip -r90 | cksum
-pamflip -r270 testgrid.pbm | \
-  pamflip -r270 | \
-  pamflip -r270 | \
-  pamflip -r270 | cksum
+pamflip -xy ${tartan_ppm} | pamflip -xy | cksum
+pamflip -r90 ${tartan_ppm} | pamflip -r90 | \
+  pamflip -r90 | pamflip -r90 | cksum
+pamflip -r270 ${tartan_ppm} | pamflip -r270 | \
+  pamflip -r270 | pamflip -r270 | cksum
+pamflip -xform=leftright ${tartan_ppm} | pamflip -leftright | cksum
+pamflip -xform=topbottom ${tartan_ppm} | pamflip -topbottom | cksum
+pamflip -xform=transpose ${tartan_ppm} | pamflip -transpose | cksum
+pamflip -xform=leftright,leftright ${tartan_ppm} | cksum
+pamflip -xform=topbottom,topbottom ${tartan_ppm} | cksum
+pamflip -xform=transpose,transpose ${tartan_ppm} | cksum
+pamflip -tb ${tartan_ppm} | pamflip -lr | \
+  pamflip -xform=leftright,topbottom | cksum
+pamflip -tb ${tartan_ppm} | pamflip -lr | pamflip -xy | \
+  pamflip -xform=leftright,topbottom,transpose | cksum
+
+rm ${tartan_ppm}
+
+pamseq 1 15 | pamtopnm -assume > ${test1_pgm}
+
+echo "Test 2.  Should print 2729474106 27 nine times"
+
+pamflip -null ${test1_pgm} | cksum
+pamflip -lr ${test1_pgm} | pamflip -lr | cksum
+pamflip -tb ${test1_pgm} | pamflip -tb | cksum
+pamflip -r180 ${test1_pgm} | pamflip -r180 | cksum
+pamflip -xy ${test1_pgm} | pamflip -xy | cksum
+pamflip -r90 ${test1_pgm} | pamflip -r270 | cksum
+pamflip -r270 ${test1_pgm} | pamflip -r90 | cksum
+pamflip -r90 ${test1_pgm} | pamflip -r90 | \
+  pamflip -r90 | pamflip -r90 | cksum
+pamflip -r270 ${test1_pgm} | pamflip -r270 | \
+  pamflip -r270 | pamflip -r270 | cksum
+
+pamflip -r180 ${test1_pgm} > ${test2_pgm}
+rm ${test1_pgm}
+
+echo "Test 3.  Should print 1849343241 27 nine times"
+
+pamflip -null ${test2_pgm} | cksum
+pamflip -lr ${test2_pgm} | pamflip -lr | cksum
+pamflip -tb ${test2_pgm} | pamflip -tb | cksum
+pamflip -r180 ${test2_pgm} | pamflip -r180 | cksum
+pamflip -xy ${test2_pgm} | pamflip -xy | cksum
+pamflip -r90 ${test2_pgm} | pamflip -r270 | cksum
+pamflip -r270 ${test2_pgm} | pamflip -r90 | cksum
+pamflip -r90 ${test2_pgm} | pamflip -r90 | \
+    pamflip -r90 | pamflip -r90 | cksum
+pamflip -r270 ${test2_pgm} | pamflip -r270 | \
+    pamflip -r270 | pamflip -r270 | cksum
+
+rm ${test2_pgm}
+
+cat > ${dot_ppm} <<EOF
+P3
+1 1
+65535
+1 10000 65535
+EOF
+
+echo "Test 4.  Should print a single pixel PPM image maxval 65535 in "
+echo "plain (ascii) format; then print 2434897823 19 fifteen times"
+
+pamflip -null -plain ${dot_ppm}
+
+# These are not round-trip
+pamflip -null ${dot_ppm} | cksum
+pamflip -lr ${dot_ppm} | cksum
+pamflip -tb ${dot_ppm} | cksum
+pamflip -xy ${dot_ppm} | cksum
+pamflip -r90 ${dot_ppm} | cksum
+pamflip -r180 ${dot_ppm} | cksum
+pamflip -r270 ${dot_ppm} | cksum
+
+pamflip -lr ${dot_ppm} | pamflip -lr | cksum
+pamflip -tb ${dot_ppm} | pamflip -tb | cksum
+pamflip -r180 ${dot_ppm} | pamflip -r180 | cksum
+pamflip -xy ${dot_ppm} | pamflip -xy | cksum
+pamflip -r90 ${dot_ppm} | pamflip -r270 | cksum
+pamflip -r270 ${dot_ppm} | pamflip -r90 | cksum
+pamflip -r90 ${dot_ppm} | pamflip -r90 | pamflip -r90 | pamflip -r90 | cksum
+pamflip -r270 ${dot_ppm} | pamflip -r270 | \
+    pamflip -r270 | pamflip -r270 | cksum
+
+rm ${dot_ppm}
+
+echo "Test 5.  Should print 281226646 481 seven times"
+
+pamflip -null maze.pbm | cksum
+pamflip -lr maze.pbm | pamflip -lr | cksum
+pamflip -tb maze.pbm | pamflip -tb | cksum
+pamflip -r180 maze.pbm | pamflip -r180 | cksum
+pamflip -xy maze.pbm | pamflip -xy | cksum
+pamflip -r90 maze.pbm | pamflip -r90 | pamflip -r90 | pamflip -r90 | cksum
+pamflip -r270 maze.pbm | pamflip -r270 | pamflip -r270 | pamflip -r270 | cksum
diff --git a/test/pamflip1.ok b/test/pamflip1.ok
index 64e0407e..1169d773 100644
--- a/test/pamflip1.ok
+++ b/test/pamflip1.ok
@@ -1,5 +1,10 @@
-2116496681 101484
+Test 1.  Should print 1350702313 12336
+1350702313 12336
+Test 2.  Should print 1035759697 40048
+1035759697 40048
+Test 3.  Should print 217037000 101484
 217037000 101484
-2052917888 101484
-3375384165 41
-604323149 41
+Test 4.  Should print 1178735266 481
+1178735266 481
+Test 5.  Should print 2339906255 481
+2339906255 481
diff --git a/test/pamflip1.test b/test/pamflip1.test
index 840cac73..f8da3a74 100755
--- a/test/pamflip1.test
+++ b/test/pamflip1.test
@@ -1,15 +1,19 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamflip
-# Also requires:
+# Also requires: pamseq
 
+echo "Test 1.  Should print 1350702313 12336"
+pamseq 3 15 | pamflip -lr | cksum
 
-# Test 1.  Should print 2116496681 101484
-pamflip -lr testimg.ppm | cksum
-# Test 2.  Should print 217037000 101484
+echo "Test 2.  Should print 1035759697 40048"
+pamseq 4 9 | pamflip -tb | cksum
+
+echo "Test 3.  Should print 217037000 101484"
 pamflip -cw testimg.ppm | cksum
-# Test 3.  Should print 2052917888 101484
-pamflip -tb testimg.ppm | cksum
-# Test 4.  Should print 3375384165 41
-pamflip -lr testgrid.pbm | cksum
-# Test 5.  Should print 604323149 41
-pamflip -tb testgrid.pbm | cksum
+
+echo "Test 4.  Should print 1178735266 481"
+pamflip -lr maze.pbm | cksum
+
+echo "Test 5.  Should print 2339906255 481"
+pamflip -tb maze.pbm | cksum
+
diff --git a/test/pamflip2.ok b/test/pamflip2.ok
index d2ea501e..e3b4185c 100644
--- a/test/pamflip2.ok
+++ b/test/pamflip2.ok
@@ -1,3 +1,6 @@
-490797850 37
-3727293411 37
-3511745816 37
+Test 1.  Should print 748061765 465
+748061765 465
+Test 2.  Should print 3217647947 465
+3217647947 465
+Test 2.  Should print 1086015439 465
+1086015439 465
diff --git a/test/pamflip2.test b/test/pamflip2.test
index 4dddb770..0393d73e 100755
--- a/test/pamflip2.test
+++ b/test/pamflip2.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamflip
 # Also requires:
 
@@ -9,9 +9,11 @@
 ## optional SSE routine.  If you make a wrong choice during configure,
 ## this test will fail.
 
-# Test 1.  Should print 490797850 37
-pamflip -cw testgrid.pbm | cksum
-# Test 1.  Should print 3727293411 37
-pamflip -ccw testgrid.pbm | cksum
-# Test 2.  Should print 3511745816 37
-pamflip -xy testgrid.pbm | cksum
+echo "Test 1.  Should print 748061765 465"
+pamflip -cw maze.pbm | cksum
+
+echo "Test 2.  Should print 3217647947 465"
+pamflip -ccw maze.pbm | cksum
+
+echo "Test 2.  Should print 1086015439 465"
+pamflip -xy maze.pbm | cksum
diff --git a/test/pamfunc.ok b/test/pamfunc.ok
new file mode 100644
index 00000000..d358355b
--- /dev/null
+++ b/test/pamfunc.ok
@@ -0,0 +1,70 @@
+Test 1
+P2 16 1 15 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  
+P2 16 1 15 3 4 5 6 7 8 9 10 11 12 13 14 15 15 15 15  
+P2 16 1 15 0 0 0 0 1 2 3 4 5 6 7 8 9 10 11 12  
+P2 16 1 15 0 3 6 9 12 15 15 15 15 15 15 15 15 15 15 15  
+P2 16 1 15 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8  
+P2 16 1 15 0 1 2 3 4 5 6 6 6 6 6 6 6 6 6 6  
+P2 16 1 15 5 5 5 5 5 5 6 7 8 9 10 11 12 13 14 15  
+P2 16 1 15 0 2 4 6 8 10 12 14 0 2 4 6 8 10 12 14  
+P2 16 1 15 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7  
+P2 16 1 15 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7  
+P2 16 1 15 0 0 2 2 4 4 6 6 8 8 10 10 12 12 14 14  
+Test 2
+P1 8 1 01010101 
+P1 8 1 00000000 
+P1 8 1 11111111 
+P1 8 1 01010101 
+P1 8 1 01010101 
+P1 8 1 01010101 
+P1 8 1 00000000 
+P1 8 1 11111111 
+P1 8 1 11111111 
+P1 8 1 11111111 
+P1 8 1 11111111 
+Test 3 (-changemaxval)
+P2 16 1 30 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  
+P2 16 1 60 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  
+P1 8 1 01010101 
+P1 8 1 11111111 
+Test 4: Should print 1926073387 101484 eight times
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+Test 5: Should print 281226646 481 six times
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
+Expected failure 7 1
+Expected failure 8 1
+Expected failure 9 1
+Expected failure 10 1
+Expected failure 11 1
+Expected failure 12 1
+Expected failure 13 1
+Expected failure 14 1
+Expected failure 15 1
+Expected failure 16 1
+Expected failure 17 1
+Expected failure 18 1
+Expected failure 19 1
+Expected failure 20 1
+Expected failure 21 1
+Expected failure 22 1
+Expected failure 23 1
+Expected failure 24 1
diff --git a/test/pamfunc.test b/test/pamfunc.test
new file mode 100755
index 00000000..fe142be7
--- /dev/null
+++ b/test/pamfunc.test
@@ -0,0 +1,213 @@
+#! /bin/sh
+# This script tests: pamfunc
+# Also requires: pamseq pamtopnm pbmmake
+
+tmpdir=${tmpdir:-/tmp}
+input_pgm=${tmpdir}/input.pgm
+
+echo "Test 1"
+
+pamseq 1 15 | pamtopnm -assume > ${input_pgm}
+pamtopnm -plain ${input_pgm} | tr '\n' ' '; echo
+
+pamfunc -adder=3 -plain ${input_pgm} | tr '\n' ' '; echo
+pamfunc -subtractor=3 -plain ${input_pgm} | tr '\n' ' '; echo
+pamfunc -multiplier=3 -plain ${input_pgm} | tr '\n' ' '; echo
+pamfunc -divisor=2 -plain ${input_pgm} | tr '\n' ' '; echo
+pamfunc -max=6 -plain ${input_pgm} | tr '\n' ' '; echo
+pamfunc -min=5 -plain ${input_pgm} | tr '\n' ' '; echo
+
+pamfunc -shiftleft  1  -plain ${input_pgm} | tr '\n' ' '; echo
+pamfunc -shiftright 1  -plain ${input_pgm} | tr '\n' ' '; echo
+pamfunc -shiftleft  1 ${input_pgm} | pamfunc -shiftright 1 -plain | \
+  tr '\n' ' '; echo
+pamfunc -shiftright 1 ${input_pgm} | pamfunc -shiftleft 1  -plain | \
+  tr '\n' ' '; echo
+
+
+input_pbm=${tmpdir}/input.pbm
+
+echo "Test 2"
+
+pbmmake -g 8 1 > ${input_pbm}
+pamtopnm -plain ${input_pbm} | tr '\n' ' '; echo
+
+pamfunc -adder=1 -plain ${input_pbm} | tr '\n' ' '; echo
+pamfunc -subtractor=1 -plain ${input_pbm} | tr '\n' ' '; echo
+pamfunc -multiplier=1 -plain ${input_pbm} | tr '\n' ' '; echo
+pamfunc -divisor=1 -plain ${input_pbm} | tr '\n' ' '; echo
+pamfunc -max=1 -plain ${input_pbm} | tr '\n' ' '; echo
+pamfunc -min=1 -plain ${input_pbm} | tr '\n' ' '; echo
+
+pamfunc -shiftleft  1  -plain ${input_pbm} | tr '\n' ' '; echo
+pamfunc -shiftright 1  -plain ${input_pbm} | tr '\n' ' '; echo
+pamfunc -shiftleft  1 ${input_pbm} | pamfunc -shiftright 1 -plain | \
+  tr '\n' ' '; echo
+pamfunc -shiftright 1 ${input_pbm} | pamfunc -shiftleft 1  -plain | \
+  tr '\n' ' '; echo
+
+
+echo "Test 3 (-changemaxval)"
+
+pamfunc -divisor 2 -changemaxval ${input_pgm} -plain | \
+  tr '\n' ' '; echo
+pamfunc -multiplier 0.25 -changemaxval ${input_pgm} -plain | \
+  tr '\n' ' '; echo
+pamfunc -divisor 2 -changemaxval ${input_pbm} -plain | \
+  tr '\n' ' '; echo
+pamfunc -multiplier 0.25 -changemaxval ${input_pbm} -plain | \
+  tr '\n' ' '; echo
+
+rm ${input_pgm} ${input_pbm}
+
+echo "Test 4: Should print 1926073387 101484 eight times"
+
+cat testimg.ppm | cksum
+
+pamfunc -not testimg.ppm | pamfunc -not | cksum
+pamfunc -andmask 0xff testimg.ppm | cksum
+pamfunc -ormask  0x00 testimg.ppm | cksum
+pamfunc -xormask 0x00 testimg.ppm | cksum
+pamfunc -xormask 0xff testimg.ppm | pamfunc -xormask 0xff | cksum
+pamfunc -shiftleft  0 testimg.ppm | cksum
+pamfunc -shiftright 0 testimg.ppm | cksum
+
+
+echo "Test 5: Should print 281226646 481 six times"
+
+cat maze.pbm | cksum
+
+pamfunc -andmask  0x1 maze.pbm | cksum
+pamfunc -ormask   0x0 maze.pbm | cksum
+pamfunc -xormask  0x1 maze.pbm | pamfunc -xormask 0x1 | cksum
+
+pamfunc -shiftleft  0 maze.pbm | cksum
+pamfunc -shiftright 0 maze.pbm | cksum
+
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+echo "Test Invalid"
+
+test_out=${tmpdir}/test_out
+
+pamfunc -multiplier testimg.ppm > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfunc -multiplier=-1 testimg.ppm > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfunc -divisor testimg.ppm > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfunc -divisor=-20 testimg.ppm > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfunc -adder testimg.ppm > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfunc -adder 0.5 testimg.ppm > ${test_out} || \
+  printf "Expected failure 6"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfunc -subtractor testimg.ppm > ${test_out} || \
+  printf "Expected failure 7"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfunc -subtractor 0.1 testimg.ppm > ${test_out} || \
+  printf "Expected failure 8"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfunc -multiplier=1 -divisor=2 testimg.ppm > ${test_out} || \
+  printf "Expected failure 9"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfunc -adder=2 -subtractor=3 testimg.ppm > ${test_out} || \
+  printf "Expected failure 10"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfunc -min testimg.ppm > ${test_out} || \
+  printf "Expected failure 11"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfunc -max testimg.ppm > ${test_out} || \
+  printf "Expected failure 12"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfunc -andmask testimg.ppm > ${test_out} || \
+  printf "Expected failure 13"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfunc -ormask testimg.ppm > ${test_out} || \
+  printf "Expected failure 14"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfunc -xormask testimg.ppm > ${test_out} || \
+  printf "Expected failure 15"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfunc -not 1 testimg.ppm > ${test_out} || \
+  printf "Expected failure 16"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfunc -min=1 -max=2 testimg.ppm > ${test_out} || \
+  printf "Expected failure 17"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfunc -andmask=1 -ormask=0 testimg.ppm > ${test_out} || \
+  printf "Expected failure 18"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfunc -andmask=0xffff testimg.ppm > ${test_out} || \
+  printf "Expected failure 19"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfunc -shiftleft testimg.ppm > ${test_out} || \
+  printf "Expected failure 20"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfunc -shiftright testimg.ppm > ${test_out} || \
+  printf "Expected failure 21"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfunc -changemaxval testimg.ppm > ${test_out} || \
+  printf "Expected failure 22"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfunc -shiftleft=1 -shiftright=1 testimg.ppm > ${test_out} || \
+  printf "Expected failure 23"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamfunc -multiplier=0.5 -changemaxval=65535 testimg.ppm > ${test_out} || \
+  printf "Expected failure 24"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pamgauss.ok b/test/pamgauss.ok
index 153d4f6e..e31a2ee8 100644
--- a/test/pamgauss.ok
+++ b/test/pamgauss.ok
@@ -1,3 +1,4 @@
+Test 1
 3712518499 55
 3712518499 55
 1147844094 55
@@ -79,3 +80,12 @@
 4102007360 169
 3022719594 169
 1769176609 169
+Test 2
+stdin:	PAM, 3 by 3 by 1 maxval 255
+    Tuple type: GRAYSCALE
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
diff --git a/test/pamgauss.test b/test/pamgauss.test
index b48517c4..9400e928 100755
--- a/test/pamgauss.test
+++ b/test/pamgauss.test
@@ -1,12 +1,53 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamgauss
-# Also requires:
+# Also requires: pamfile
 
+echo "Test 1"
 
-for i in `seq 3 11`
-do
-for s in `seq 1 9`
-do
-pamgauss $i $i -oversample=1 -sigma=.$s | cksum
-done
-done
+for i in 3 4 5 6 7 8 9 10 11    # for i in `seq 3 11`
+  do
+  for s in 1 2 3 4 5 6 7 8 9    # for s in `seq 9`
+    do
+    pamgauss ${i} ${i} -oversample=1 -sigma=.${s} | cksum
+    done
+  done
+
+echo "Test 2"
+
+pamgauss 3 3 -sigma=0.5 -tupletype="GRAYSCALE" | pamfile
+
+
+echo "Test Invalid"
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+pamgauss 3 3               > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamgauss 3 3   -sigma=0    > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamgauss 3 3   -sigma=-1.5 > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamgauss 3     -sigma=0.5  > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamgauss 3 3 3 -sigma=0.5  > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pamhue-roundtrip.ok b/test/pamhue-roundtrip.ok
new file mode 100644
index 00000000..b341398c
--- /dev/null
+++ b/test/pamhue-roundtrip.ok
@@ -0,0 +1,10 @@
+input image
+1926073387 101484
+360
+1926073387 101484
+180
+1926073387 101484
+120
+1926073387 101484
+60
+1926073387 101484
diff --git a/test/pamhue-roundtrip.test b/test/pamhue-roundtrip.test
new file mode 100755
index 00000000..d68ee344
--- /dev/null
+++ b/test/pamhue-roundtrip.test
@@ -0,0 +1,19 @@
+#! /bin/sh
+# This script tests: pamhue
+# Also requires:
+
+echo input image
+cat testimg.ppm | cksum
+
+echo 360
+pamhue -huechange=360 testimg.ppm | cksum
+echo 180
+pamhue -huechange=180 testimg.ppm | pamhue -huechange=180 | cksum
+echo 120
+pamhue -huechange=120 testimg.ppm | pamhue -huechange=120 | \
+  pamhue -huechange=120 | cksum
+echo 60
+pamhue -huechange=60 testimg.ppm | pamhue -huechange=60 | \
+  pamhue -huechange=60 | pamhue -huechange=60 | \
+  pamhue -huechange=60 | pamhue -huechange=60 | cksum
+
diff --git a/test/pamhue.ok b/test/pamhue.ok
new file mode 100644
index 00000000..5935cc5e
--- /dev/null
+++ b/test/pamhue.ok
@@ -0,0 +1,36 @@
+Test 1
+1213482165 83
+1213482165 83
+Test 2
+ Summary: 8 colors: 1 black, 1 white, 0 gray, 6 color
+
+   r     g     b   	 lum 	 count  
+ ----- ----- ----- 	-----	------- 
+     0     0     0	    0	      1 
+     0     0   255	   29	      1 
+     0   255     0	  150	      1 
+     0   255   255	  179	      1 
+   255     0     0	   76	      1 
+   255     0   255	  105	      1 
+   255   255     0	  226	      1 
+   255   255   255	  255	      1 
+ Summary: 8 colors: 1 black, 1 white, 0 gray, 6 color
+
+   r     g     b   	 lum 	 count  
+ ----- ----- ----- 	-----	------- 
+     0     0     0	    0	      1 
+     0     0   255	   29	      1 
+     0   255     0	  150	      1 
+     0   255   255	  179	      1 
+   255     0     0	   76	      1 
+   255     0   255	  105	      1 
+   255   255     0	  226	      1 
+   255   255   255	  255	      1 
+Test 3
+0 0 : 0
+0 0 : 0
+Test 4
+0 0 : 0
+0 0 : 0
+Test Invalid
+Expected failure 1 1
diff --git a/test/pamhue.test b/test/pamhue.test
new file mode 100755
index 00000000..5979e414
--- /dev/null
+++ b/test/pamhue.test
@@ -0,0 +1,48 @@
+#! /bin/bash
+# This script tests: pamhue
+# Also requires: pamseq ppmhist pamdepth
+
+echo "Test 1"
+# Should print 1213482165 83 twice
+
+pamseq -tupletype=RGB 3 1 | pamdepth 255 | pamhue -huechange=60 | cksum
+pamseq -tupletype=RGB 3 1 | pamdepth 255 | pamhue -huechange=-300 | cksum
+
+echo "Test 2"
+
+pamseq -tupletype=RGB 3 1 | pamdepth 255 | ppmhist -sort=rgb
+pamseq -tupletype=RGB 3 1 | pamdepth 255 | pamhue -huechange=60 | \
+  ppmhist -sort=rgb
+
+echo "Test 3"
+# pamhue has no effect on monotone images
+# Should print 281226646 481 twice
+
+pamhue -huechange=45  maze.pbm | cmp -s - maze.pbm
+  echo ${PIPESTATUS[@]} ":" $?
+pamhue -huechange=180 maze.pbm | cmp -s - maze.pbm
+  echo ${PIPESTATUS[@]} ":" $?
+
+echo "Test 4"
+# spinning the color wheel by multiples of 360 leaves the image unchanged
+# Should print 1926073387 101484 twice
+
+pamhue -huechange=0 testimg.ppm   | cmp -s - testimg.ppm
+  echo ${PIPESTATUS[@]} ":" $?
+pamhue -huechange=360 testimg.ppm | cmp -s - testimg.ppm
+  echo ${PIPESTATUS[@]} ":" $?
+
+echo "Test Invalid"
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Omission of mandatory argument." 1>&2
+echo "An error message should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pamhue testimg.ppm  > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pammixmulti-identity.test b/test/pammixmulti-identity.test
index d205c359..21136fbe 100755
--- a/test/pammixmulti-identity.test
+++ b/test/pammixmulti-identity.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pammixmulti
 # Also requires: pgmnoise pnminvert pamsumm
 
diff --git a/test/pamrecolor.ok b/test/pamrecolor.ok
new file mode 100755
index 00000000..0a6b5413
--- /dev/null
+++ b/test/pamrecolor.ok
@@ -0,0 +1,11 @@
+Test 1. Should produce 3500040755 101532
+3500040755 101532
+Test 2. Should produce 3500040755 101532 twice
+3500040755 101532
+3500040755 101532
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
diff --git a/test/pamrecolor.test b/test/pamrecolor.test
new file mode 100755
index 00000000..a5fecc1f
--- /dev/null
+++ b/test/pamrecolor.test
@@ -0,0 +1,62 @@
+#! /bin/sh
+# This script tests: pamrecolor
+# Also requires: ppmtopgm pgmmake
+
+tmpdir=${tmpdir:-/tmp}
+base_pgm=${tmpdir}/base.pgm
+
+pgmmake 0.5 230 150 > ${base_pgm}
+
+echo "Test 1. Should produce 3500040755 101532"
+
+pamrecolor --colorfile=${base_pgm} testimg.ppm | cksum
+
+echo "Test 2. Should produce 3500040755 101532 twice"
+
+pamrecolor --targetcolor=rgb:80/80/80 testimg.ppm | cksum
+pamrecolor --colorspace=ntsc --targetcolor=rgb:80/80/80 testimg.ppm | cksum
+
+
+test_out=${tmpdir}/test_out
+truncated_file=${tmpdir}/truncated.txt
+echo P6 > ${truncated_file}
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pamrecolor --targetcolor=rgb:00/11/22 \
+           --colorfile=${base1_pgm} testimg.ppm > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamrecolor --rmult=0.3  --gmult=0.3  --bmult=0.3 \
+           --colorfile=${base1_pgm} testimg.ppm > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamrecolor --colorspace=void \
+           --targetcolor=rgb:80/80/80 testimg.ppm > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamrecolor --targetcolor=vague testimg.ppm > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamrecolor --colorfile=${truncated_file} testimg.ppm > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamrecolor --rmult=0.2989 --gmult=0.5866 testimg.ppm > ${test_out} || \
+  printf "Expected failure 6"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+rm ${base_pgm} ${truncated_file}
diff --git a/test/pamrestack.ok b/test/pamrestack.ok
new file mode 100644
index 00000000..07552913
--- /dev/null
+++ b/test/pamrestack.ok
@@ -0,0 +1,68 @@
+Test 1.
+P2
+24 1
+7
+0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 
+P2
+10 3
+7
+0 1 2 3 4 5 6 7 0 1 
+2 3 4 5 6 7 0 1 2 3 
+4 5 6 7 0 0 0 0 0 0 
+P2
+10 2
+7
+0 1 2 3 4 5 6 7 0 1 
+2 3 4 5 6 7 0 1 2 3 
+P2
+4 6
+7
+0 1 2 3 
+4 5 6 7 
+0 1 2 3 
+4 5 6 7 
+0 1 2 3 
+4 5 6 7 
+P2
+12 2
+7
+0 1 2 3 4 5 6 7 0 1 2 3 
+4 5 6 7 0 1 2 3 4 5 6 7 
+Test 2.  Should print 0 twelve times
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+Test 3.  Should produce 3141273448 431 fifteen times
+3141273448 431
+3141273448 431
+3141273448 431
+3141273448 431
+3141273448 431
+3141273448 431
+3141273448 431
+3141273448 431
+3141273448 431
+3141273448 431
+3141273448 431
+3141273448 431
+3141273448 431
+3141273448 431
+3141273448 431
+Test 4. Should produce 1768948962 101484 twice
+1768948962 101484
+1768948962 101484
+Test Invalid.
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
diff --git a/test/pamrestack.test b/test/pamrestack.test
new file mode 100755
index 00000000..2ebee49f
--- /dev/null
+++ b/test/pamrestack.test
@@ -0,0 +1,91 @@
+#! /bin/sh
+# This script tests: pamrestack
+# Also requires: pamfile pamflip pgmramp pnmcrop pnminvert
+
+tmpdir=${tmpdir:-/tmp}
+ramp_pgm=${tmpdir}/ramp.pgm
+ramp2_pgm=${tmpdir}/ramp2.pgm
+maze_singlerow_pbm=${tmpdir}/maze_singlerow.pbm
+maze_inverted_pbm=${tmpdir}/maze_inverted.pbm
+
+echo "Test 1."
+
+pgmramp -lr -maxval=7 8 3 | tee ${ramp_pgm} | pamrestack -plain
+pamrestack -width=10 -trim=fill -plain ${ramp_pgm}
+pamrestack -width=10 -trim=crop -plain ${ramp_pgm}
+pamrestack -width=4 -trim=fill -plain ${ramp_pgm}
+pamrestack -width=12 -trim=fill -plain ${ramp_pgm}
+
+echo "Test 2.  Should print 0 twelve times"
+
+for width in 2 4 5 8 12 24
+do
+    pamrestack -width=${width} -trim=crop ${ramp_pgm} > ${ramp2_pgm}
+    for flag in "-trim=crop"  "-trim=fill"
+    do
+    pamrestack -width=${width} ${flag} ${ramp2_pgm} | cmp -s - ${ramp2_pgm}
+    echo $?
+    done
+done
+
+rm ${ramp_pgm} ${ramp2_pgm}
+
+echo "Test 3.  Should produce 3141273448 431 fifteen times"
+
+# Invert maze.pbm because the lower right corner is black
+
+pixels=`pamfile -size maze.pbm | awk '{print $1 * $2}'`
+
+pnminvert maze.pbm | tee ${maze_inverted_pbm} | \
+  pamrestack | tee ${maze_singlerow_pbm} | pnmcrop -right -black | cksum
+for width in 1 2 3 100 1000 ${pixels} $((pixels -1))
+do
+pamrestack -width=${width} ${maze_inverted_pbm} | pamrestack | \
+  pnmcrop -right -black | cksum
+pamrestack -width=${width} ${maze_singlerow_pbm} | \
+  pamrestack | pnmcrop -right -black | cksum
+done
+
+rm ${maze_inverted_pbm} ${maze_singlerow_pbm}
+
+echo "Test 4. Should produce 1768948962 101484 twice"
+
+pamrestack -width=1 testimg.ppm | pamflip -ccw | cksum
+pamrestack \
+  -width=`pamfile -size testimg.ppm | cut -d " " -f2` testimg.ppm | \
+  pamrestack | cksum
+
+test_out=${tmpdir}/test_out
+echo "Test Invalid."
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pamrestack testgrid.pbm maze.pbm > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamrestack -abort \
+  -width=$((pixels * 2 + 1 )) maze.pbm > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamrestack -crop \
+  -width=$((pixels * 2 + 1)) maze.pbm > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamrestack -width=0 maze.pbm > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamrestack -width maze.pbm > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pamscale-filters1.test b/test/pamscale-filters1.test
index 63e0d012..c81dcf9a 100755
--- a/test/pamscale-filters1.test
+++ b/test/pamscale-filters1.test
@@ -1,12 +1,12 @@
 #! /bin/bash
 # This script tests: pamscale pamenlarge
-# Also requires: pamvalidate pnmpsnr
+# Also requires: pamfile pamvalidate pnmpsnr
 
 tmpdir=${tmpdir:-/tmp}
 enlarge_ppm=${tmpdir}/enlarge.ppm
 
-width_height=`pamfile -size testimg.ppm | \
-                awk '{print "-width="$1, "-height="$2}'`
+width_height=$(pamfile -size testimg.ppm | \
+                awk '{print "-width="$1, "-height="$2}')
 
 # The target values here were determined by running the test on a
 # 32-bit GNU/Linux system and subtracting 2.5 (dB) from observed
diff --git a/test/pamscale-filters2.test b/test/pamscale-filters2.test
index f7370020..d3cb8d6c 100755
--- a/test/pamscale-filters2.test
+++ b/test/pamscale-filters2.test
@@ -1,12 +1,12 @@
 #! /bin/bash
 # This script tests: pamscale pamstretch pamstretch-gen
-# Also requires: pamvalidate pnmpsnr
+# Also requires: pamfile pamvalidate pnmpsnr
 
 tmpdir=${tmpdir:-/tmp}
 stretch_ppm=${tmpdir}/stretch.ppm
 
-width_height=`pamfile -size testimg.ppm | \
-                awk '{print "-width="$1, "-height="$2}'`
+width_height=$(pamfile -size testimg.ppm | \
+               awk '{print "-width="$1, "-height="$2}')
 
 pamstretch -xscale=4 -yscale=3 testimg.ppm | pamvalidate > ${stretch_ppm}
 echo -xscale=4 -yscale=3 mitchell:  
diff --git a/test/pamscale-filters3.ok b/test/pamscale-filters3.ok
index 94d4ae96..182700cd 100644
--- a/test/pamscale-filters3.ok
+++ b/test/pamscale-filters3.ok
@@ -1,4 +1,3 @@
-failure : 0
 3.96 hermite:
 match
 match
diff --git a/test/pamscale-filters3.test b/test/pamscale-filters3.test
index 83198e2b..8d20e690 100755
--- a/test/pamscale-filters3.test
+++ b/test/pamscale-filters3.test
@@ -1,13 +1,12 @@
 #! /bin/bash
 # This script tests: pamscale pamstretch pamstretch-gen 
- # Also requires: pamvalidate pnmpsnr || \
-  echo failure ${PIPESTATUS[@]} ":" $?
+# Also requires: pamfile pamvalidate pnmpsnr
 
 tmpdir=${tmpdir:-/tmp}
 stretch_ppm=${tmpdir}/stretch.ppm
 
-width_height=`pamfile -size testimg.ppm | \
-                awk '{print "-width="$1, "-height="$2}'`
+width_height=$(pamfile -size testimg.ppm | \
+               awk '{print "-width="$1, "-height="$2}')
 
 pamstretch-gen 3.96 testimg.ppm | pamvalidate > ${stretch_ppm}
 echo 3.96 hermite:  
diff --git a/test/pamscale-reportonly.ok b/test/pamscale-reportonly.ok
index 00152411..bf5cde99 100644
--- a/test/pamscale-reportonly.ok
+++ b/test/pamscale-reportonly.ok
@@ -1,3 +1,4 @@
+Test 1
 227 149 3.000000 3.000000 681 447
 227 149 5.000000 5.000000 1135 745
 227 149 2.682819 2.684564 609 400
@@ -10,9 +11,10 @@
 227 149 2.819383 2.000000 640 298
 227 149 1.400881 2.684564 318 400
 227 149 1.000000 1.000000 227 149
-expected error
-expected error
-expected error
-expected error
-expected error
-expected error
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
diff --git a/test/pamscale-reportonly.test b/test/pamscale-reportonly.test
index 7205be2f..924fb7c2 100755
--- a/test/pamscale-reportonly.test
+++ b/test/pamscale-reportonly.test
@@ -1,7 +1,9 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamscale
 # Also requires:
 
+echo "Test 1"
+
 pamscale -reportonly 3 testimg.ppm
 pamscale -reportonly 5 testimg.ppm
 pamscale -reportonly -xysize 640 400 testimg.ppm
@@ -15,21 +17,50 @@ pamscale -reportonly -width=640 -yscale=2 testimg.ppm
 pamscale -reportonly -xscale=1.4 -height=400 testimg.ppm
 pamscale -reportonly -pixels=45000 testimg.ppm
 
-# expected error cases
+echo "Test Invalid"
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+# Expected failure cases
+
 echo 1>&2
 echo "Invalid command-line argument combinations." 1>&2
 echo "Error messages should appear below the line." 1>&2
 echo "-----------------------------------------------------------" 1>&2
-pamscale -reportonly -xsize=640 -ysize=400 -xscale=2 testimg.ppm || \
-  echo expected error
-pamscale -reportonly -xsize=640 -xscale=2 -yscale=3 testimg.ppm || \
-  echo expected error
-pamscale -reportonly -xsize=640 -ysize=400 -pixels=200000 testimg.ppm || \
-  echo expected error
-pamscale -reportonly -xsize=640 -ysize=400 -xysize 640 400 testimg.ppm || \
-  echo expected error
-pamscale -reportonly -xsize=640 -ysize=400 -xyfit  640 400 testimg.ppm || \
-  echo expected error
-pamscale -reportonly -xsize=640 -ysize=400 -xyfill 640 400 testimg.ppm || \
-  echo expected error
 
+pamscale -reportonly -xsize=640 -ysize=400 -xscale=2 testimg.ppm > \
+  ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamscale -reportonly -xsize=640 -xscale=2 -yscale=3 testimg.ppm > \
+  ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamscale -reportonly -xsize=640 -ysize=400 -pixels=200000 testimg.ppm \
+  > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamscale -reportonly -xsize=640 -ysize=400 -xysize 640 400 testimg.ppm \
+  > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamscale -reportonly -xsize=640 -ysize=400 -xyfit  640 400 testimg.ppm \
+  > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamscale -reportonly -xsize=640 -ysize=400 -xyfill 640 400 testimg.ppm \
+  > ${test_out} || \
+  printf "Expected failure 6"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pamseq.ok b/test/pamseq.ok
index 52bb3dd8..654596fb 100644
--- a/test/pamseq.ok
+++ b/test/pamseq.ok
@@ -1 +1,7 @@
+Test 1
 3929266994 304
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
diff --git a/test/pamseq.test b/test/pamseq.test
index e7b8060d..ce3d4995 100755
--- a/test/pamseq.test
+++ b/test/pamseq.test
@@ -1,6 +1,42 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamseq
 # Also requires:
 
+echo "Test 1"
 
 pamseq 1 255 | cksum
+
+echo "Test Invalid"
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+pamseq 1 > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamseq 0 255 > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamseq 3 0   > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+c64="0123456789012345678901234567890123456789012345678901234567890123"
+c256=${c64}${c64}${c64}${c64}
+
+# Tupletype string length=256
+
+pamseq -tupletype="${c256}" 3 15 > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pamshuffle.ok b/test/pamshuffle.ok
new file mode 100755
index 00000000..4f829744
--- /dev/null
+++ b/test/pamshuffle.ok
@@ -0,0 +1,19 @@
+Test 1.  Should print 1081361896 1432 five times
+1081361896 1432
+1081361896 1432
+1081361896 1432
+1081361896 1432
+1081361896 1432
+Test 2.  Should print 1936883899 143517 four times
+1936883899 143517
+1936883899 143517
+1936883899 143517
+1936883899 143517
+Test 3.  Should print nomatch three times
+nomatch
+nomatch
+nomatch
+Test Invalid.
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
diff --git a/test/pamshuffle.test b/test/pamshuffle.test
new file mode 100755
index 00000000..2941a9bc
--- /dev/null
+++ b/test/pamshuffle.test
@@ -0,0 +1,67 @@
+#! /bin/sh
+# This script tests: pamshuffle
+# Also requires: pamseq pamrestack pgmhist ppmhist pnmpsnr
+
+tmpdir=${tmpdir:-/tmp}
+seq_pam=${tmpdir}/seq.pam
+seq16_pam=${tmpdir}/seq16.pam
+
+out1_pam=${tmpdir}/out1.pam
+
+echo "Test 1.  Should print 1081361896 1432 five times"
+
+pgmhist -machine maze.pbm | cksum
+pamshuffle -randomseed=1 maze.pbm | pgmhist -machine | cksum
+pamshuffle -randomseed=2 maze.pbm | pgmhist -machine | cksum
+pamshuffle -column -randomseed=3 maze.pbm | pgmhist -machine | cksum
+pamrestack maze.pbm | pamshuffle -randomseed=3 | pgmhist -machine | cksum
+
+echo "Test 2.  Should print 1936883899 143517 four times"
+
+pamseq -tupletype="RGB" 3 15 > ${seq_pam}
+
+ppmhist -map ${seq_pam} | cksum
+pamshuffle -randomseed=2 ${seq_pam} | ppmhist -map | cksum
+pamrestack -width=16 -trim=abort ${seq_pam} | tee ${seq16_pam} | \
+  ppmhist -map | cksum
+pamshuffle -column -randomseed=3 ${seq16_pam} | ppmhist -map | cksum
+
+echo "Test 3.  Should print nomatch three times"
+
+pamshuffle -randomseed=$((100 +i)) ${seq16_pam} > ${out1_pam}
+pamshuffle -randomseed=${i} ${seq16_pam} | \
+pnmpsnr -target=14.0 ${out1_pam} -
+rm ${seq_pam} ${seq16_pam} ${out1_pam}
+
+pamshuffle -randomseed=$((100 +i)) testimg.ppm > ${out1_pam}
+pamshuffle -randomseed=${i} testimg.ppm | \
+  pnmpsnr -target=14.0 ${out1_pam} -
+rm ${out1_pam}
+
+pamshuffle -randomseed=$((100 +i)) -column testimg.ppm > ${out1_pam}
+pamshuffle -randomseed=${i} -column testimg.ppm | \
+  pnmpsnr -target=14.0 ${out1_pam} -
+rm ${out1_pam}
+
+test_out=${tmpdir}/test_out
+echo "Test Invalid."
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pamshuffle testimg.ppm testgrid.pbm > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamshuffle -randomseed -column testgrid.pbm > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamshuffle -randomseed=null testgrid.pbm > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pamslice-roundtrip.ok b/test/pamslice-roundtrip.ok
index eae64745..50e83b2a 100644
--- a/test/pamslice-roundtrip.ok
+++ b/test/pamslice-roundtrip.ok
@@ -1,4 +1,9 @@
-2425386270 41
-914327477 4864
-914327477 4864
-914327477 4864
+Test 1.  Should print 139976034 137 twice
+139976034 137
+139976034 137
+Test 2.  Should print 1624460505 574 three times
+1624460505 574
+1624460505 574
+1624460505 574
+Test 3.  Should print 1624460505 574
+1624460505 574
diff --git a/test/pamslice-roundtrip.test b/test/pamslice-roundtrip.test
index 6cb5533f..2b7929cf 100755
--- a/test/pamslice-roundtrip.test
+++ b/test/pamslice-roundtrip.test
@@ -1,75 +1,75 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamslice pamdeinterlace
-# Also requires: pamcut pamtopnm pamflip
+# Also requires: pamfile pamcut pamtopnm pamflip
 
-
-# Test 1.
-# Slice rows, one by one, out of testgrid.pbm.
+echo "Test 1.  Should print 139976034 137 twice"
+# Slice rows, one by one, out of maze.pbm.
 # Add header and reconstruct pbm image.
 # Note that in pamslice output 0 is white and 1 is black: opposite of PBM
-# Should print 2425386270 41
+
+mwidth=$(pamfile -size maze.pbm | cut -d " " -f 1)
+height=16
+
+pamcut -top=0 -left=0 -height=${height} maze.pbm | cksum
 
 (echo "P1"
- echo "14 16"
- seq 0 15 | while read i;
+ echo "${mwidth} ${height}"
+ for i in `seq 0 $((${height}-1))` 
      do
-     pamslice -row=$i testgrid.pbm
-     done | awk '{print $2}' | sed 'y/01/10/' ) \
+     pamslice -row=$i maze.pbm
+     done | cut -d" " -f2- | sed 'y/01/10/' ) \
  | pamtopnm | cksum
 
-# Test 2.
+
+echo "Test 2.  Should print 1624460505 574 three times"
 # Slice rows, one by one, out of ppm test image
 # We take a part out of testimg.ppm with pamcut for processing the
 # whole image takes much time.
 # Add header and reconstruct ppm image.
-# Should print 914327477 4864
 
 tmpdir=${tmpdir:-/tmp}
+test1711_ppm=${tmpdir}/test1711.ppm
 
-test4933_ppm=${tmpdir}/test4933.ppm
-
-pamcut 50 50 49 33 testimg.ppm > ${test4933_ppm}
+pamcut -left=50 -top=50 -width=17 -height=11 testimg.ppm | \
+  tee ${test1711_ppm} | cksum
 
 (echo "P3"
- echo "49 33"
+ echo "17 11"
  echo "255"
- seq 0 32 | while read i;
+ for i in 0 1 2 3 4 5 6 7 8 9 10   # for i in `seq 0 10`
      do
-     pamslice -row=$i ${test4933_ppm}
-     done | awk '{print $2, $3, $4}' ) \
+     pamslice -row=${i} ${test1711_ppm}
+     done | cut -d" " -f2- ) \
  | pamtopnm | cksum
 
 # Same as above test 2, but take cols instead of rows.
-# Should print 914327477 4864
 
 (echo "P3"
- echo "33 49"
+ echo "11 17"
  echo "255"
- seq 0 48 | while read i;
+ for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16    # for i in `seq 0 16`
      do
-     pamslice -col=$i ${test4933_ppm}
-     done | awk '{print $2, $3, $4}' ) \
- | pamflip -xy | cksum
+     pamslice -col=${i} ${test1711_ppm}
+     done | cut -d " " -f2- ) | pamflip -xy | cksum
 
-# Test 4.
+echo "Test 3.  Should print 1624460505 574"
 # Divide input image into two with pamdeinterlace and recombine.
 
 testeven_ppm=${tmpdir}/testeven.ppm
 testodd_ppm=${tmpdir}/testodd.ppm
 
-pamdeinterlace -takeodd ${test4933_ppm} > ${testodd_ppm}
-pamdeinterlace -takeeven ${test4933_ppm} > ${testeven_ppm}
+pamdeinterlace -takeodd ${test1711_ppm} > ${testodd_ppm}
+pamdeinterlace -takeeven ${test1711_ppm} > ${testeven_ppm}
 
-(echo "P3"
- echo "49 33"
- echo "255"
- ( seq 0 15 | while read i;
-     do
-     pamslice -row=$i ${testeven_ppm}
-     pamslice -row=$i ${testodd_ppm}
-     done
-     pamslice -row=16 ${testeven_ppm};
- )  | awk '{print $2, $3, $4}' ) \
- | pamtopnm | cksum
+( echo "P3"
+  echo "17 11"
+  echo "255"
+  ( for i in  0 1 2 3 4 
+        do
+        pamslice -row=${i} ${testeven_ppm}
+        pamslice -row=${i} ${testodd_ppm}
+        done
+        pamslice -row=5 ${testeven_ppm};
+  ) | cut -d" " -f2- ) | pamtopnm | cksum
 
-rm ${test4933_ppm} ${testodd_ppm} ${testeven_ppm}
+rm ${test1711_ppm} ${testodd_ppm} ${testeven_ppm}
diff --git a/test/pamstretch.test b/test/pamstretch.test
index 55dd4e9c..38e3a649 100755
--- a/test/pamstretch.test
+++ b/test/pamstretch.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamstretch
 # Also requires: pamcut pamfile
 
@@ -13,6 +13,7 @@ pamstretch -xscale=2 -blackedge testimg.ppm | cksum
 
 # Test 3.  Should print 3427416462 301047
 echo test 3
+tmpdir=${tmpdir:-/tmp}
 dropedge1_ppm=${tmpdir}/drop1.ppm
 pamstretch -yscale=3 -dropedge testimg.ppm | tee ${dropedge1_ppm} | cksum
 
@@ -39,10 +40,10 @@ blackedge_ppm=${tmpdir}/black.ppm
 pamstretch 3 testimg.ppm | tee ${stretch_ppm} | cksum
 pamstretch 3 -blackedge testimg.ppm | tee ${blackedge_ppm} | cksum
 pamstretch -xscale=3 -dropedge ${dropedge1_ppm} | tee ${dropedge_ppm} | cksum
-width_height=`pamfile -size ${dropedge_ppm} | \
-              awk '{print "-width="$1, "-height="$2}'`
+width_height=$(pamfile -size ${dropedge_ppm} | \
+              awk '{print "-width="$1, "-height="$2}')
 pamcut -left=0 -top=0 ${width_height} ${stretch_ppm} | cksum
 pamcut -left=0 -top=0 ${width_height} ${blackedge_ppm} | cksum
 pamcut -left=0 -top=0 ${width_height} ${dropedge_ppm} | cksum
 
-rm ${stretch_ppm} ${dropedge_ppm} ${dropedge1_ppm} ${blackedge_ppm}
\ No newline at end of file
+rm ${stretch_ppm} ${dropedge_ppm} ${dropedge1_ppm} ${blackedge_ppm}
diff --git a/test/pamsumm.ok b/test/pamsumm.ok
index 0643081b..b9ce0269 100644
--- a/test/pamsumm.ok
+++ b/test/pamsumm.ok
@@ -1,8 +1,20 @@
+Test 1.  Should print in order: 56, 0, 1, 0.250000
 56
 0
 1
 0.250000
+Test 2.  Should print in order: 1627, 0, 1, 0.483794
+1627
+0
+1
+0.483794
+Test 3.  Should print in order: 10772432, 15, 255, 106.164760
 10772432
 15
 255
 106.164760
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
diff --git a/test/pamsumm.test b/test/pamsumm.test
index a99dea0e..f482911a 100755
--- a/test/pamsumm.test
+++ b/test/pamsumm.test
@@ -1,14 +1,55 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamsumm
 # Also requires:
 
+echo "Test 1.  Should print in order: 56, 0, 1, 0.250000"
 
 for type in -sum -min -max -mean
   do
   pamsumm -brief $type testgrid.pbm
   done
 
+echo "Test 2.  Should print in order: 1627, 0, 1, 0.483794"
+
+for type in -sum -min -max -mean
+  do
+  pamsumm -brief $type maze.pbm
+  done
+
+echo "Test 3.  Should print in order: 10772432, 15, 255, 106.164760"
+
 for type in -sum -min -max -mean
   do
   pamsumm -brief $type testimg.ppm
   done
+
+
+echo "Test Invalid"
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pamsumm -sum -min  testimg.ppm > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamsumm -sum -max  testimg.ppm > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamsumm -mean -max testimg.ppm > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pamsumm            testimg.ppm > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pamtable.ok b/test/pamtable.ok
index c8db6002..d63c7720 100644
--- a/test/pamtable.ok
+++ b/test/pamtable.ok
@@ -1,3 +1,4 @@
+Test 1
 0 1 0 1 0 1 0 1 0 1 0 1 0 1
 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 1 0 1 0 1 0 1 0 1 0 1 0 1
@@ -15,10 +16,66 @@
 0 1 0 1 0 1 0 1 0 1 0 1 0 1
 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 
+Test 2
 0 0 0|0 0 1|0 0 2|0 1 0|0 1 1|0 1 2|0 2 0|0 2 1|0 2 2|1 0 0|1 0 1|1 0 2|1 1 0|1 1 1|1 1 2|1 2 0|1 2 1|1 2 2|2 0 0|2 0 1|2 0 2|2 1 0|2 1 1|2 1 2|2 2 0|2 2 1|2 2 2
 
+Test 3
 0 0 0 0|0 0 0 1|0 0 1 0|0 0 1 1|0 1 0 0|0 1 0 1|0 1 1 0|0 1 1 1|1 0 0 0|1 0 0 1|1 0 1 0|1 0 1 1|1 1 0 0|1 1 0 1|1 1 1 0|1 1 1 1
 
+Test 4
+(1) (0) (1) (0) (1)
+
+Test 5
+(1)
+(0)
+(1)
+(0)
+(1)
+(0)
+(1)
+(0)
+(1)
+(0)
+
+Test 6
+(0,0,0) (0,0,1) (0,0,2)
+(0,0,3) (0,1,0) (0,1,1)
+(0,1,2) (0,1,3) (0,2,0)
+(0,2,1) (0,2,2) (0,2,3)
+(0,3,0) (0,3,1) (0,3,2)
+(0,3,3) (1,0,0) (1,0,1)
+(1,0,2) (1,0,3) (1,1,0)
+(1,1,1) (1,1,2) (1,1,3)
+(1,2,0) (1,2,1) (1,2,2)
+(1,2,3) (1,3,0) (1,3,1)
+(1,3,2) (1,3,3) (2,0,0)
+(2,0,1) (2,0,2) (2,0,3)
+(2,1,0) (2,1,1) (2,1,2)
+(2,1,3) (2,2,0) (2,2,1)
+(2,2,2) (2,2,3) (2,3,0)
+(2,3,1) (2,3,2) (2,3,3)
+(3,0,0) (3,0,1) (3,0,2)
+(3,0,3) (3,1,0) (3,1,1)
+(3,1,2) (3,1,3) (3,2,0)
+(3,2,1) (3,2,2) (3,2,3)
+(3,3,0) (3,3,1) (3,3,2)
+(3,3,3) (0,0,0) (0,0,0)
+
+Test 7
+00 00|00 11|00 22|00 33|00 44|00 55|00 66|00 77
+00 88|00 99|00 aa|00 bb|00 cc|00 dd|00 ee|00 ff
+0a 00|0a 11|0a 22|0a 33|0a 44|0a 55|0a 66|0a 77
+0a 88|0a 99|0a aa|0a bb|0a cc|0a dd|0a ee|0a ff
+14 00|14 11|14 22|14 33|14 44|14 55|14 66|14 77
+14 88|14 99|14 aa|14 bb|14 cc|14 dd|14 ee|14 ff
+1e 00|1e 11|1e 22|1e 33|1e 44|1e 55|1e 66|1e 77
+1e 88|1e 99|1e aa|1e bb|1e cc|1e dd|1e ee|1e ff
+28 00|28 11|28 22|28 33|28 44|28 55|28 66|28 77
+28 88|28 99|28 aa|28 bb|28 cc|28 dd|28 ee|28 ff
+32 00|32 11|32 22|32 33|32 44|32 55|32 66|32 77
+32 88|32 99|32 aa|32 bb|32 cc|32 dd|32 ee|32 ff
+
+Test 8
 9 0
 0 9
 
@@ -64,3 +121,6 @@
 65535     0     0|    0     0 65535|    0     0 65535|    0 65535     0
 65535     0     0|    0     0 65535|    0     0 65535|    0 65535     0
 
+Test Invalid
+Should print: Expected failure 1
+Expected failure 1
diff --git a/test/pamtable.test b/test/pamtable.test
index 5c66b7ae..e948ad0c 100755
--- a/test/pamtable.test
+++ b/test/pamtable.test
@@ -1,20 +1,62 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamtable
-# Also requires: pamgradient pamseq pamdepth
+# Also requires: pamseq pamrestack pamdepth pbmmake ppmrainbow
 
+echo "Test 1"
 pamtable testgrid.pbm
+
 echo
+echo "Test 2"
 pamseq 3 2 -tupletype=RGB | pamtable
+
 echo
+echo "Test 3"
 pamseq 4 1 -tupletype=RGBA | pamtable
+
+echo
+echo "Test 4"
+pbmmake -gray 5 1 | pamtable -tuple
+
+echo
+echo "Test 5"
+pbmmake -gray 1 10 | pamtable -tuple
+
+echo
+echo "Test 6"
+pamseq 3 3 -tupletype=RGB | pamrestack -width=3 | pamtable -tuple
+
+echo
+echo "Test 7"
+pamseq 2 255 -max=50,255 -step=10,17 | pamrestack -width=8 | \
+  pamtable -hex
+
 echo
+echo "Test 8"
 for maxval in 9 10 9999 10000 65535
-  do pbmmake -g 2 2 | pamdepth $maxval | pamtable
-     echo
-     ppmrainbow -width=3 -height=2 -norepeat black white | \
-     pamdepth $maxval | pamtable
-     echo
-     ppmrainbow -width=4 -height=2 -norepeat red blue green | \
-     pamdepth $maxval | pamtable
-     echo
+  do
+  pbmmake -g 2 2 | pamdepth ${maxval} | pamtable
+  echo
+  ppmrainbow -width=3 -height=2 -norepeat black white | \
+    pamdepth ${maxval} | pamtable
+  echo
+  ppmrainbow -width=4 -height=2 -norepeat red blue green | \
+    pamdepth ${maxval} | pamtable
+  echo
   done
+
+echo "Test Invalid"
+
+test_out=${tmpdir}/test.out
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+echo "Should print: Expected failure 1"
+
+pamseq -tupletype="void" 1 1 | pamtable -tuple -hex > \
+  ${test_out} || \
+  printf "Expected failure"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pamtopam.ok b/test/pamtopam.ok
index dcb597d3..d84b2b6c 100644
--- a/test/pamtopam.ok
+++ b/test/pamtopam.ok
@@ -1,3 +1,18 @@
+Test 1. Should print five PAM headers
+P7
+WIDTH 14
+HEIGHT 16
+DEPTH 1
+MAXVAL 1
+TUPLTYPE BLACKANDWHITE
+ENDHDR
+P7
+WIDTH 1
+HEIGHT 1
+DEPTH 1
+MAXVAL 255
+TUPLTYPE GRAYSCALE
+ENDHDR
 P7
 WIDTH 227
 HEIGHT 149
@@ -6,11 +21,26 @@ MAXVAL 255
 TUPLTYPE RGB
 ENDHDR
 P7
-WIDTH 14
-HEIGHT 16
-DEPTH 1
+WIDTH 64
+HEIGHT 1
+DEPTH 2
+MAXVAL 7
+TUPLTYPE GRAYSCALE_ALPHA
+ENDHDR
+P7
+WIDTH 16
+HEIGHT 1
+DEPTH 4
 MAXVAL 1
-TUPLTYPE BLACKANDWHITE
+TUPLTYPE RGB_ALPHA
 ENDHDR
-1873848880 101532
+Test 2. Should print 2260748250 293
 2260748250 293
+Test 3. Should print 1873848880 101532
+1873848880 101532
+Test 4. Should print 1475247910 3432 twice
+1475247910 3432
+1475247910 3432
+Test 5. Should print 2347274358 101825 twice
+2347274358 101825
+2347274358 101825
diff --git a/test/pamtopam.test b/test/pamtopam.test
index 394d9904..c12470ec 100755
--- a/test/pamtopam.test
+++ b/test/pamtopam.test
@@ -1,10 +1,25 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamtopam
-# Also requires:
+# Also requires: pgmmake pamseq
 
+echo "Test 1. Should print five PAM headers"
 
-pamtopam < testimg.ppm  | sed '/ENDHDR/q'
 pamtopam < testgrid.pbm | sed '/ENDHDR/q'
+pgmmake 0.5 1 1 | pamtopam | sed '/ENDHDR/q'
+pamtopam < testimg.ppm  | sed '/ENDHDR/q'
+pamseq -tupletype="GRAYSCALE_ALPHA" 2 7 | pamtopam | sed '/ENDHDR/q'
+pamseq -tupletype="RGB_ALPHA" 4 1 | pamtopam | sed '/ENDHDR/q'
 
-pamtopam < testimg.ppm   | cksum
+echo "Test 2. Should print 2260748250 293"
 pamtopam < testgrid.pbm  | cksum
+
+echo "Test 3. Should print 1873848880 101532"
+pamtopam < testimg.ppm   | cksum
+
+echo "Test 4. Should print 1475247910 3432 twice"
+pamtopam < maze.pbm  | cksum
+pamtopam < maze.pbm  | pamtopam | cksum
+
+echo "Test 5. Should print 2347274358 101825 twice"
+cat testgrid.pbm testimg.ppm | pamtopam | cksum
+( pamtopam  < testgrid.pbm; pamtopam < testimg.ppm ) | cksum
diff --git a/test/pamtopdbimg.test b/test/pamtopdbimg.test
index 8de78a70..d6c105bf 100755
--- a/test/pamtopdbimg.test
+++ b/test/pamtopdbimg.test
@@ -21,7 +21,7 @@ echo high compression
 pgmmake 0.5 -maxval=15 160 160 > ${mono_pgm}
 for flag in "-compressed" "-maybecompressed" "-uncompressed"
    do
-   pamtopdbimg $flag ${mono_pgm} | wc -c
+   pamtopdbimg $flag ${mono_pgm} | wc -c | tr -d ' '
    done  | uniq -c | awk '{print $1}'
 rm ${mono_pgm}
 
@@ -82,13 +82,13 @@ awk 'BEGIN { ABC="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 
 head -c 65533 ${text65597} > ${text65533}
 head -c 65534 ${text65597} > ${text65534}
-pamtopdbimg -uncompressed testgrid.pbm | \
+pamtopdbimg -uncompressed maze.pbm | \
   wc -c | tr -d ' '
   echo ${PIPESTATUS[0]}
-pamtopdbimg -uncompressed -notefile=${text65533} testgrid.pbm | \
+pamtopdbimg -uncompressed -notefile=${text65533} maze.pbm | \
   wc -c | tr -d ' '
   echo ${PIPESTATUS[0]}
-pamtopdbimg -uncompressed -notefile=${text65534} testgrid.pbm | \
+pamtopdbimg -uncompressed -notefile=${text65534} maze.pbm | \
   wc -c | tr -d ' '
   echo ${PIPESTATUS[0]}
 
diff --git a/test/pamundice.ok b/test/pamundice.ok
new file mode 100644
index 00000000..1234431d
--- /dev/null
+++ b/test/pamundice.ok
@@ -0,0 +1,27 @@
+Test 1.  Should print 2096818803 2818 twice
+2096818803 2818
+2096818803 2818
+Test 2.  Should print 2096818803 2818 twice
+2096818803 2818
+2096818803 2818
+Test 3.  Should print 2096818803 2818 twice
+2096818803 2818
+2096818803 2818
+Test 4.  Should print 2434390296 4436 four times
+2434390296 4436
+2434390296 4436
+2434390296 4436
+2434390296 4436
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
+Expected failure 7 1
+Expected failure 8 1
+Expected failure 9 1
+Expected failure 10 1
+Expected failure 11 1
+Expected failure 12 1
diff --git a/test/pamundice.test b/test/pamundice.test
new file mode 100755
index 00000000..ba532c30
--- /dev/null
+++ b/test/pamundice.test
@@ -0,0 +1,202 @@
+#! /bin/sh
+# This script tests: pamundice
+# Also requires: pamfile pgmmake pnmtile pamcat
+
+tmpdir=${tmpdir:-/tmp}
+fname_stem=${tmpdir}/part
+
+echo "Test 1.  Should print 2096818803 2818 twice"
+
+for x in 0 1 2
+  do for y in 0 1 2 3 4
+    do
+    pgmmake "."$(( x* 25 + y )) 11 17 > ${fname_stem}_${y}_${x}.pgm
+    done
+  done
+
+pamundice -across=3 -down=5 ${fname_stem}"_%1d_%1a".pgm | cksum
+
+ls ${fname_stem}_?_?.pgm | \
+    pamundice -across=3 -down=5 -listfile=- | cksum
+
+echo "Test 2.  Should print 2096818803 2818 twice"
+
+tempfile=${tmpdir}/temp
+
+for y in 0 1 2 3 4
+  do
+  pamundice -across=3 ${fname_stem}"_"$y"_%1a".pgm > ${tempfile}_"$y"
+  done
+
+pamcat -tb ${tempfile}_[01234] | cksum
+rm ${tempfile}_[01234]
+
+# Note: the following 2 are valid.  There should not be warning messages.
+
+for x in 0 1 2
+  do
+  pamundice -down=5 ${fname_stem}"_%1d_"$x.pgm > ${tempfile}"_"$x
+  done
+
+pamcat -lr ${tempfile}_[012] | cksum
+rm ${tempfile}_[012]
+
+rm ${fname_stem}_?_?.pgm
+
+echo "Test 3.  Should print 2096818803 2818 twice"
+
+for x in 0 1
+  do for y in 0 1 2 3 4
+    do
+    pgmmake "."$(( x* 25 + y )) 12 17 > ${fname_stem}_${y}_${x}.pgm
+    done
+  done
+
+for x in 2
+  do for y in 0 1 2 3 4
+    do
+    pgmmake "."$(( x* 25 + y )) 11 17 > ${fname_stem}_${y}_${x}.pgm
+    done
+  done
+
+pamundice -across=3 -down=5 \
+  -hoverlap=1 ${fname_stem}"_%1d_%1a".pgm | cksum
+
+rm ${fname_stem}_?_?.pgm
+
+for x in 0 1 2
+  do for y in 0 1 2 3
+    do
+    pgmmake "."$(( x* 25 + y )) 11 18 > ${fname_stem}_${y}_${x}.pgm
+    done
+  done
+
+for x in 0 1 2
+  do for y in 4
+    do
+    pgmmake "."$(( x* 25 + y )) 11 17 > ${fname_stem}_${y}_${x}.pgm
+    done
+  done
+
+pamundice -across=3 -down=5 \
+  -voverlap=1 ${fname_stem}"_%1d_%1a".pgm | cksum
+
+rm ${fname_stem}_?_?.pgm
+
+
+# Test 4.
+echo "Test 4.  Should print 2434390296 4436 four times"
+
+msize=$(pamfile -size maze.pbm)
+mw=$(echo ${msize} | cut -d " " -f 1)
+mh=$(echo ${msize} | cut -d " " -f 2)
+
+pnmtile $((${mw} * 2)) $((${mh} * 5)) maze.pbm | cksum
+
+for x in 0 1
+  do for y in 0 1 2 3 4
+    do cp maze.pbm ${fname_stem}_${y}_${x}.pbm; done
+  done
+
+for i in 0 1 2 3 4 5 6 7 8 9
+  do
+  echo maze.pbm
+  done | pamundice -down=5 -across=2 -listfile=- | cksum
+
+pamundice -down=5 -across=2 ${fname_stem}_"%1d"_"%1a".pbm | cksum
+
+echo "A warning message should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pamundice -down=5 -across=2 maze.pbm | cksum
+
+
+# Test Invalid.
+echo "Test Invalid"
+
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+# No input file pattern specified
+pamundice -down=5 -across=2 > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# -down=0
+pamundice -down=0 -across=2 ${fname_stem}_"%1d"_"%1a".pbm > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# -across=0
+pamundice -down=5 -across=0 ${fname_stem}_"%1d"_"%1a".pbm > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# -down too large
+pamundice -down=6 -across=2 ${fname_stem}_"%1d"_"%1a".pbm > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# -across too large
+pamundice -down=5 -across=3 ${fname_stem}_"%1d"_"%1a".pbm > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# precision does not match
+pamundice -down=5 -across=2 ${fname_stem}_"%2d"_"%2a".pbm > ${test_out} || \
+  printf "Expected failure 6"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# precision set to zero
+pamundice -down=5 -across=2 ${fname_stem}_"%0d"_"%0a".pbm > ${test_out} || \
+  printf "Expected failure 7"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# no precision
+pamundice -down=5 -across=2 ${fname_stem}_"%d"_"%a".pbm > ${test_out} || \
+  printf "Expected failure 8"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# -hoverlap too large
+pamundice -down=5 -across=2 -hoverlap=$((${mw}+1)) \
+  ${fname_stem}_"%1d"_"%1a".pbm > ${test_out} || \
+  printf "Expected failure 9"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# -voverlap too large
+pamundice -down=5 -across=2 -voverlap=$((${mh}+1)) \
+  ${fname_stem}_"%1d"_"%1a".pbm > ${test_out} || \
+  printf "Expected failure 10"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# corrupt listfile : file names do not exist
+for i in 0 1 2 3 4 5 6 7 8 9
+  do
+  mktemp -u XXXXXXXXXX.${i} || echo ":::::::::::"${i}":::::::::::"
+  done | pamundice -down=5 -across=2 -listfile=- > ${test_out} || \
+  printf "Expected failure 11"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# listfile with insufficient lines (insufficient file entries)
+ls ${fname_stem}_*_*.pbm | head -n 9 | \
+  pamundice -down=5 -across=2 -listfile=- > ${test_out} || \
+  printf "Expected failure 12"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+rm ${fname_stem}*.pbm
diff --git a/test/pamvalidate.ok b/test/pamvalidate.ok
new file mode 100644
index 00000000..98b0f70a
--- /dev/null
+++ b/test/pamvalidate.ok
@@ -0,0 +1,13 @@
+valid
+P1
+5 5
+01010
+10101
+01010
+00000
+11111
+not valid: Should print 0 four times
+0
+0
+0
+0
diff --git a/test/pamvalidate.test b/test/pamvalidate.test
new file mode 100755
index 00000000..708197da
--- /dev/null
+++ b/test/pamvalidate.test
@@ -0,0 +1,20 @@
+#! /bin/sh
+# This script tests: pamvalidate
+# Also requires:
+
+echo "valid"
+printf "P1\n5 5\n01010\n10101\n01010\n00000\n11111\n" | pamvalidate -plain
+
+echo "not valid: Should print 0 four times"
+printf "P1\n5 5\n01010\n10101\n01010\n00000\n1111\n"  | pamvalidate | \
+  wc -c | tr -d ' '
+
+printf "P1\n5 5\n01010\n10102\n01010\n00001\n11111\n" | pamvalidate | \
+  wc -c | tr -d ' '
+
+printf "P1\n5\n01010\n10101\n01010\n00000\n11111\n" | pamvalidate | \
+  wc -c | tr -d ' '
+
+printf "P1\n5 5" | pamvalidate | wc -c | tr -d ' '
+
+
diff --git a/test/pbm-misc-converters.ok b/test/pbm-misc-converters.ok
index a137102f..1ae5d817 100644
--- a/test/pbm-misc-converters.ok
+++ b/test/pbm-misc-converters.ok
@@ -1,27 +1,58 @@
-1638343024 43
-2141128209 77
-2542756600 120
-3102495729 32
-2414506375 47
-3241517214 145
-1454090165 46
-1436169407 46
-1454090165 46
-2912484298 46
-3576177652 52
-1478164284 52
-3213223606 141
-3213223606 141
-3213223606 141
-1463148415 108
-203901789 30
-3732005859 92
-2459345477 86
-424535246 92
-609530223 252
-4195053594 248
-2602382240 43
-129620534 361
-2256096096 80
-1349121911 149
+pbmto10x
+3017587389 501
+3017587389 501
+pbmto4425
+2529120683 622
+2529120683 622
+pbmtoascii
+2361485126 1740
+2361485126 1740
+4017331268 450
+pbmtodjvurle
+2707446245 1744
+2707446245 1744
+pbmtoepson
+2100180787 510
+2100180787 510
+2963515498 510
+2100180787 510
+1513122412 510
+pbmtogo
+34750317 804
+34750317 804
+pbmtoibm23xx
+1731023722 546
+1731023722 546
+pbmtolj
+1540204160 762
+1540204160 762
+908699854 763
+908699854 763
+pbmtoln03
+1554612498 636
+1554612498 636
+pbmtomatrixorbital
+1574732995 458
+1574732995 458
+pbmtonokia
+3813814418 972
+3813814418 972
+1385394245 966
+3924854157 972
+3970098281 3388
+167529797 3384
+2260274013 483
+pbmtoplot
+2120102625 5318
+2120102625 5318
+pbmtoptx
+541430122 708
+541430122 708
+pbmtozinc
+2297581967 1725
+2297581967 1725
+pbmtobbnbg
+3481527833 672
+pbmtoppa
+3955750161 284701
 3955750161 284701
diff --git a/test/pbm-misc-converters.test b/test/pbm-misc-converters.test
index aa71489b..ba350bc7 100755
--- a/test/pbm-misc-converters.test
+++ b/test/pbm-misc-converters.test
@@ -1,8 +1,8 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pbmto10x pbmto4425 pbmtoascii pbmtobbnbg
 # This script tests: pbmtodjvurle pbmtoepson pbmtogo pbmtoibm23xx
 # This script tests: pbmtolj pbmtoln03 pbmtomatrixorbital pbmtonokia
-# This script tests: pbmtoplot pbmtoptx pbmtozinc
+# This script tests: pbmtoplot pbmtoppa pbmtoptx pbmtozinc
 # Also requires: pbmpage
 
 # Note: one-way test.
@@ -10,31 +10,89 @@
 # direction.  We check whether the output is unchanged from older
 # versions.
 
-pbmto10x             testgrid.pbm | cksum
-pbmto4425            testgrid.pbm | cksum
-pbmtoascii           testgrid.pbm | cksum
-pbmtoascii -2x4      testgrid.pbm | cksum
-pbmtobbnbg         < testgrid.pbm | cksum
-pbmtodjvurle         testgrid.pbm | cksum
-pbmtoepson           testgrid.pbm | cksum
-pbmtoepson -protocol=escp   testgrid.pbm | cksum
-pbmtoepson -protocol=escp9  testgrid.pbm | cksum
-pbmtoepson -nonadjacent     testgrid.pbm | cksum
-pbmtogo              testgrid.pbm | cksum
-pbmtoibm23xx -xres=60 -yres=60 testgrid.pbm | cksum
-pbmtolj              testgrid.pbm | cksum
-pbmtolj  -packbits   testgrid.pbm | cksum
-pbmtolj  -compress   testgrid.pbm | cksum
-pbmtoln03            testgrid.pbm | cksum
-pbmtomatrixorbital < testgrid.pbm | cksum
-pbmtonokia -fmt HEX_NOL testgrid.pbm | cksum
-pbmtonokia -fmt HEX_NGG testgrid.pbm | cksum
-pbmtonokia -fmt HEX_NPM testgrid.pbm | cksum
-pbmtonokia -fmt NOL  testgrid.pbm | cksum
-pbmtonokia -fmt NGG  testgrid.pbm | cksum
-pbmtonokia -fmt NPM  testgrid.pbm | cksum
-pbmtoplot            testgrid.pbm | cksum
-pbmtoptx             testgrid.pbm | cksum
-pbmtozinc            testgrid.pbm | cksum
-
-(pbmpage 1; pbmpage 2; pbmpage 3) | pbmtoppa | cksum
+echo "pbmto10x"
+pbmto10x               maze.pbm | cksum
+pbmto10x             < maze.pbm | cksum
+
+echo "pbmto4425"
+pbmto4425              maze.pbm | cksum
+pbmto4425            < maze.pbm | cksum
+
+# Asciitopgm works in the opposite direction, but the round-trip is not accurate
+
+echo "pbmtoascii"
+pbmtoascii             maze.pbm | cksum
+pbmtoascii           < maze.pbm | cksum
+pbmtoascii -2x4        maze.pbm | cksum
+
+echo "pbmtodjvurle"
+pbmtodjvurle           maze.pbm | cksum
+pbmtodjvurle         < maze.pbm | cksum
+
+echo "pbmtoepson"
+pbmtoepson             maze.pbm | cksum
+pbmtoepson           < maze.pbm | cksum
+pbmtoepson -protocol=escp   maze.pbm | cksum
+pbmtoepson -protocol=escp9  maze.pbm | cksum
+pbmtoepson -nonadjacent     maze.pbm | cksum
+
+echo "pbmtogo"
+pbmtogo                maze.pbm | cksum
+pbmtogo              < maze.pbm | cksum
+
+echo "pbmtoibm23xx"
+pbmtoibm23xx -xres=60 -yres=60    maze.pbm | cksum
+pbmtoibm23xx -xres=60 -yres=60  < maze.pbm | cksum
+
+echo "pbmtolj"
+pbmtolj                maze.pbm | cksum
+pbmtolj              < maze.pbm | cksum
+pbmtolj  -packbits     maze.pbm | cksum
+pbmtolj  -compress     maze.pbm | cksum
+
+echo "pbmtoln03"
+pbmtoln03              maze.pbm | cksum
+pbmtoln03            < maze.pbm | cksum
+
+echo "pbmtomatrixorbital"
+pbmtomatrixorbital     maze.pbm | cksum
+pbmtomatrixorbital   < maze.pbm | cksum
+
+echo "pbmtonokia"
+pbmtonokia -fmt HEX_NOL   maze.pbm | cksum
+pbmtonokia -fmt HEX_NOL < maze.pbm | cksum
+pbmtonokia -fmt HEX_NGG   maze.pbm | cksum
+pbmtonokia -fmt HEX_NPM   maze.pbm | cksum
+pbmtonokia -fmt NOL       maze.pbm | cksum
+pbmtonokia -fmt NGG       maze.pbm | cksum
+pbmtonokia -fmt NPM       maze.pbm | cksum
+
+echo "pbmtoplot"
+pbmtoplot              maze.pbm | cksum
+pbmtoplot            < maze.pbm | cksum
+
+echo "pbmtoptx"
+pbmtoptx               maze.pbm | cksum
+pbmtoptx             < maze.pbm | cksum
+
+# pbmtozinc embeds input filename in the output
+
+echo "pbmtozinc"
+pbmtozinc   maze.pbm | cksum
+pbmtozinc < maze.pbm | sed 's/noname/maze/' | cksum
+
+# pbmtobbnbg input must be from stdin
+
+echo "pbmtobbnbg"
+pbmtobbnbg < maze.pbm | cksum
+
+# pbmtoppa has constraints on what can be accepted as input; maze.pbm is not accepted
+# pbmpage produces suitable input
+
+tmpdir=${tmpdir:-/tmp}
+testpage_pbm=${tmpdir}/testpage.pbm
+
+echo "pbmtoppa"
+(pbmpage 1; pbmpage 2; pbmpage 3) | tee ${testpage_pbm} | pbmtoppa | cksum
+pbmtoppa ${testpage_pbm} | cksum
+rm ${testpage_pbm}
diff --git a/test/pbm-ppm-roundtrip.ok b/test/pbm-ppm-roundtrip.ok
new file mode 100644
index 00000000..91c502b5
--- /dev/null
+++ b/test/pbm-ppm-roundtrip.ok
@@ -0,0 +1,39 @@
+Test 1.  Should print 281226646 481 five times.
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+Test 2.  Should print three all-white, then three all-black PBM images
+P1
+7 3
+0000000
+0000000
+0000000
+
+P1
+7 3
+0000000
+0000000
+0000000
+
+P1
+7 3
+0000000
+0000000
+0000000
+
+P1
+17 2
+11111111111111111
+11111111111111111
+
+P1
+17 2
+11111111111111111
+11111111111111111
+
+P1
+17 2
+11111111111111111
+11111111111111111
diff --git a/test/pbm-ppm-roundtrip.test b/test/pbm-ppm-roundtrip.test
new file mode 100755
index 00000000..9a3ff79f
--- /dev/null
+++ b/test/pbm-ppm-roundtrip.test
@@ -0,0 +1,34 @@
+#! /bin/sh
+# This script tests: pgmtoppm ppmtopgm ppmtoppm pgmtopbm
+# Also requires: pbmmake ppmcolormask pnminvert
+
+echo "Test 1.  Should print 281226646 481 five times."
+
+cat maze.pbm | cksum
+pgmtoppm black-white maze.pbm | ppmtopgm | \
+  pgmtopbm -th -val=0.5 | cksum
+pgmtoppm white-black maze.pbm | ppmtopgm | \
+  pgmtopbm -th -val=0.5 | pnminvert | cksum
+pgmtoppm white-black maze.pbm | ppmcolormask white | cksum
+ppmtoppm < maze.pbm | ppmtopgm | pgmtopbm -th -val=0.5 | cksum
+
+echo "Test 2.  Should print three all-white, then three all-black PBM images"
+
+pbmmake -w 7 3  -plain
+echo
+
+pbmmake -w 7 3 | pgmtoppm black-white | ppmtopgm | \
+  pgmtopbm -th -val=0.5 -plain
+echo
+pbmmake -w 7 3 | ppmtoppm | ppmtopgm | \
+  pgmtopbm -th -val=0.5 -plain
+echo
+
+pbmmake -b 17 2 -plain
+echo
+
+pbmmake -b 17 2 | pgmtoppm black-white | ppmtopgm | \
+  pgmtopbm -th -val=0.5 -plain
+echo
+pbmmake -b 17 2 | ppmtoppm | ppmtopgm | \
+  pgmtopbm -th -val=0.5 -plain
diff --git a/test/pbmclean.ok b/test/pbmclean.ok
index 71b622d0..17ee0338 100644
--- a/test/pbmclean.ok
+++ b/test/pbmclean.ok
@@ -1,3 +1,4 @@
+Test 1
 P1
 7 7
 1111111
@@ -70,4 +71,18 @@ P1
 0000000
 0000000
 0000000
+Test 2
 760076056 4210813
+Test 3
+2096087149 5051
+2096087149 5051
+3762787431 5051
+1966718 5051
+544084261 5051
+2970762900 5051
+2571756059 5051
+2571756059 5051
+436062787 5051
+4188415575 5051
+Test Invalid
+Expected failure 1 1
diff --git a/test/pbmclean.test b/test/pbmclean.test
index a8e469b1..5eba68e0 100755
--- a/test/pbmclean.test
+++ b/test/pbmclean.test
@@ -1,19 +1,53 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pbmclean
-# Also requires: pbmmake pbmpage pnmmargin pnmpad
+# Also requires: pbmmake pbmpage pbmtext pnmmargin pnmpad
 
 
 tmpdir=${tmpdir:-/tmp}
 test_pbm=${tmpdir}/test.pbm
+sheet_pbm=${tmpdir}/sheet.pbm
+
+echo "Test 1"
 
 pbmmake -g 3 3 | pnmmargin -black 2 > ${test_pbm}
 
 for n in 1 2 3 4 5 6 7 8
-do
-pbmclean -min=$n -black -plain ${test_pbm}
-done
+  do
+  pbmclean -min=${n} -black -plain ${test_pbm}
+  done
 
 rm ${test_pbm}
 
+
+echo "Test 2"
+
 # Should print 760076056 4210813
 pbmpage 1 | pbmclean -black | cksum
+
+
+echo "Test 3"
+
+pbmtext -dump-sheet > ${sheet_pbm}
+for n in 1 2 3 4 5 6 7 8 9 10
+  do
+  pbmclean -min=${n} -extended  ${sheet_pbm} | cksum
+  done
+
+rm ${sheet_pbm}
+
+echo "Test Invalid"
+
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line argument combination." 1>&2
+echo "An error message should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+# overspecification
+pbmclean -black -white -min=1 -extended testgrid.pbm > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# note that without -extended the above is valid.
diff --git a/test/pbmlife.ok b/test/pbmlife.ok
new file mode 100755
index 00000000..bd214dfb
--- /dev/null
+++ b/test/pbmlife.ok
@@ -0,0 +1,63 @@
+P1
+63 29
+000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000
+000000000000001111111000111100000000000111000111000000000000000
+000000000000000100001001100110000000001000101001100000000000000
+000000000000000100000001000010000000001000101000100000000000000
+000000000000000100010010000001000010001100101000100000000000000
+000000000000000111110010000001000010000111001100100000000000000
+000000000000000100010010000001001111101001100111100000000000000
+000000000000000100000001000010000010001000100001000000000000000
+000000000000000100000001100110000010001000100011000000000000000
+000000000000001111000000111100000000000111001100000000000000000
+000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000
+
+   tiles:	1722
+ x-edges:	1812
+ y-edges:	1842
+vertices:	1920
+    area:	1722
+perimeter:	420
+ eulerchi:	-12
+
+   tiles:	17
+ x-edges:	33
+ y-edges:	33
+vertices:	64
+    area:	17
+perimeter:	64
+ eulerchi:	15
+
+   tiles:	2
+ x-edges:	3
+ y-edges:	4
+vertices:	6
+    area:	2
+perimeter:	6
+ eulerchi:	1
+
+   tiles:	0
+ x-edges:	0
+ y-edges:	0
+vertices:	0
+    area:	0
+perimeter:	0
+ eulerchi:	0
diff --git a/test/pbmlife.test b/test/pbmlife.test
new file mode 100755
index 00000000..c292ee65
--- /dev/null
+++ b/test/pbmlife.test
@@ -0,0 +1,13 @@
+#! /bin/sh
+# This script tests: pbmlife pbmminkowski
+# Also requires: pbmtext
+
+pbmtext FO+89 -plain
+echo
+pbmtext FO+89 | pbmminkowski
+echo
+pbmtext FO+89 | pbmlife | pbmminkowski
+echo
+pbmtext FO+89 | pbmlife | pbmlife | pbmminkowski
+echo
+pbmtext FO+89 | pbmlife | pbmlife | pbmlife | pbmminkowski
diff --git a/test/pbmmake.ok b/test/pbmmake.ok
index 754eefdf..e39f4cf8 100644
--- a/test/pbmmake.ok
+++ b/test/pbmmake.ok
@@ -1,3 +1,4 @@
+Test 1
 P11 10
 P11 11
 P11 10
@@ -22,6 +23,7 @@ P17 70101010101010101010101010101010101010101010101010
 P18 80000000000000000000000000000000000000000000000000000000000000000
 P18 81111111111111111111111111111111111111111111111111111111111111111
 P18 80101010110101010010101011010101001010101101010100101010110101010
+Test 2
 4058563256 45
 3969089344 105
 702117756 189
@@ -41,3 +43,12 @@ P18 80101010110101010010101011010101001010101101010100101010110101010
 1824232358 2931
 3651864954 3375
 3302595397 3849
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
+Expected failure 7 1
+Expected failure 8 1
diff --git a/test/pbmmake.test b/test/pbmmake.test
index 4b18e3ea..1d1c682b 100755
--- a/test/pbmmake.test
+++ b/test/pbmmake.test
@@ -1,18 +1,73 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pbmmake
 # Also requires:
 
+echo "Test 1"
 
-for i in `seq 1 8`
-do
-for color in -w -b -g
-do
-pbmmake -plain $color $i $i | tr -d '\n'; echo
-done
-done
-for i in `seq 8 5 98`
-do
- ( pbmmake -w $i $i ;
-  pbmmake -b $i $i ;
-  pbmmake  -g $i $i ) | cksum
-done
+for size in 1 2 3 4 5 6 7 8             # for size in `seq 8`
+  do
+  for color in -white -black -gray
+    do
+    pbmmake -plain ${color} ${size} ${size} | tr -d '\n'; echo
+    done
+  done
+
+echo "Test 2"
+
+for size in 8 13 18 23 28 33 38 43 48 53 58 63 68 73 78 83 88 93 98
+	    # for size in `seq 8 5 98`
+  do
+  ( pbmmake -w ${size} ${size} ;
+    pbmmake -b ${size} ${size} ;
+    pbmmake -g ${size} ${size} ) | cksum
+  done
+
+echo "Test Invalid"
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+pbmmake -b -w -plain 1 1 > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmmake -b -g -plain 1 1 > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmmake -white -gray -plain 1 1 > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmmake -white -plain   > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmmake -white -plain 1 > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmmake -white -plain 1 0 > ${test_out} || \
+  printf "Expected failure 6"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmmake -white -plain 0 1 > ${test_out} || \
+  printf "Expected failure 7"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmmake -white -plain 1 1 1 > ${test_out} || \
+  printf "Expected failure 8"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pbmminkowski.ok b/test/pbmminkowski.ok
index 71a909ce..9780e3c2 100644
--- a/test/pbmminkowski.ok
+++ b/test/pbmminkowski.ok
@@ -21,3 +21,11 @@ vertices:	224
     area:	56
 perimeter:	224
  eulerchi:	56
+
+   tiles:	1627
+ x-edges:	2479
+ y-edges:	2427
+vertices:	3376
+    area:	1627
+perimeter:	3304
+ eulerchi:	97
diff --git a/test/pbmminkowski.test b/test/pbmminkowski.test
index 389ff44a..790e45bd 100755
--- a/test/pbmminkowski.test
+++ b/test/pbmminkowski.test
@@ -1,11 +1,12 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pbmminkowski
-# Also requires: pbmmake pnmmargin pnmpad
+# Also requires: pbmmake pnmpad
 
-
-pbmmake -w 1 1 | pnmmargin -b 1 | \
+pbmmake -w 1 1 | pnmpad -black -top=1 -left=1 -bottom=1 -right=1 | \
   pbmminkowski
 echo
 pbmmake -g 3 3 | pbmminkowski
 echo
 pbmminkowski testgrid.pbm
+echo
+pbmminkowski maze.pbm
\ No newline at end of file
diff --git a/test/pbmnoise-parameters.ok b/test/pbmnoise-parameters.ok
new file mode 100644
index 00000000..c2a61c37
--- /dev/null
+++ b/test/pbmnoise-parameters.ok
@@ -0,0 +1,26 @@
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
+Expected failure 7 1
+Expected failure 8 1
+Expected failure 9 1
+Expected failure 10 1
+Expected failure 11 1
+Expected failure 12 1
+Expected failure 13 1
+Expected failure 14 1
+Expected failure 15 1
+Expected failure 16 1
+Expected failure 17 1
+Expected failure 17 1
+Expected failure 18 1
+Expected failure 19 1
+Expected failure 20 1
+Expected failure 21 1
+Expected failure 22 1
+Expected failure 23 1
+Expected failure 24 1
diff --git a/test/pbmnoise-parameters.test b/test/pbmnoise-parameters.test
new file mode 100755
index 00000000..17d2c76b
--- /dev/null
+++ b/test/pbmnoise-parameters.test
@@ -0,0 +1,143 @@
+#! /bin/sh
+# This script tests: pbmnoise
+# Also requires:
+
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+echo "Test Invalid"
+
+test_out=${tmpdir}/test_out
+
+# Invalid -ratio arguments
+
+pbmnoise -ratio       100 100 > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmnoise -ratio 0     1  100 > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmnoise -ratio=1.1   100 100 > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+  
+pbmnoise -ratio=-1    100 100 > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmnoise -ratio=half  100 100 > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmnoise -ratio=0/1/1 100 100 > ${test_out} || \
+  printf "Expected failure 6"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmnoise -ratio=-1/2  100 100 > ${test_out} || \
+  printf "Expected failure 7"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmnoise -ratio=1/0   100 100 > ${test_out} || \
+  printf "Expected failure 8"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmnoise -ratio=/2    100 100 > ${test_out} || \
+  printf "Expected failure 9"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmnoise -ratio=4/2   100 100 > ${test_out} || \
+  printf "Expected failure 10"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmnoise -ratio=6/    100 100 > ${test_out} || \
+  printf "Expected failure 11"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmnoise -ratio=1.0/2.0 100 100 > ${test_out} || \
+  printf "Expected failure 12"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# denominator must be power of 2  
+pbmnoise -ratio=3/9   100 100 > ${test_out} || \
+  printf "Expected failure 13"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmnoise -ratio=a/2   100 100 > ${test_out} || \
+  printf "Expected failure 14"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+
+pbmnoise -ratio=2/a  100 100 > ${test_out} || \
+        printf "Expected failure 15"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmnoise -ratio=1/-2  100 100 > ${test_out} || \
+        printf "Expected failure 16"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# Denominator must be 65536 or less
+pbmnoise -ratio=1/65537 100 100 > ${test_out} || \
+  printf "Expected failure 17"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmnoise -ratio=1/131072 100 100 > ${test_out} || \
+  printf "Expected failure 17"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmnoise -endian=large 100 100 > ${test_out} || \
+  printf "Expected failure 18"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmnoise -randomseed 100 100 > ${test_out} || \
+  printf "Expected failure 19"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmnoise -randomseed=-1 100 100 > ${test_out} || \
+  printf "Expected failure 20"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmnoise -randomseed=0.1 100 100 > ${test_out} || \
+  printf "Expected failure 21"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmnoise > ${test_out} || \
+  printf "Expected failure 22"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmnoise 100 > ${test_out} || \
+  printf "Expected failure 23"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmnoise 100 200 300 > ${test_out} || \
+  printf "Expected failure 24"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+  
diff --git a/test/pbmnoise1.ok b/test/pbmnoise1.ok
new file mode 100644
index 00000000..84f1f04e
--- /dev/null
+++ b/test/pbmnoise1.ok
@@ -0,0 +1,50 @@
+Test 1.  Should print 242292858 962 five times
+242292858 962
+242292858 962
+242292858 962
+242292858 962
+242292858 962
+Test 2.
+P1 32 1 00000000000000000000000000000000 
+P1 32 1 00010000000001000000000000000000 
+P1 32 1 00010000000001000010000000000000 
+P1 32 1 00010000000001000000000000000000 
+P1 32 1 00010000000001000010010000000000 
+P1 32 1 01010001000101000000000000000000 
+P1 32 1 00010000000001000010100000000000 
+P1 32 1 01010001000111000000000000100010 
+P1 32 1 10011001000001100010010000000000 
+P1 32 1 01010001000111000000010100100010 
+P1 32 1 01011001000101000010100000000000 
+P1 32 1 01010001000111000001010100100110 
+P1 32 1 00010000000001000111110000000100 
+P1 32 1 01010001010111001001010100100110 
+P1 32 1 01011011000111000010101000101010 
+P1 32 1 01010001011111011001010100110110 
+P1 32 1 10011001001001110010011000101110 
+P1 32 1 01010001011111011011010101110110 
+P1 32 1 01011011000111000010111110101010 
+P1 32 1 01010001011111011011110101110110 
+P1 32 1 11011001010101101111110000000100 
+P1 32 1 01011001011111011011110101110110 
+P1 32 1 01011011000111000111111110101110 
+P1 32 1 01011011011111011011111101111110 
+P1 32 1 10111111101011110111111000111111 
+P1 32 1 01011011011111011011111111111110 
+P1 32 1 11011011010111101111111110101110 
+P1 32 1 01011011011111011111111111111110 
+P1 32 1 11111111111111111111111000111111 
+P1 32 1 11011011011111111111111111111110 
+P1 32 1 11111111111111111111111110111111 
+P1 32 1 11111111111111111111111111111111 
+P1 32 1 11111111111111111111111111111111 
+Test 3.  Should print 126142586 1218 four times
+126142586 1218
+126142586 1218
+126142586 1218
+126142586 1218
+Test 4.
+P1 64 1 1000010001101101101000100101001110101011010010011111001011100110 
+P1 64 1 1000010001101101101000100101001110101011010010011111001011100110 
+P1 64 1 0101001110100010011011011000010011100110111100100100100110101011 
+P1 64 1 0101001110100010011011011000010011100110111100100100100110101011 
diff --git a/test/pbmnoise1.test b/test/pbmnoise1.test
new file mode 100755
index 00000000..855a5629
--- /dev/null
+++ b/test/pbmnoise1.test
@@ -0,0 +1,38 @@
+#! /bin/sh
+# This script tests: pbmnoise
+#
+
+# Assumes that the random number generator is Mersenne Twister
+
+echo "Test 1.  Should print 242292858 962 five times"
+
+for arg in "" "-ratio=1/2" "-ratio=256/512" "-ratio=32768/65536" "-pack" 
+    do
+    pbmnoise -endian=big -randomseed=1 1088 7 ${arg} | cksum
+done
+
+echo "Test 2."
+
+for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 \
+	 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 
+         # for i in `seq 0 32`
+  do
+  pbmnoise -endian=little -randomseed=11 -ratio=$i/32 -plain 32 1 | \
+  tr '\n' ' ';  echo
+done
+
+echo "Test 3.  Should print 126142586 1218 four times"
+
+pbmnoise -endian=big -pack -randomseed=12 -plain 19 64 | sed 2d | tr -d '\n' | cksum
+pbmnoise -endian=big -pack -randomseed=12 -plain 152 8 | sed 2d | tr -d '\n' | cksum
+pbmnoise -endian=big -pack -randomseed=12 -plain 64 19 | sed 2d | tr -d '\n' | cksum
+pbmnoise -endian=big       -randomseed=12 -plain 64 19 | sed 2d | tr -d '\n' | cksum
+
+echo "Test 4."
+
+   pbmnoise -endian=big    -randomseed=23 64 1 -plain | tr '\n' ' '; echo
+(  pbmnoise -endian=native -randomseed=23 64 1 -plain | tr '\n' ' '; echo 
+   pbmnoise -endian=swap   -randomseed=23 64 1 -plain | tr '\n' ' '; echo
+)  | sort -nr
+   pbmnoise -endian=little -randomseed=23 64 1 -plain | tr '\n' ' '; echo
+
diff --git a/test/pbmnoise2.ok b/test/pbmnoise2.ok
new file mode 100644
index 00000000..5c3959e0
--- /dev/null
+++ b/test/pbmnoise2.ok
@@ -0,0 +1,19 @@
+Test 1.  Should print OK 1, then OK 2 three times
+OK 1
+OK 2
+OK 2
+OK 2
+Test 2.  Should print OK 1, then OK 2 three times
+OK 1
+OK 2
+OK 2
+OK 2
+Test 3-black.  Should print 255    384    100%    100% four times
+  255    384    100%    100%
+  255    384    100%    100%
+  255    384    100%    100%
+  255    384    100%    100%
+Test 3-white.  Should print 0    320    100%    100% three times
+    0    320    100%    100%
+    0    320    100%    100%
+    0    320    100%    100%
diff --git a/test/pbmnoise2.test b/test/pbmnoise2.test
new file mode 100755
index 00000000..8845e3b8
--- /dev/null
+++ b/test/pbmnoise2.test
@@ -0,0 +1,85 @@
+#! /bin/sh
+# This script tests: pbmnoise
+# Also requires: pgmhist
+
+# Expected value and variance of binominal distribution:
+# Pb: probability of getting a black pixel (=ratio)
+# Pw: probability of getting a white pixel (= 1 - Pb = 1 - ratio)
+#
+# E(width, height, Pb, Pw) = width * height * Pb
+# V(width, height, Pb, Pw) = width * height * Pb * Pw
+#
+# When width * height is large and Pb is not too near edges
+# approximate with normal distribution
+
+echo "Test 1.  Should print OK 1, then OK 2 three times"
+
+args1="-endian=big -randomseed=1"
+
+( pbmnoise            ${args1} 320 200 | pgmhist
+  pbmnoise -ratio=1/2 ${args1} 160 400 | pgmhist
+  pbmnoise -ratio=2/4 ${args1} 64000 1 | pgmhist
+  pbmnoise -pack      ${args1} 10 6400 | pgmhist ) | \
+  awk 'BEGIN { pixels=64000; Pb=Pw=0.5;
+               average=pixels*Pb;
+               sd=sqrt(pixels*Pb*Pw);  # standard deviation
+               sl=1.96                 # significance level 
+               limit1 = average - sd * sl;
+               limit2 = average + sd * sl
+               count=-1  # initial value
+              }
+       $1!=0  { next }
+              { v=1  }    # initial value
+       limit1 < $2 && $2 < limit2 { v=0 }
+       v==0   {print "OK", (count==prev)+1}
+       v==1   {print "NG" $0}
+              {prev=count}'
+
+
+
+echo "Test 2.  Should print OK 1, then OK 2 three times"
+
+args2="-endian=big -randomseed=2"
+
+( pbmnoise -ratio=11/32        ${args1} 32  119 | pgmhist
+  pbmnoise -ratio=11/32        ${args1} 224  17 | pgmhist
+  pbmnoise -ratio=22/64        ${args1} 3808  1 | pgmhist
+  pbmnoise -ratio=44/128 -pack ${args1} 1904 2 | pgmhist ) | \
+  awk 'BEGIN {pixels=32*119; Pb=11/32; Pw=1-Pb;
+               average=pixels*Pb;
+               sd=sqrt(pixels*Pb*Pw);  # standard deviation
+               sl=1.96                 # significance level 
+               limit1 = average - sd * sl;
+               limit2 = average + sd * sl
+               count=-1  # initial value
+              }
+       $1!=0  { next }
+              { v=1  }    # initial value
+       limit1 < $2 && $2 < limit2 { v=0 }
+       v==0   {print "OK", (count==prev)+1}
+       v==1   {print "NG" $0}
+              {prev=count}'
+
+
+
+
+echo "Test 3-black.  Should print 255    384    100%    100% four times"
+
+pbmnoise -ratio=0/1     -randomseed=1       128 3 | pgmhist | \
+  awk '$1==0 || $1==255'
+pbmnoise -ratio=0/1024  -randomseed=1       64  6 | pgmhist | \
+  awk '$1==0 || $1==255'
+pbmnoise -ratio=0/8192  -randomseed=1       32 12 | pgmhist | \
+  awk '$1==0 || $1==255'
+pbmnoise -ratio=0/65536 -randomseed=1 -pack 1 384 | pgmhist | \
+  awk '$1==0 || $1==255'
+
+echo "Test 3-white.  Should print 0    320    100%    100% three times"
+
+pbmnoise -ratio=1/1         -randomseed=1       64  5 | pgmhist | \
+  awk '$1==0 || $1==255'
+pbmnoise -ratio=8/8         -randomseed=1       32 10 | pgmhist | \
+  awk '$1==0 || $1==255'
+pbmnoise -ratio=65536/65536 -randomseed=1 -pack 2 160 | pgmhist | \
+  awk '$1==0 || $1==255'
+
diff --git a/test/pbmpage.ok b/test/pbmpage.ok
index 7f68da74..8013f2f2 100644
--- a/test/pbmpage.ok
+++ b/test/pbmpage.ok
@@ -1,3 +1,9 @@
+Test 1
 550172004 4210813
 4142746975 4210813
 2347597649 4210813
+3453559794 4349933
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
diff --git a/test/pbmpage.test b/test/pbmpage.test
index e9bfe352..4f15452d 100755
--- a/test/pbmpage.test
+++ b/test/pbmpage.test
@@ -1,8 +1,35 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pbmpage
 # Also requires:
 
+echo "Test 1"
 
-pbmpage 1 | cksum
-pbmpage 2 | cksum
-pbmpage 3 | cksum
+pbmpage 1     | cksum
+pbmpage 2     | cksum
+pbmpage 3     | cksum
+pbmpage -a4 2 | cksum
+
+echo "Test Invalid"
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+pbmpage -a3 1 > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmpage 0 > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmpage 4 > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pbmpscale.ok b/test/pbmpscale.ok
index e25d4027..9ea594d8 100644
--- a/test/pbmpscale.ok
+++ b/test/pbmpscale.ok
@@ -1,50 +1,178 @@
+Test 1.  Should print "abc" rendered in PBM plain format
 P1
-21 45
-000000000000000000000
-000000000000000000000
-000000000000000000000
-000000000000000000000
-000000000000000000000
-000000000000000000000
-000000000000000000000
-000000000000000000000
-000000000000000000000
-111111111111111111110
-111111111111111111111
-111111111111111111111
-001111100000000001111
-000111000000000000111
-000111000000000000111
-000111000000000000000
-000111000000000000000
-000111000000000000000
-000111000000000111000
-000111000000000111000
-000111100000001111000
-000111111111111111000
-000111111111111111000
-000111111111111111000
-000111100000001111000
-000111000000000111000
-000111000000000111000
-000111000000000000000
-000111000000000000000
-000111000000000000000
-000111000000000000000
-000111000000000000000
-001111100000000000000
-111111111111000000000
-111111111111000000000
-111111111111000000000
-000000000000000000000
-000000000000000000000
-000000000000000000000
-000000000000000000000
-000000000000000000000
-000000000000000000000
-000000000000000000000
-000000000000000000000
-000000000000000000000
-2150868536 457
-3761734242 1065
-3462719777 1803
+17 15
+00000000000000000
+00000000000000000
+00000000000000000
+00000011000000000
+00000001000000000
+00000001000000000
+00110001110000110
+01001001001001001
+00111001001001000
+01001001001001000
+01001001001001001
+00110101110000110
+00000000000000000
+00000000000000000
+00000000000000000
+Test 2.  "ABC" in PBM plain format
+P1
+48 30
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000001100000000111111111110000000000111100011
+000000001100000000111111111111100000011111110011
+000000001100000000011110000111100000011110011111
+000000011110000000001100000011110000111100001111
+000000010010000000001100000000110000111000000111
+000000110011000000001100000000110001110000000011
+000000110011000000001100000011110001100000000000
+000001100001100000001110000111100011000000000000
+000001000000100000001111111111000011000000000000
+000011000000110000001111111111000011000000000000
+000011111111110000001110000001100011000000000000
+000011111111110000001100000000110001100000000000
+000011100001110000001100000000110001110000000011
+000111000000111000001100000001110000111000000111
+001100000000001100001100000011110000111100001111
+011100000000001110011110000111100000011110011110
+111111000000111111111111111111100000011111111110
+111111000000111111111111111110000000000111111000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000
+Test 3.  "D.!" in PBM plain format
+P1
+42 45
+000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000
+111111111111111110000000000000000000000111
+111111111111111111000000000000000000000111
+111111111111111111100000000000000000000111
+001111100000001111110000000000000000000111
+000111000000000111111000000000000000000111
+000111000000000111111000000000000000000111
+000111000000000001111000000000000000000111
+000111000000000000111000000000000000000111
+000111000000000000111100000000000000000111
+000111000000000000001110000000000000000111
+000111000000000000000111000000000000000111
+000111000000000000000111000000000000000111
+000111000000000000000111000000000000000111
+000111000000000000000111000000000000000111
+000111000000000000000111000000000000000111
+000111000000000000000111000000000000000111
+000111000000000000000111000000000000000111
+000111000000000000001110000000000000000111
+000111000000000000111100000000000000000111
+000111000000000000111000000000000000000111
+000111000000000001111000000000000000000111
+000111000000000111111000000000000000000000
+000111000000000111111000000000000000000000
+001111100000001111110000000000000000000000
+111111111111111111100000000000111000000111
+111111111111111111000000000000111000000111
+111111111111111110000000000000111000000111
+000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000
+Test 3.  "E,?" in PBM plain format
+P1
+60 60
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+011111111111111111111111110000000000000000000000011111100000
+111111111111111111111111111000000000000000000000111111110000
+111111111111111111111111111100000000000000000001111111111000
+011111111111111111111111111100000000000000000011111111111100
+001111111100000000000011111100000000000000000111110000111110
+000111111000000000000001111100000000000000001111100000011111
+000011110000000000000000111100000000000000001111000000001111
+000011110000000000000000011000000000000000000110000000001111
+000011110000000000000000000000000000000000000000000000001111
+000011110000000000000000000000000000000000000000000000001111
+000011110000000000000000000000000000000000000000000000011111
+000011110000000000000000000000000000000000000000000000111110
+000011110000000000000110000000000000000000000000000001111100
+000011110000000000001111000000000000000000000000000011111000
+000011111000000000011111000000000000000000000000000111110000
+000011111100000000111111000000000000000000000000001111100000
+000011111111111111111111000000000000000000000000011111000000
+000011111111111111111111000000000000000000000000111110000000
+000011111111111111111111000000000000000000000000111100000000
+000011111111111111111111000000000000000000000000111100000000
+000011111100000000111111000000000000000000000000111100000000
+000011111000000000011111000000000000000000000000111100000000
+000011110000000000001111000000000000000000000000111100000000
+000011110000000000000110000000000000000000000000111100000000
+000011110000000000000000000000000000000000000000111100000000
+000011110000000000000000000000000000000000000000111100000000
+000011110000000000000000000000000000000000000000111100000000
+000011110000000000000000000000000000000000000000011000000000
+000011110000000000000000011000000000000000000000000000000000
+000011110000000000000000111100000000000000000000000000000000
+000111111000000000000001111100000000000000000000000000000000
+001111111100000000000011111100000000000000000000000000000000
+011111111111111111111111111100000000011000000000011000000000
+111111111111111111111111111100000000111100000000111100000000
+111111111111111111111111111000000000111100000000111100000000
+011111111111111111111111110000000000111100000000011000000000
+000000000000000000000000000000000000111100000000000000000000
+000000000000000000000000000000000000111100000000000000000000
+000000000000000000000000000000000001111100000000000000000000
+000000000000000000000000000000000011111000000000000000000000
+000000000000000000000000000000000111110000000000000000000000
+000000000000000000000000000000001111100000000000000000000000
+000000000000000000000000000000001111000000000000000000000000
+000000000000000000000000000000000110000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+Test 5.  Should print 576003211 10631
+576003211 10631
+Test 6.  Should print 3501321825 369
+3501321825 369
+Test 7.  Should print 1588181271 535
+1588181271 535
+Test 8.  Should print 2843090781 610
+2843090781 610
+Test 9.  Should print 146160766 820
+146160766 820
+Test 10. Should print 3327221668 2111
+3327221668 2111
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
diff --git a/test/pbmpscale.test b/test/pbmpscale.test
index 42046c74..efa5bfb5 100755
--- a/test/pbmpscale.test
+++ b/test/pbmpscale.test
@@ -1,12 +1,51 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pbmpscale
-# Also requires: pamenlarge pbmtext
+# Also requires: pbmtext
 
+echo "Test 1.  Should print \"abc\" rendered in PBM plain format"
+pbmtext -nomargin "abc" | pbmpscale 1 -plain
+echo "Test 2.  \"ABC\" in PBM plain format"
+pbmtext -nomargin "ABC" | pbmpscale 2 -plain
+echo "Test 3.  \"D.!\" in PBM plain format"
+pbmtext -nomargin "D.!" | pbmpscale 3 -plain
+echo "Test 3.  \"E,?\" in PBM plain format"
+pbmtext -nomargin "E,?" | pbmpscale 4 -plain
 
-pbmtext -nomargin "F" | pbmpscale 3 -plain
+echo "Test 5.  Should print 576003211 10631"
+pbmpscale 5 maze.pbm | cksum
 
-for i in 2 3 4
-do
-pamenlarge 2 testgrid.pbm | \
-  pbmpscale $i | cksum
-done
+echo "Test 6.  Should print 3501321825 369"
+pbmtext -nomargin "6" | pbmpscale 6 | cksum
+echo "Test 7.  Should print 1588181271 535"
+pbmtext -nomargin "7" | pbmpscale 7 | cksum
+echo "Test 8.  Should print 2843090781 610"
+pbmtext -nomargin "8" | pbmpscale 8 | cksum
+echo "Test 9.  Should print 146160766 820"
+pbmtext -nomargin "9" | pbmpscale 9 | cksum
+echo "Test 10. Should print 3327221668 2111"
+pbmtext -nomargin "10" | pbmpscale 10 | cksum
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+echo "Test Invalid"
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pbmpscale testgrid.pbm > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmpscale 0 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmpscale 2 3 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pbmtext-bdf.ok b/test/pbmtext-bdf.ok
index b1486493..eab8a4bd 100644
--- a/test/pbmtext-bdf.ok
+++ b/test/pbmtext-bdf.ok
@@ -1,4 +1,6 @@
+Test 1
 386826492 35
+Test 2
 1
 1
 1
@@ -17,5 +19,6 @@
 1
 1
 1
+Test 3
 0
 0
diff --git a/test/pbmtext-bdf.test b/test/pbmtext-bdf.test
index 50df7b75..f1d2019e 100755
--- a/test/pbmtext-bdf.test
+++ b/test/pbmtext-bdf.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pbmtext
 # Also requires:
 
@@ -65,8 +65,10 @@ EOF
 
 # Test 1
 # This should succeed and produce 386826492 35
-pbmtext -font ${font_bdf} ABC | cksum
 
+echo "Test 1"
+
+pbmtext -font ${font_bdf} ABC | cksum
 
 # Test 2
 # These should all fail.  Writes 1 eightteen times.
@@ -75,6 +77,8 @@ echo "Test whether corrupted BDF font files are properly handled." 1>&2
 echo "Error messages should appear below the line." 1>&2
 echo "-----------------------------------------------------------" 1>&2
 
+echo "Test 2"
+
 pbmtext -font ${font_bdf} BCD
 echo $?
 
@@ -154,10 +158,12 @@ for delete_line in 14 16 18 20
   done
 
 
-# Test 2
+# Test 3
 # These should succeed.  Warning messages will be displayed.
 # Writes 1 two times.
 
+echo "Test 3"
+
 for token in "CHARSET_ENCODING" "CHARSET_REGISTRY"
 do
   font_corrupt_bdf=${font_corrupt}.naked_${token}.bdf
@@ -167,3 +173,5 @@ do
   echo $?
   rm ${font_corrupt_bdf}
 done
+
+rm ${font_bdf}
\ No newline at end of file
diff --git a/test/pbmtext-iso88591.ok b/test/pbmtext-iso88591.ok
index 6cc1a856..842c435d 100644
--- a/test/pbmtext-iso88591.ok
+++ b/test/pbmtext-iso88591.ok
@@ -1,4 +1,6 @@
-3806607098 5110
-3806607098 5110
+Test 1
+2066913605 5110
+2066913605 5110
+Test 2
 2858870527 192
 2858870527 192
diff --git a/test/pbmtext-iso88591.test b/test/pbmtext-iso88591.test
index bc5e83ab..6df296dd 100755
--- a/test/pbmtext-iso88591.test
+++ b/test/pbmtext-iso88591.test
@@ -1,46 +1,69 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pbmtext
 # Also requires:
 
-# This test requires the following locale:
-#   LC_ALL en_US.iso88591
+# This test requires an iso-8859-1 locale
 # Skip this test if it is not available
 
-iconv /dev/null
-if [ $? -ne 0  ]
-  then echo "iconv command not available." 1>&2
-       echo "Skipping." 1>&2
-  exit 80;
-fi
+LANG=C
+LC_ALL=C
+export LANG LC_ALL
+
+tmpdir=${tmpdir:-/tmp}
+iso88591_locale_list=${tmpdir}/iso88591_locale_list
+
+
+locale_to_test="en_US.iso88591"  # Initial value
+# Edit the above value if necessary
+  
+# Make a list of available locales which end in "iso88591"
+locale -a | grep "\.iso88591$" > ${iso88591_locale_list}
+
+# Hunt for a valid iso-8859-1 locale  
+# Submit each candidate to a trial pbmtext run until one that works is
+# encountered
+
+i=0
+until [ -z ${locale_to_test} ] || \
+  echo "A" | LC_ALL=${locale_to_test} pbmtext -wchar > /dev/null
+  do
+    let i=$(($i+1));
+    locale_to_test=`sed "$i"p -n  ${iso88591_locale_list}`;
+  done;
 
-echo "A" | LC_ALL=en_US.iso88591 pbmtext -wchar > /dev/null
-if [ $? -ne 0  ]
-  then echo "LC_ALL could not be set to en_US.iso88591" 1>&2
+rm ${iso88591_locale_list};
+if [ -z  ${locale_to_test} ]
+  then echo "No iso-8859-1 locale available." 1>&2
        echo "Skipping." 1>&2
-  exit 80;
-fi
+       exit 80;
+else
+       echo "Testing with locale set to ${locale_to_test}" 1>&2
+fi;
+
+locale_for_test=${locale_to_test};
+
 
 # Two rows
-# Should print 3806607098 5110 twice
-LC_ALL=C \
+# Should print 2066913605 5110 twice
+echo "Test 1"
+
 awk 'BEGIN { for (i=32; i<=126;++i) printf("%c",i); print ""; \
-             for (i=160;i<=255;++i) printf("%c",i); }' | \
+             for (i=161;i<=255;++i) printf("%c",i); }' | \
     pbmtext -builtin bdf | cksum
 
-
-LC_ALL=C \
 awk 'BEGIN { for (i=32; i<=126;++i) printf("%c",i); print ""; \
-             for (i=160;i<=255;++i) printf("%c",i); }' | \
-    LC_ALL=en_US.iso88591 pbmtext -builtin bdf -wchar | cksum
+             for (i=161;i<=255;++i) printf("%c",i); }' | \
+    LC_ALL=${locale_for_test} pbmtext -builtin bdf -wchar | cksum
 
 
 # Two rows
 # Should print 2858870527 192 twice
-LC_ALL=C \
+
+echo "Test 2"
+
 awk 'BEGIN { for (i=32; i<=126;++i) printf("%c",i); print ""; \
              for (i=161;i<=255;++i) printf("%c",i); print "" }' | cksum
 
-LC_ALL=C \
 awk 'BEGIN { for (i=32; i<=126;++i) printf("%c",i); print ""; \
              for (i=161;i<=255;++i) printf("%c",i); print ""}' | \
-    LC_ALL=en_US.iso88591 pbmtext -builtin bdf -wchar -text-dump | cksum
\ No newline at end of file
+    LC_ALL=${locale_for_test} pbmtext -builtin bdf -wchar -text-dump | cksum
diff --git a/test/pbmtext-utf8.ok b/test/pbmtext-utf8.ok
index 588bf617..84743a09 100644
--- a/test/pbmtext-utf8.ok
+++ b/test/pbmtext-utf8.ok
@@ -1,8 +1,24 @@
+Test 1
 2066913605 5110
 2066913605 5110
+Test 2
 2920616515 2301
 2920616515 2301
-0 0 0 0 : 0
+Test 3
+0 0 0 : 0
+Test 4
  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
-0 1 : 1
+Test 5 Invalid
+9998
+989454365 52512
+9999
+Expected failure 1 1
+Expected failure 2 1
+Test 6 Invalid
+6-1: 0 1 : 1 1
+6-2: 0 1 : 1 1
+6-3: 0 1 : 1 1
+6-4: 0 1 : 1 1
+6-5: 0 1 : 1 1
+6-6: 0 1 : 1 1
diff --git a/test/pbmtext-utf8.test b/test/pbmtext-utf8.test
index cf495b7c..9203607f 100755
--- a/test/pbmtext-utf8.test
+++ b/test/pbmtext-utf8.test
@@ -2,68 +2,101 @@
 # This script tests: pbmtext
 # Also requires:
 
-# This test requires the en_US.utf8 locale
-# Skip this test if it is not available
+LANG=C
+LC_ALL=C
+export LANG LC_ALL
+
+
+# This test requires a working UTF-8 locale
+# Skip this test if it is are not available
 
 iconv /dev/null
 if [ $? -ne 0  ]
   then echo "iconv command not available." 1>&2
        echo "Skipping." 1>&2
-  exit 80;
+       exit 80;
 fi
 
-echo "A" | LC_ALL=en_US.utf8 pbmtext -wchar > /dev/null
-if [ $? -ne 0  ]
-  then echo "LC_ALL could not be set to en_US.utf8." 1>&2
+tmpdir=${tmpdir:-/tmp}
+utf_locale_list=${tmpdir}/utf_locale_list
+
+locale_to_test="en_US.utf8"  # Initial value
+# Edit the above value if necessary
+
+# Make a list of available locales which end in "utf8"
+locale -a | grep "\.utf8$" > ${utf_locale_list}
+
+# Hunt for a valid utf8 locale
+# Submit each candidate to a trial pbmtext run until one that works is
+# encountered
+
+i=0
+until [ -z ${locale_to_test} ] || \
+  echo "A" | LC_ALL=${locale_to_test} pbmtext -wchar > /dev/null
+    do
+      let i=$(($i+1));
+      locale_to_test=`sed "$i"p -n  ${utf_locale_list}`;
+    done;
+
+rm ${utf_locale_list};
+if [ -z  ${locale_to_test} ]
+  then echo "No utf-8 locale available." 1>&2
        echo "Skipping." 1>&2
-  exit 80;
-fi
+       exit 80;
+  else
+       echo "Testing with locale set to ${locale_to_test}" 1>&2
+fi;
+
+locale_for_test=${locale_to_test}
+
 
 # Test 1.
 # Two rows
 # Should print 2066913605 5110 twice
-LC_ALL=C \
+
+echo "Test 1"
+
 awk 'BEGIN { for (i=32; i<=126;++i) printf("%c",i); print ""; \
              for (i=161;i<=255;++i) printf("%c",i); }' | \
     pbmtext -builtin bdf | cksum
 
-LC_ALL=C \
 awk 'BEGIN { for (i=32; i<=126;++i) printf("%c",i); print ""; \
-             for (i=161;i<=255;++i) printf("%c",i);  }' | \
-    iconv -f iso8859-1 -t utf-8 | \
-    LC_ALL=en_US.utf8 pbmtext -builtin bdf -wchar | cksum
+             for (i=161;i<=191;++i) printf("%c%c",194,i);     \
+             for (i=128;i<=191;++i) printf("%c%c",195,i); }' | \
+    LC_ALL=${locale_for_test} pbmtext -builtin bdf -wchar | cksum
 
 
 # Test 2.
 # One row
 # Should print 2920616515 2301 twice
-LC_ALL=C \
+
+echo "Test 2"
+
 awk 'BEGIN { for (i=32; i<=126;++i) printf("%c",i); print "" }' | \
     pbmtext -builtin bdf | cksum
 
-LC_ALL=C \
 awk 'BEGIN { for (i=32; i<=126;++i) printf("%c",i);  print ""}' | \
-    LC_ALL=en_US.utf8 pbmtext -builtin bdf -wchar | cksum
-
+    LC_ALL=${locale_for_test} pbmtext -builtin bdf -wchar | cksum
 
-tmpdir=${tmpdir:-/tmp}
 output=${tmpdir}/output
 
 
 # Test 3.
 # Two rows
-# Output may be affected by locale.  Compare with cmp.
-# Should print 0
-LC_ALL=C \
+# Compare with cmp.
+# Should print 0 0 0 : 0
+
+echo "Test 3"
+
 awk 'BEGIN { for (i=32; i<=126;++i) printf("%c",i); print ""; \
-             for (i=161;i<=255;++i) printf("%c",i); print "" }' | \
-    iconv -f iso8859-1 -t utf-8 > ${output}
+             for (i=161;i<=191;++i) printf("%c%c",194,i);      \
+             for (i=128;i<=191;++i) printf("%c%c",195,i); print ""}' \
+    > ${output}
 
-LC_ALL=C \
 awk 'BEGIN { for (i=32; i<=126;++i) printf("%c",i); print ""; \
-             for (i=161;i<=255;++i) printf("%c",i); print "" }' | \
-    iconv -f iso8859-1 -t utf-8 | \
-    LC_ALL=en_US.utf8 pbmtext -builtin bdf -wchar -text-dump | \
+             for (i=161;i<=191;++i) printf("%c%c",194,i);      \
+             for (i=128;i<=191;++i) printf("%c%c",195,i); print ""}' | \
+    LC_ALL=${locale_for_test} pbmtext -builtin bdf -wchar -text-dump | \
     cmp --quiet - ${output}
 
 echo ${PIPESTATUS[@]} ":" $?
@@ -71,25 +104,106 @@ rm ${output}
 
 
 # Test 4.
-# One row
+# One row  ASCII 7-bit range
 # Should print the following twice:
 # !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
-LC_ALL=C \
+
+echo "Test 4"
+
 awk 'BEGIN { for (i=32; i<=126;++i) printf("%c",i); print "" } '
 
-LC_ALL=C \
 awk 'BEGIN { for (i=32; i<=126;++i) printf("%c",i); print ""}' | \
-        LC_ALL=en_US.utf8 pbmtext -builtin bdf -wchar -text-dump
+        LC_ALL=${locale_for_test} pbmtext -builtin bdf -wchar -text-dump
+
+# Test 5.
+# Long input text
 
 
-echo "Invalid utf-8 sequence as input." 1>&2
-echo "An error message should appear below the line." 1>&2
+echo "Test 5 Invalid"
+
+long_txt=${tmpdir}/long.txt
+test_out=${tmpdir}/test_out
+
+head -c 4999 /dev/zero | sed 's@\x00@\xc2\xbe@g' > ${long_txt}
+cat ${long_txt} | wc -c | tr -d ' '
+
+cat ${long_txt} | \
+  LC_ALL=${locale_for_test} pbmtext -nomargins -builtin fixed -wchar | cksum
+
+echo 1>&2
+echo "Test input text which exceeds length limit" 1>&2
+echo "Error messages should appear below the line." 1>&2
 echo "-----------------------------------------------------------" 1>&2
 
-# Test 5.
-# Invalid utf-8 sequence
-# Should print 1
-LC_ALL=C \
-awk 'BEGIN { for (i=128; i<=129;++i) printf("%c",i);  print ""}' | \
-        LC_ALL=en_US.utf8 pbmtext -builtin bdf -wchar -text-dump
-echo ${PIPESTATUS[@]} ":" $?
+printf "z" >> ${long_txt}
+cat ${long_txt} | wc -c | tr -d ' '
+
+cat ${long_txt} | \
+  LC_ALL=${locale_for_test} \
+  pbmtext -nomargins -builtin fixed -wchar > ${test_out} || \
+  printf "Expected failure 1";
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+cat ${long_txt} | \
+  LC_ALL=${locale_for_test} \
+  pbmtext -nomargins -builtin fixed -wchar > ${test_out} || \
+  printf "Expected failure 2";
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+rm ${long_txt}
+
+
+# Test 6.
+# Invalid utf-8 sequences
+# For each case output should be:
+# 6-x : 0 1 : 1 1
+
+echo "Invalid utf-8 sequences as input." 1>&2
+echo "Errors message should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+echo "Test 6 Invalid"
+
+awk 'BEGIN { printf("%c%c",128,129);  print ""}' | \
+        LC_ALL=${locale_for_test} \
+        pbmtext -builtin bdf -wchar -text-dump > ${test_out}
+  printf "6-1: ${PIPESTATUS[*]} : $?"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+awk 'BEGIN { printf("ABC%c%c",192, 193);  print ""}' | \
+        LC_ALL=${locale_for_test} \
+        pbmtext -builtin bdf -wchar -text-dump > ${test_out}
+  printf "6-2: ${PIPESTATUS[*]} : $?"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+awk 'BEGIN { printf("abcde%c%c", 254, 253);  print ""}' | \
+        LC_ALL=${locale_for_test} \
+        pbmtext -builtin bdf -wchar -text-dump > ${test_out}
+  printf "6-3: ${PIPESTATUS[*]} : $?"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+awk 'BEGIN { printf("abcdefg%c%c", 195, 15);  print ""}' | \
+        LC_ALL=${locale_for_test} \
+        pbmtext -builtin bdf -wchar -text-dump > ${test_out}
+  printf "6-4: ${PIPESTATUS[*]} : $?"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+awk 'BEGIN { printf("123456789%c%c%c", 224, 143 ,0);  print ""}' | \
+        LC_ALL=${locale_for_test} \
+        pbmtext -builtin bdf -wchar -text-dump > ${test_out}
+  printf "6-5: ${PIPESTATUS[*]} : $?"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+awk 'BEGIN { printf("abcdefg123ABCDEFG%c%c%c%c",247, 135, 135, 7);  print ""}' | \
+        LC_ALL=${locale_for_test} \
+        pbmtext -builtin bdf -wchar -text-dump > ${test_out}
+  printf "6-6: ${PIPESTATUS[*]} : $?"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pbmtext.ok b/test/pbmtext.ok
index 96e351f9..68ed40d8 100644
--- a/test/pbmtext.ok
+++ b/test/pbmtext.ok
@@ -1,16 +1,39 @@
+Test 1
 3898818212 967
 3898818212 967
 2506052117 1354
 2506052117 1354
+Test 2
 1028079028 967
 1888680721 445
 1305436978 1018
+Test 3
 1028079028 967
 1028079028 967
 1305436978 1018
 1305436978 1018
+Test 4
 1647614653 2027
 1647614653 2027
 1647614653 2027
+Test 5
 2547645687 4564
 1174281741 5741
+Test 6 Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
+Expected failure 7 1
+Expected failure 8 1
+Test 7
+text length: 4999
+1854691667 52512
+1854691667 52512
+Test 8 Invalid
+text length: 5000
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
diff --git a/test/pbmtext.test b/test/pbmtext.test
index 38578636..247f76c5 100755
--- a/test/pbmtext.test
+++ b/test/pbmtext.test
@@ -1,27 +1,29 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pbmtext
 # Also requires: pamfile
 
 tmpdir=${tmpdir:-/tmp}
 
 # Test 1:
+echo "Test 1"
 
 # Should print 3898818212 967 twice
 
 pbmtext UNIX Philosophy: Do one thing and do it well. | cksum
-echo -n "UNIX Philosophy: Do one thing and do it well." | pbmtext | cksum
+printf "UNIX Philosophy: Do one thing and do it well." | pbmtext | cksum
 
 # Should print 2506052117 1354 twice
 
 pbmtext -builtin fixed \
     For truth is always strange. Stranger than fiction. Lord Byron | cksum
-echo -n "For truth is always strange. Stranger than fiction. Lord Byron" | \
+printf "For truth is always strange. Stranger than fiction. Lord Byron" | \
     pbmtext -builtin fixed | cksum
 
 
 text="The quick brown fog jumps over the lazy docs."
 
 # Test 2:
+echo "Test 2"
 
 for flags in "" "-nomargins" "-builtin fixed"
 do
@@ -33,12 +35,13 @@ temp_pbm=${tmpdir}/temp.pbm
 
 # Test 3: Check if image is produced unaltered when -width is specified
 # Should print 1028079028 967 twice, then 1305436978 1018 twice
+echo "Test 3"
 
 for flags in "" "-builtin fixed"
 do
 pbmtext ${flags} ${text} | tee ${temp_pbm} | cksum
 width1=`pamfile ${temp_pbm} | awk '$2=="PBM" && NR==1 {w=$4}; END {print w}' `
-width2=`pbmtext ${flags} ${text} --dry-run | awk '{print $1}' `
+width2=`pbmtext ${flags} ${text} --dry-run | cut -d " " -f 1`
 
 if [ ${width1} -eq ${width2} ]; then
     pbmtext ${flags} -width=${width1} ${text} | cksum
@@ -50,7 +53,7 @@ done
 
 
 # Test 4: Should print 1647614653 2027 three times
-# Note: backslashes inserted in 3 locations in the rectange to make
+# Note: backslashes inserted in 3 locations in the rectangle to make
 # possible input as a here document.
 
 fontRectangle_txt=${tmpdir}/fontRectangle.txt
@@ -71,13 +74,16 @@ _ PQRSTUVWXYZ[ _
 M ",/^_[\`jpqy| M
 EOF
 
+echo "Test 4"
+
 pbmtext -dump-sheet -builtin fixed | tee ${font_pbm}      | cksum
 cat ${fontRectangle_txt} | pbmtext -nom -builtin fixed    | cksum
 cat ${fontRectangle_txt} | pbmtext -nom -font ${font_pbm} | cksum
-rm ${fontRectangle_txt} ${font_pbm}
+rm ${fontRectangle_txt}
 
 
 # Test 5: Print all characters defined in the built-in bdf font
+echo "Test 5"
 
 # One long row
 # Should print 3233136020 4535
@@ -92,3 +98,98 @@ LC_ALL=C \
 awk 'BEGIN { for (i=32; i<=126;++i) printf("%c\n",i);
              for (i=160;i<=255;++i) printf("%c\n",i); }' | \
     pbmtext -nomargins -builtin bdf | cksum
+
+
+# Test 6
+
+echo 1>&2
+echo "Invalid font file specifications & command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+echo "Test 6 Invalid"
+
+test_out=${tmpdir}/test_out
+
+pbmtext -font=testgrid.pbm foo > ${test_out} || \
+  printf "Expected failure 1";
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmtext -font=testimg.ppm  foo > ${test_out} || \
+  printf "Expected failure 2";
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmtext -builtin=void      foo > ${test_out} || \
+  printf "Expected failure 3";
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmtext -font=${font_pbm} -builtin=fixed foo > ${test_out}  || \
+  printf "Expected failure 4";
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmtext -dry-run    -text-dump  foo > ${test_out} || \
+  printf "Expected failure 5";
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmtext -dump-sheet -text-dump  foo > ${test_out} || \
+  printf "Expected failure 6";
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmtext -dry-run    -dump-sheet foo > ${test_out} || \
+  printf "Expected failure 7";
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmtext -wchar foo > ${test_out} || \
+  printf "Expected failure 8";
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+rm ${font_pbm}
+
+# Test 7
+# Text to render in very long single line
+
+echo "Test 7"
+
+long_txt=${tmpdir}/long.txt
+
+head -c 4999 /dev/zero | tr '\0' 'A' > ${long_txt}
+awk '{print "text length:", length($0)}' ${long_txt}
+
+pbmtext -nomargins -builtin fixed `cat ${long_txt}`  | cksum
+cat ${long_txt} | pbmtext -nomargins -builtin fixed  | cksum
+
+echo "Test 8 Invalid"
+
+printf "z" >> ${long_txt}
+awk '{print "text length:", length($0)}' ${long_txt}
+
+echo 1>&2
+echo "Test input text which exceeds length limit" 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pbmtext -nomargins -builtin fixed `cat ${long_txt}` > ${test_out}  || \
+  printf "Expected failure 1";
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+cat ${long_txt} | pbmtext -nomargins -builtin fixed > ${test_out}  || \
+  printf "Expected failure 2";
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+cat ${long_txt} | \
+  LC_ALL=C pbmtext -nomargins -builtin fixed -wchar > ${test_out}  || \
+  printf "Expected failure 3";
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+rm ${long_txt}
diff --git a/test/pbmtextps-dump.ok b/test/pbmtextps-dump.ok
new file mode 100644
index 00000000..11a4c5fd
--- /dev/null
+++ b/test/pbmtextps-dump.ok
@@ -0,0 +1,88 @@
+Test 1
+-font=ZQUEl8eS38RlsvEahHGNfnrbSswrcJKFwvlCdEttwcheuXvCN49MvWmndqj4
+< /FindFont {/Times-Roman findfont} def
+> /FindFont {/ZQUEl8eS38RlsvEahHGNfnrbSswrcJKFwvlCdEttwcheuXvCN49MvWmndqj4 findfont} def
+-fontsize 2000
+< /fontsize 24.000000 def
+> /fontsize 2000.000000 def
+< /descent 36.000000 def
+< /leftmargin 12.000000 def
+> /descent 3000.000000 def
+> /leftmargin 1000.000000 def
+-resolution 7200
+-leftmargin=15
+< /leftmargin 12.000000 def
+> /leftmargin 15.000000 def
+-rightmargin=20
+< /rightmargin 0.000000 def
+> /rightmargin 20.000000 def
+-topmargin=10
+< /topmargin 0.000000 def
+> /topmargin 10.000000 def
+-bottommargin=14
+< /descent 36.000000 def
+> /descent 0.000000 def
+< /bottommargin 0.000000 def
+> /bottommargin 14.000000 def
+-ascent=30
+< /ascent 0.000000 def
+> /ascent 30.000000 def
+-descent=20
+< /descent 36.000000 def
+> /descent 20.000000 def
+-pad
+< /descent 36.000000 def
+> /descent 0.000000 def
+< /pad false def
+> /pad true def
+-crop
+< /descent 36.000000 def
+< /leftmargin 12.000000 def
+> /descent 0.000000 def
+> /leftmargin 0.000000 def
+-stroke 1
+< /pensize -1.000000 def
+> /pensize 1.000000 def
+Test 2
+30 31 32 20 41 42 43 2d 78 79 7a 2e
+1
+303132204142432d78797a2e
+1
+<303132 20 414243 2d 78797a 2e>
+1
+Test Invalid
+Expected failure 1 (-fontsize) 1
+Expected failure 2 (-fontsize 0) 1
+Expected failure 3 (-resolution) 1
+Expected failure 4 (-resolution=0) 1
+Expected failure 5 (-leftmargin) 1
+Expected failure 6 (-leftmargin -1) 1
+Expected failure 7 (-rightmargin) 1
+Expected failure 8 (-rightmargin -1) 1
+Expected failure 9 (-topmargin) 1
+Expected failure 10 (-topmargin -1) 1
+Expected failure 11 (-bottommargin) 1
+Expected failure 12 (-bottommargin -1) 1
+Expected failure 13 (-ascent) 1
+Expected failure 14 (-ascent -1) 1
+Expected failure 15 (-descent) 1
+Expected failure 16 (-descent -1) 1
+Expected failure 17 (-stroke=A) 1
+Expected failure 18 (-pad -crop) 1
+Expected failure 19 (-asciihex <a>) 1
+Expected failure 20 (-asciihex ) 1
+Expected failure 21 (-asciihex <53756c667572) 1
+Expected failure 22 (-asciihex 53756c667572>) 1
+Expected failure 23 (-asciihex <5375<6c667572>) 1
+Expected failure 24 (-asciihex <53756c>667572>) 1
+Expected failure 25 (-ascii85 <~@<6O!FD5W(~) 1
+Expected failure 26 (-ascii85 ~@<6O!FD5W(~>) 1
+Expected failure 27 (-ascii85 <~@<6O<~!FD5W(~>) 1
+Expected failure 28 (-ascii85 <~@<6O~>!FD5W(~>) 1
+Expected failure 29 (-ascii85 <~@<6O!FD5W(~~>) 1
+Expected failure 30 (-ascii85 v) 1
+Expected failure 31 (-ascii85 y) 1
+Expected failure 32 (-ascii85 1z) 1
+Expected failure 33 (-ascii85 z1z) 1
+Expected failure 34 (-ascii85 <~0123z~>) 1
+Expected failure 35 (-font="") 1
diff --git a/test/pbmtextps-dump.test b/test/pbmtextps-dump.test
new file mode 100755
index 00000000..82856f7e
--- /dev/null
+++ b/test/pbmtextps-dump.test
@@ -0,0 +1,136 @@
+#! /bin/sh
+# This script tests: pbmtextps
+# Also requires:
+
+# Dump several variants of the ps file and compare against default.
+# Ghostscript is not required.
+
+tmpdir=${tmpdir:-/tmp}
+text1_ps=${tmpdir}/text1.ps
+text2_ps=${tmpdir}/text2.ps
+
+text="UNIX Philosophy: Do one thing and do it well."
+
+# Test 1:
+echo "Test 1"
+
+pbmtextps -dump-ps ${text} > ${text1_ps}
+
+# Font name is random sequence of alphanumerical characters.
+# Should not match any real name.
+
+for flag in \
+  "-font=ZQUEl8eS38RlsvEahHGNfnrbSswrcJKFwvlCdEttwcheuXvCN49MvWmndqj4" \
+  "-fontsize 2000" \
+  "-resolution 7200" \
+  "-leftmargin=15" \
+  "-rightmargin=20" \
+  "-topmargin=10" \
+  "-bottommargin=14" \
+  "-ascent=30" \
+  "-descent=20" \
+  "-pad" \
+  "-crop" \
+  "-stroke 1"
+  do
+  echo ${flag}
+  pbmtextps -dump-ps ${flag} ${text} | diff ${text1_ps} - | grep "^[<>]"
+  done
+
+rm ${text1_ps}
+
+
+# Test 2:
+echo "Test 2"
+
+pbmtextps -dump-ps "012 ABC-xyz." > ${text2_ps}
+
+for hextext in \
+  "30 31 32  20	 41 42 43  2d	78 79 7a  2e" \
+  "303132204142432d78797a2e" \
+  "<303132 20 414243 2d 78797a 2e>" 
+  do
+  echo ${hextext}
+  pbmtextps -dump-ps -asciihex ${hextext} | diff ${text2_ps} - | grep "^[<>]"
+  echo $?
+  done
+
+rm ${text2_ps}
+
+
+echo "Test Invalid"
+
+echo 1>&2
+echo "Invalid command line arguments" 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+test_out=${tmpdir}/test.out
+
+n=1
+
+for error_flag in \
+  "-fontsize" \
+  "-fontsize 0" \
+  "-resolution" \
+  "-resolution=0" \
+  "-leftmargin" \
+  "-leftmargin -1" \
+  "-rightmargin" \
+  "-rightmargin -1" \
+  "-topmargin" \
+  "-topmargin -1" \
+  "-bottommargin" \
+  "-bottommargin -1" \
+  "-ascent" \
+  "-ascent -1" \
+  "-descent" \
+  "-descent -1" \
+  "-stroke=A" \
+  "-pad -crop"
+  do
+    pbmtextps ${error_flag} -dump-ps ${text} >${test_out} || \
+    printf "Expected failure $n (${error_flag})";
+    test -s ${test_out}; echo " "$?
+    rm -f ${test_out}
+    n=$((n + 1))
+  done
+
+for asciihex_string in \
+  "<a>" \
+  "" \
+  "<53756c667572" \
+  "53756c667572>" \
+  "<5375<6c667572>" \
+  "<53756c>667572>"
+  do
+    pbmtextps -dump-ps -asciihex ${asciihex_string} >${test_out} || \
+    printf "Expected failure $n (-asciihex ${asciihex_string})";
+    test -s ${test_out}; echo " "$?
+    rm -f ${test_out}
+    n=$((n + 1))
+  done
+
+for ascii85_string in \
+  '<~@<6O!FD5W(~'\
+  '~@<6O!FD5W(~>'\
+  "<~@<6O<~!FD5W(~>"\
+  "<~@<6O~>!FD5W(~>"\
+  "<~@<6O!FD5W(~~>"\
+  "v"\
+  "y"\
+  "1z"\
+  "z1z"\
+  "<~0123z~>"
+  do
+    pbmtextps -dump-ps -ascii85 ${ascii85_string} >${test_out} || \
+    printf "Expected failure $n (-ascii85 ${ascii85_string})";
+    test -s ${test_out}; echo " "$?
+    rm -f ${test_out}
+    n=$((n + 1))
+  done
+
+  pbmtextps -font="" -dump-ps ${text} >${test_out} || \
+  printf "Expected failure $n (-font=\"\")";
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pbmtextps.ok b/test/pbmtextps.ok
new file mode 100644
index 00000000..2063ac4a
--- /dev/null
+++ b/test/pbmtextps.ok
@@ -0,0 +1,18 @@
+Test 1.  Should print 0 five times.
+0
+0
+0
+0
+0
+Test 2.  Should print P1 1 1 0 five times
+P1 1 1 0 
+P1 1 1 0 
+P1 1 1 0 
+P1 1 1 0 
+P1 1 1 0 
+Test 3.  Should print eulerchi: N
+ eulerchi:	1
+ eulerchi:	2
+ eulerchi:	3
+ eulerchi:	4
+ eulerchi:	5
diff --git a/test/pbmtextps.test b/test/pbmtextps.test
new file mode 100755
index 00000000..55f3f96a
--- /dev/null
+++ b/test/pbmtextps.test
@@ -0,0 +1,55 @@
+#! /bin/sh
+# This script tests: pbmtextps pbmminkowski
+# Also requires: gs pnmcrop
+
+tmpdir=${tmpdir:-/tmp}
+text_pbm=${tmpdir}/text.pbm
+
+text="Do one thing and do it well."
+
+echo "Test 1.  Should print 0 five times."
+# -ascent -descent values too small to have effect
+
+pbmtextps -descent=1 ${text} > ${text_pbm}
+  echo $?
+  test -s ${text_pbm}
+  echo $?
+pbmtextps -ascent=10 -descent=1 ${text} | cmp -s - ${text_pbm}
+  echo $?
+pbmtextps -ascent=1 -descent=1 ${text}  | cmp -s - ${text_pbm}
+  echo $?
+pbmtextps -descent=2 ${text} | cmp -s - ${text_pbm}
+  echo $?
+
+rm ${text_pbm}
+
+
+echo "Test 2.  Should print P1 1 1 0 five times"
+# blank images
+
+pbmtextps " " | pnmcrop -plain -blank-image=minimize |\
+  tr '\n' ' ' ; echo
+pbmtextps -fontsize=12   " " | pnmcrop -plain -blank-image=minimize |\
+  tr '\n' ' ' ; echo
+pbmtextps -resolution=50 " " | pnmcrop -plain -blank-image=minimize |\
+  tr '\n' ' ' ; echo
+pbmtextps -asciihex "20" | pnmcrop -plain -blank-image=minimize |\
+  tr '\n' ' ' ; echo
+pbmtextps -ascii85  "+9" | pnmcrop -plain -blank-image=minimize |\
+  tr '\n' ' ' ; echo
+
+
+
+echo "Test 3.  Should print eulerchi: N"
+# Test with characters known to produce stable eulerchi values
+# accross various fonts
+
+pbmtextps " " | pbmminkowski | grep "eulerchi"
+
+pbmtextps "+" | pbmminkowski | grep "eulerchi"
+
+pbmtextps "+" | pnmcrop -left -right | pbmminkowski | grep "eulerchi"
+
+pbmtextps "+" | pnmcrop | pbmminkowski | grep "eulerchi"
+
+pbmtextps "o" | pnmcrop | pbmminkowski | grep "eulerchi"
diff --git a/test/pbmtog3.ok b/test/pbmtog3.ok
index cef9e3f9..6660206b 100644
--- a/test/pbmtog3.ok
+++ b/test/pbmtog3.ok
@@ -1,10 +1,20 @@
-3697098186 144
-1248301383 122
-686713716 144
-215463240 122
+Test 1.  Should print 2156383714 1106
+2156383714 1106
+Test 2.  Should print 162371073 1049
+162371073 1049
+Test 3.  Should print 750267045 1106
+750267045 1106
+Test 4.  Should print 1140269483 1049
+1140269483 1049
+Test 5.  Should print 28792587 47
 28792587 47
+Test 6.  Should print 277456854 32
 277456854 32
+Test 7.  Should print 28792587 47
 28792587 47
+Test 8.  Should print 3736247115 62
 3736247115 62
+Test 9.  Should print 2820255307 2191856
 2820255307 2191856
+Test 10.  Should print 4159089282 2226575
 4159089282 2226575
diff --git a/test/pbmtog3.test b/test/pbmtog3.test
index c5dc3357..8b9c29e1 100755
--- a/test/pbmtog3.test
+++ b/test/pbmtog3.test
@@ -1,25 +1,34 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pbmtog3
 # Also requires: pbmmake
 
-# Test 1.  Should print 3697098186 144
-pbmtog3 testgrid.pbm | cksum
-# Test 2.  Should print 1248301383 122
-pbmtog3 -nofixedwidth testgrid.pbm | cksum
-# Test 3.  Should print 686713716 144
-pbmtog3 -reverse testgrid.pbm | cksum
-# Test 4.  Should print 215463240 122
-pbmtog3 -nofixedwidth -reverse testgrid.pbm | cksum
-# Test 5.  Should print 28792587 47
+echo "Test 1.  Should print 2156383714 1106"
+pbmtog3 maze.pbm | cksum
+
+echo "Test 2.  Should print 162371073 1049"
+pbmtog3 -nofixedwidth maze.pbm | cksum
+
+echo "Test 3.  Should print 750267045 1106"
+pbmtog3 -reverse maze.pbm | cksum
+
+echo "Test 4.  Should print 1140269483 1049"
+pbmtog3 -nofixedwidth -reverse maze.pbm | cksum
+
+echo "Test 5.  Should print 28792587 47"
 pbmmake -w 10 10 | pbmtog3 | cksum
-# Test 6.  Should print 277456854 32
+
+echo "Test 6.  Should print 277456854 32"
 pbmmake -w 10 10 | \
   pbmtog3 -nofixedwidth | cksum
-# Test 7.  Should print 28792587 47
+
+echo "Test 7.  Should print 28792587 47"
 pbmmake -w 10000 10 | pbmtog3 | cksum
-# Test 8.  Should print 3736247115 62
+
+echo "Test 8.  Should print 3736247115 62"
 pbmmake -b 10 10 | pbmtog3 | cksum
-# Test 9.  Should print 2820255307 2191856
+
+echo "Test 9.  Should print 2820255307 2191856"
 pbmmake -g 1700 2286 | pbmtog3 | cksum
-# Test 10.  Should print 4159089282 2226575
+
+echo "Test 10.  Should print 4159089282 2226575"
 pbmmake -g 1800 2286 | pbmtog3 | cksum
diff --git a/test/pbmtopgm.ok b/test/pbmtopgm.ok
new file mode 100644
index 00000000..6ccf9c64
--- /dev/null
+++ b/test/pbmtopgm.ok
@@ -0,0 +1,25 @@
+Test 1
+P2
+14 16
+1
+0 1 0 1 0 1 0 1 0 1 0 1 0 1
+0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 1 0 1 0 1 0 1 0 1 0 1 0 1
+0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 1 0 1 0 1 0 1 0 1 0 1 0 1
+0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 1 0 1 0 1 0 1 0 1 0 1 0 1
+0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 1 0 1 0 1 0 1 0 1 0 1 0 1
+0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 1 0 1 0 1 0 1 0 1 0 1 0 1
+0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 1 0 1 0 1 0 1 0 1 0 1 0 1
+0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 1 0 1 0 1 0 1 0 1 0 1 0 1
+0 0 0 0 0 0 0 0 0 0 0 0 0 0
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
diff --git a/test/pbmtopgm.test b/test/pbmtopgm.test
new file mode 100755
index 00000000..02f2bb21
--- /dev/null
+++ b/test/pbmtopgm.test
@@ -0,0 +1,38 @@
+#! /bin/sh
+# This script tests: pbmtopgm
+# Also requires:
+
+#Test 1
+echo "Test 1"
+
+pbmtopgm -plain 1 1 testgrid.pbm
+
+echo "Test Invalid"
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pbmtopgm 5 0 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmtopgm 0 9 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmtopgm 15 5 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmtopgm 5 17 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pbmupc.ok b/test/pbmupc.ok
index 3e58f409..f1b91e99 100644
--- a/test/pbmupc.ok
+++ b/test/pbmupc.ok
@@ -1 +1,12 @@
+Test 1
 2619309127 10172
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
+Expected failure 7 1
+Expected failure 8 1
+Expected failure 9 1
diff --git a/test/pbmupc.test b/test/pbmupc.test
index 275117d5..f8343dd7 100755
--- a/test/pbmupc.test
+++ b/test/pbmupc.test
@@ -1,9 +1,65 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pbmupc
 # Also requires:
 
+echo "Test 1"
 
 for type in -s1 -s2
 do
 pbmupc $type 0 72890 00011
 done | cksum
+
+echo "Test Invalid"
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pbmupc -s3 0 72890 00011     > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmupc -s1   72890 00011     > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmupc -s1 0 72890           > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmupc -s1 10 72890 00011    > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmupc -s1 0 172890 00011    > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmupc -s1 0   2890 00011    > ${test_out} || \
+  printf "Expected failure 6"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmupc -s1 0 72890 100011    > ${test_out} || \
+  printf "Expected failure 7"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmupc -s1 0 72890   0011    > ${test_out} || \
+  printf "Expected failure 8"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pbmupc -s1 0 72890 100011 1  > ${test_out} || \
+  printf "Expected failure 9"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pcx-roundtrip.ok b/test/pcx-roundtrip.ok
index 968f46b9..0f5ac87d 100644
--- a/test/pcx-roundtrip.ok
+++ b/test/pcx-roundtrip.ok
@@ -1,5 +1,9 @@
+Test 1.  Should print 1926073387 101484
 1926073387 101484
+Test 2.  Should print 369063776 101484 three times
 369063776 101484
 369063776 101484
 369063776 101484
-829921912 685
+Test 3.  Should print 669206373 10102 twice
+669206373 10102
+669206373 10102
diff --git a/test/pcx-roundtrip.test b/test/pcx-roundtrip.test
index 3dba42b9..194af131 100755
--- a/test/pcx-roundtrip.test
+++ b/test/pcx-roundtrip.test
@@ -1,7 +1,6 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmtopcx pcxtoppm
-# Also requires: pnmremap
-
+# Also requires: pgmtoppm pnmremap
 
 tmpdir=${tmpdir:-/tmp}
 pcxstd_ppm=${tmpdir}/pcxstd_ppm
@@ -29,17 +28,16 @@ P3
 255 255 255
 EOF
 
-# Test 1. Should print 1926073387 101484
+echo "Test 1.  Should print 1926073387 101484"
 ppmtopcx testimg.ppm | pcxtoppm | cksum
 
-# Test 2.  Should print 369063776 101484 three times
+echo "Test 2.  Should print 369063776 101484 three times"
 pnmremap testimg.ppm -mapfile=${pcxstd_ppm} | tee ${testpcx_ppm} | cksum
 ppmtopcx -stdpalette -packed ${testpcx_ppm} | pcxtoppm | cksum
 ppmtopcx -stdpalette -packed -8bit ${testpcx_ppm} | pcxtoppm | cksum
 
 rm ${testpcx_ppm} ${pcxstd_ppm}
 
-# Test 3. Should print 829921912 685 which is the
-# result of:
-# pgmtoppm < testgrid.pbm | cksum
-ppmtopcx -stdpalette -packed testgrid.pbm | pcxtoppm | cksum
+echo "Test 3.  Should print 669206373 10102 twice"
+pgmtoppm < maze.pbm | cksum
+ppmtopcx -stdpalette -packed maze.pbm | pcxtoppm | cksum
diff --git a/test/pdb-roundtrip.ok b/test/pdb-roundtrip.ok
index b903da8d..fbc897fe 100644
--- a/test/pdb-roundtrip.ok
+++ b/test/pdb-roundtrip.ok
@@ -1,18 +1,18 @@
-pbm grid
+Test 1: pbm grid : Should print 2224198737 25671 three times
 2224198737 25671
 2224198737 25671
 2224198737 25671
-pbm tiled
+Test 2: pbmnoise : Should print 0 0 0 0 : 0 four times
 0 0 0 0 : 0
 0 0 0 0 : 0
 0 0 0 0 : 0
 0 0 0 0 : 0
-pgm ellipse
+Test 3: pgm ellipse : Should print 0 0 0 0 0 : 0 four times
 0 0 0 0 0 : 0
 0 0 0 0 0 : 0
 0 0 0 0 0 : 0
 0 0 0 0 0 : 0
-pgm ellipse -4depth
+Test 4: pgm ellipse -4depth : Should print 0 0 0 0 0 : 0 three times
 0 0 0 0 0 : 0
 0 0 0 0 0 : 0
 0 0 0 0 0 : 0
diff --git a/test/pdb-roundtrip.test b/test/pdb-roundtrip.test
index 6b4e152c..f56be1bf 100755
--- a/test/pdb-roundtrip.test
+++ b/test/pdb-roundtrip.test
@@ -1,37 +1,31 @@
 #! /bin/bash
 # This script tests: pamtopdbimg pdbimgtopam
-# Also requires: pnmtile pgmramp pamtopnm
+# Also requires: pbmnoise pgmramp pamtopnm pamdepth
 
 tmpdir=${tmpdir:-/tmp}
-tiled_pbm=${tmpdir}/tiled.pbm
+noise_pbm=${tmpdir}/noise.pbm
 ellipse_pgm=${tmpdir}/ellipse.pgm
 
 
-# Test 1. Should produce 2224198737 25671
-# 3 times 
-echo pbm grid
+echo "Test 1: pbm grid : Should print 2224198737 25671 three times"
 for flag in "-compressed" "-maybecompressed" "-uncompressed"
    do
    pamtopdbimg ${flag} testgrid.pbm | pdbimgtopam | cksum
    done
 
 
-# Test 2. Should produce 0 0 0
-# 4 times 
-echo pbm tiled
-pnmtile 160 160 testgrid.pbm > ${tiled_pbm}
+echo "Test 2: pbmnoise : Should print 0 0 0 0 : 0 four times" 
+pbmnoise -randomseed=1 160 160 > ${noise_pbm}
 for flag in "" "-compressed" "-maybecompressed" "-uncompressed"
   do
-  pamtopdbimg ${flag} ${tiled_pbm} | pdbimgtopam | pamtopnm | \
-    cmp -s - ${tiled_pbm}
+  pamtopdbimg ${flag} ${noise_pbm} | pdbimgtopam | pamtopnm | \
+    cmp -s - ${noise_pbm}
   echo ${PIPESTATUS[@]} ":" $?
   done
-rm ${tiled_pbm}
+rm ${noise_pbm}
 
 
-# Test 3. Should produce 0 0 0
-# 4 times
-echo pgm ellipse
+echo "Test 3: pgm ellipse : Should print 0 0 0 0 0 : 0 four times"
 pgmramp -ellipse 160 160 -maxval=3 > ${ellipse_pgm}
 for flag in "" "-compressed" "-maybecompressed" "-uncompressed"
     do
@@ -42,9 +36,7 @@ for flag in "" "-compressed" "-maybecompressed" "-uncompressed"
 rm ${ellipse_pgm}
 
 
-# Test 3. Should produce 0 0 0
-# 3 times 
-echo pgm ellipse -4depth
+echo "Test 4: pgm ellipse -4depth : Should print 0 0 0 0 0 : 0 three times"
 pgmramp -ellipse 160 160 -maxval=15 > ${ellipse_pgm}
 for flag in "-compressed" "-maybecompressed" "-uncompressed"
     do
@@ -52,4 +44,4 @@ for flag in "-compressed" "-maybecompressed" "-uncompressed"
       pamtopnm | pamdepth 15 | cmp -s - ${ellipse_pgm}
     echo ${PIPESTATUS[@]} ":" $?
     done
-rm ${ellipse_pgm}
\ No newline at end of file
+rm ${ellipse_pgm}
diff --git a/test/pfm-roundtrip.test b/test/pfm-roundtrip.test
index f1b5d418..95bfc62f 100755
--- a/test/pfm-roundtrip.test
+++ b/test/pfm-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamtopfm pfmtopam
 # Also requires: pamtopnm
 
diff --git a/test/pgmbentley.test b/test/pgmbentley.test
index 0429d54b..800aa1f7 100755
--- a/test/pgmbentley.test
+++ b/test/pgmbentley.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pgmbentley
 # Also requires: pgmramp
 
diff --git a/test/pgmhist.ok b/test/pgmhist.ok
index 7d89bb33..3be73ff9 100644
--- a/test/pgmhist.ok
+++ b/test/pgmhist.ok
@@ -1,3 +1,4 @@
+Test 1
 value count b% w%
 ----- ----- ------ ------
  0 2 12.5% 100%
@@ -12,3 +13,24 @@ value count b% w%
 ----- ----- ------ ------
  0 168 75% 100%
  255 56 100% 25%
+Test 2
+127
+63
+127
+191
+255
+25
+51
+76
+102
+127
+153
+179
+204
+230
+255
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
diff --git a/test/pgmhist.test b/test/pgmhist.test
index 42666fbf..c141627d 100755
--- a/test/pgmhist.test
+++ b/test/pgmhist.test
@@ -1,12 +1,55 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pgmhist
 # Also requires: pgmramp
 
 
 # Ignore differences in spaces.
 
+echo "Test 1"
+
 pgmramp -maxval=8 -lr 8 2 | pgmhist | \
   sed -e 's/  */ /g' -e 's/ *$//'
 
 pgmhist testgrid.pbm | \
   sed -e 's/  */ /g' -e 's/ *$//'
+
+echo "Test 2"
+
+pgmramp -lr 256 1 | pgmhist -machine -median   | \
+  sed -e 's/  */ /g' -e 's/ *$//'
+
+pgmramp -lr 256 1 | pgmhist -machine -quartile | \
+  sed -e 's/  */ /g' -e 's/ *$//'
+
+pgmramp -lr 256 1 | pgmhist -machine -decile   | \
+  sed -e 's/  */ /g' -e 's/ *$//'
+
+echo "Test Invalid"
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pgmhist -median   -quartile testgrid.pbm > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmhist -median   -decile   testgrid.pbm > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmhist -quartile -decile   testgrid.pbm > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmhist testimg.ppm > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pgmmake.ok b/test/pgmmake.ok
index b9a03af2..8b242822 100644
--- a/test/pgmmake.ok
+++ b/test/pgmmake.ok
@@ -1,2 +1,12 @@
+Test 1
 3662611538 2513
 3109612402 5012
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
+Expected failure 7 1
+Expected failure 8 1
diff --git a/test/pgmmake.test b/test/pgmmake.test
index 4a3c4842..3c96d99e 100755
--- a/test/pgmmake.test
+++ b/test/pgmmake.test
@@ -1,7 +1,59 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pgmmake
 # Also requires:
 
+echo "Test 1"
 
 pgmmake 1 50 50 | cksum
 pgmmake .2 50 100 -maxval=5 | cksum
+
+
+echo "Test Invalid"
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+pgmmake 100  5 5 > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmmake 1.01 5 5 > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmmake .5   5   > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmmake .5       > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmmake -maxval=5        5 5 > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmmake -maxval=0     .5 5 5 > ${test_out} || \
+  printf "Expected failure 6"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmmake -maxval=-1    .5 5 5 > ${test_out} || \
+  printf "Expected failure 7"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmmake -maxval=65536 .5 5 5 > ${test_out} || \
+  printf "Expected failure 8"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pgmminkowski.ok b/test/pgmminkowski.ok
new file mode 100644
index 00000000..86f43207
--- /dev/null
+++ b/test/pgmminkowski.ok
@@ -0,0 +1,17 @@
+#threshold	 tiles	x-edges	y-edges	vertices
+#---------	 -----	-------	-------	--------
+0.000000	     9	     12	     12	      16	1	1	     1
+0.501961	     1	      2	      2	       4	0.111111	0.333333	     1
+#  check:	     0	      0	      0	       0
+
+#threshold	 tiles	x-edges	y-edges	vertices
+#---------	 -----	-------	-------	--------
+0.000000	     9	     12	     12	      16	1	1	     1
+1.000000	     5	     10	     10	      16	0.555556	1.66667	     1
+#  check:	     0	      0	      0	       0
+
+#threshold	 tiles	x-edges	y-edges	vertices
+#---------	 -----	-------	-------	--------
+0.000000	   224	    240	    238	     255	1	1	     1
+1.000000	    56	    112	    112	     224	0.25	3.73333	    56
+#  check:	     0	      0	      0	       0
diff --git a/test/pgmminkowski.test b/test/pgmminkowski.test
new file mode 100755
index 00000000..e81de3e1
--- /dev/null
+++ b/test/pgmminkowski.test
@@ -0,0 +1,10 @@
+#! /bin/sh
+# This script tests: pgmminkowski
+# Also requires: pbmmake pgmmake pnmpad
+
+pgmmake .5 1 1 | pnmpad -black -top=1 -left=1 -bottom=1 -right=1 | \
+  pgmminkowski
+echo
+pbmmake -g 3 3 | pgmminkowski
+echo
+pgmminkowski testgrid.pbm
diff --git a/test/pgmnoise-parameters.ok b/test/pgmnoise-parameters.ok
new file mode 100644
index 00000000..1bb1cd59
--- /dev/null
+++ b/test/pgmnoise-parameters.ok
@@ -0,0 +1,5 @@
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
diff --git a/test/pgmnoise-parameters.test b/test/pgmnoise-parameters.test
new file mode 100755
index 00000000..c5e6ada5
--- /dev/null
+++ b/test/pgmnoise-parameters.test
@@ -0,0 +1,36 @@
+#! /bin/sh
+# This script tests: pgmnoise
+# Also requires:
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pgmnoise -maxval=255  -randomseed=1 > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmnoise 100 -randomseed=1 > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmnoise 100 0 -randomseed=1 > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmnoise 0 100 -randomseed=1 > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmnoise 100 100 100 -randomseed=1 > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pgmnoise.ok b/test/pgmnoise.ok
new file mode 100644
index 00000000..d98ee053
--- /dev/null
+++ b/test/pgmnoise.ok
@@ -0,0 +1,102 @@
+Test 1.
+Should print: 2132901423 10015
+2132901423 10015
+Test 2.
+P2
+5 20
+9999
+1612 9302 6734 4585 4204
+5391 9429 3985 2298 7403
+2835 4565 740 4426 8239
+2720 519 8804 4697 8106
+3009 4609 4243 4039 746
+2626 2536 8553 8460 1771
+7212 4909 929 1418 4126
+2695 4553 893 8587 4728
+4844 7306 495 5920 2597
+8076 445 6934 5307 8902
+9058 5693 9660 3006 2222
+2786 6116 5227 1234 7006
+4839 1161 1026 3808 5152
+3250 4612 9652 7801 1673
+4425 7642 6209 5879 1891
+1326 2609 3880 4788 4008
+2678 1923 1099 1100 9586
+2873 7582 3983 1720 6969
+2059 8444 8154 2595 3247
+6536 8742 7111 4600 9344
+Test 3.
+1
+P2 16 1 1 1 0 1 0 0 1 0 0 0 0 1 0 1 1 1 1 2
+P2 16 1 2 1 2 0 2 1 1 2 2 2 0 2 0 1 2 1 0 3
+P2 16 1 3 1 1 2 0 0 1 3 3 1 0 0 3 2 2 2 1 4
+P2 16 1 4 0 4 4 3 3 3 1 1 4 2 3 4 1 3 3 0 5
+P2 16 1 5 1 5 0 2 1 1 5 5 5 0 2 3 4 5 1 0 6
+P2 16 1 6 0 3 4 3 3 6 0 5 0 3 4 6 5 5 2 5 7
+P2 16 1 7 5 4 0 2 7 3 0 6 2 5 5 5 6 1 0 4 8
+P2 16 1 8 4 5 0 5 7 1 2 5 8 0 2 3 1 8 4 0 9
+P2 16 1 9 5 9 4 8 3 3 1 1 9 2 8 9 6 3 3 0 10
+P2 16 1 10 0 3 5 0 3 1 5 1 0 0 9 1 4 5 5 6 11
+P2 16 1 11 1 11 0 8 7 1 11 5 11 0 8 9 4 11 1 0 12
+P2 16 1 12 6 9 3 1 6 1 7 2 12 9 1 0 9 11 12 1 13
+P2 16 1 13 7 3 4 10 3 13 7 5 7 10 4 13 12 5 9 12 14
+P2 16 1 14 10 14 9 8 13 13 11 11 14 12 8 9 1 8 13 0 15
+P2 16 1 15 5 2 4 15 1 12 10 6 11 14 0 8 7 4 15 15 16
+P2 16 1 16 2 9 15 8 14 7 7 16 5 5 16 2 4 6 1 14 255
+P2 16 1 255 37 244 193 106 235 128 71 255 140 47 103 184 72 20 188 238 65535
+P2 16 1 65535 62501 27329 33003 65351 12172 47207 5192 61116 32511 7 50057 8396 43723 19813 7813 65473 
+Test 4.
+1  stdin:	PGM raw, 1 by 10  maxval 1
+2  stdin:	PGM raw, 2 by 10  maxval 2
+3  stdin:	PGM raw, 3 by 10  maxval 3
+4  stdin:	PGM raw, 4 by 10  maxval 4
+5  stdin:	PGM raw, 5 by 10  maxval 5
+6  stdin:	PGM raw, 6 by 10  maxval 6
+7  stdin:	PGM raw, 7 by 10  maxval 7
+8  stdin:	PGM raw, 8 by 10  maxval 8
+9  stdin:	PGM raw, 9 by 10  maxval 9
+10  stdin:	PGM raw, 10 by 10  maxval 10
+11  stdin:	PGM raw, 11 by 10  maxval 11
+12  stdin:	PGM raw, 12 by 10  maxval 12
+13  stdin:	PGM raw, 13 by 10  maxval 13
+14  stdin:	PGM raw, 14 by 10  maxval 14
+15  stdin:	PGM raw, 15 by 10  maxval 15
+16  stdin:	PGM raw, 16 by 10  maxval 16
+30  stdin:	PGM raw, 30 by 10  maxval 30
+31  stdin:	PGM raw, 31 by 10  maxval 31
+32  stdin:	PGM raw, 32 by 10  maxval 32
+254  stdin:	PGM raw, 254 by 10  maxval 254
+255  stdin:	PGM raw, 255 by 10  maxval 255
+256  stdin:	PGM raw, 256 by 10  maxval 256
+65534  stdin:	PGM raw, 65534 by 10  maxval 65534
+65535  stdin:	PGM raw, 65535 by 10  maxval 65535
+Test 5.
+Should print four identical lines
+969759084 1682
+969759084 1682
+969759084 1682
+969759084 1682
+Test 6.
+First column should be 2^n - 1.  Last column should be 'pool'.
+1 pgmnoise: method: pool
+3 pgmnoise: method: pool
+7 pgmnoise: method: pool
+15 pgmnoise: method: pool
+31 pgmnoise: method: pool
+63 pgmnoise: method: pool
+127 pgmnoise: method: pool
+255 pgmnoise: method: pool
+511 pgmnoise: method: pool
+1023 pgmnoise: method: pool
+65535 pgmnoise: method: pool
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
+Expected failure 7 1
+Expected failure 8 1
+Expected failure 9 1
+Expected failure 10 1
diff --git a/test/pgmnoise.rand-ok b/test/pgmnoise.rand-ok
deleted file mode 100644
index b69f48e5..00000000
--- a/test/pgmnoise.rand-ok
+++ /dev/null
@@ -1,3 +0,0 @@
-000|0
-081|2005134911 10015
-082|3516404574 10015
diff --git a/test/pgmnoise.test b/test/pgmnoise.test
index 03301ce6..6141121a 100755
--- a/test/pgmnoise.test
+++ b/test/pgmnoise.test
@@ -1,7 +1,128 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pgmnoise
-# Also requires:
+# Also requires: pgmhist pamvalidate pamfile
 
-# Should print: 1663614689 10015 (Glibc)
-#               3516404574 10015 (MAC OS)
+echo "Test 1."
+echo "Should print: 2132901423 10015" # (Mersenne Twister)
+#                   1663614689 10015 (Glibc rand())
+#                   3516404574 10015 (MAC OS rand())
 pgmnoise --randomseed=0 100 100 | cksum
+
+
+echo "Test 2."
+# Output is similar to that of Test 2. of random-generator.test
+# The lowest four decimal digits are printed.
+
+pgmnoise --randomseed=5489 -maxval=9999 -plain 5 20
+
+
+echo "Test 3."
+for maxval in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 255 65535
+  do
+  echo ${maxval}
+  pgmnoise -maxval=${maxval} -randomseed=1 -plain 16 1 | tr '\n' ' '
+  done
+echo
+
+echo "Test 4."
+# Check for maxval violation
+for maxval in  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 \
+               30 31 32 254 255 256 65534 65535
+  do
+  printf "%d  " ${maxval}
+  pgmnoise -maxval=${maxval} -randomseed=1 -plain ${maxval} 10 | \
+    pamvalidate | pamfile
+  done
+
+echo "Test 5."
+echo "Should print four identical lines"
+# width height values do not affect random number sequence
+for xysize in "1 10000" "100 100" "250 40" "1000 10"
+  do pgmnoise --randomseed=0 ${xysize} | pgmhist -mach | cksum
+  done
+
+
+tmpdir=${tmpdir:-/tmp}
+outfile=${tmpdir}/out
+
+echo "Test 6."
+echo "First column should be 2^n - 1.  Last column should be 'pool'."
+# The "pool" method of generating pixvals is used iff maxval is
+# a power of 2 minus 1: 1, 3, 7, 15, 31 ...
+
+    
+for maxval in \
+    1 2 3 4 5 6 7 8 9 \
+    10 11 12 13 14 15 16 17 18 19 \
+    20 21 22 23 24 25 26 27 28 29 \
+    30 31 32 33  60 61 62 63 64 65 \
+    127 255 511 1023  65535 \
+    129 142 186 219 677 1068 1788 1820 2067 2154 2301 2317 \
+    5180 5321 5596 6304 7565 9525 \
+    10501 14178 25797 27451 28653
+    do
+    pgmnoise -maxval=${maxval} -plain -randomseed=1 -verbose 1 1 \
+		 > /dev/null 2> ${outfile}
+    awk -v mval=${maxval} '/method/ && /pool/ { print mval, $0 }' ${outfile}
+    rm ${outfile}
+    done
+
+
+echo "Test Invalid"
+
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line arguments." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pgmnoise 0 0  > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmnoise 0 1  > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmnoise 1 0  > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmnoise      > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmnoise 1    > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmnoise 100 -1 > ${test_out} || \
+  printf "Expected failure 6"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmnoise -randomseed=-1 100 100  > ${test_out} || \
+  printf "Expected failure 7"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmnoise -maxval=-1 100 100  > ${test_out} || \
+  printf "Expected failure 8"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmnoise -maxval=0 100 100  > ${test_out} || \
+  printf "Expected failure 9"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmnoise -maxval=$((256 * 256 * 256 * 256)) 10 10 > ${test_out} || \
+  printf "Expected failure 10"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pgmramp.ok b/test/pgmramp.ok
index 989ef7d4..de0d9206 100644
--- a/test/pgmramp.ok
+++ b/test/pgmramp.ok
@@ -1,3 +1,4 @@
+Test 1
 P2
 4 4
 6
@@ -33,8 +34,16 @@ P2
 1 2 3 4
 2 3 4 5
 3 4 5 6
+Test 2
 1777787286 65551
 2046889993 65551
 1975520432 65551
 807973067 65551
+Test 3
 886972785 131087
+Test Invalid
+Expected failure: -lr -tb 1
+Expected failure: -lr -rectangle 1
+Expected failure: -rectangle -ellipse 1
+Expected failure: insufficient parameters 1
+Expected failure: excessive parameters 1
diff --git a/test/pgmramp.test b/test/pgmramp.test
index f6f770fe..b4dbb3cd 100755
--- a/test/pgmramp.test
+++ b/test/pgmramp.test
@@ -1,15 +1,47 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pgmramp
 # Also requires:
 
+echo "Test 1"
 
 for type in -lr -tb -rectangle -ellipse -diagonal
 do
 pgmramp -maxval=6 $type 4 4 -plain
 done
 
+echo "Test 2"
+
 for type in -lr -tb -rectangle -ellipse
 do pgmramp $type 256 256 | cksum
 done
 
+echo "Test 3"
+
 pgmramp -diagonal -maxval=510 256 256 | cksum
+
+echo "Test Invalid"
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+for combination in "-lr -tb" "-lr -rectangle" "-rectangle -ellipse"
+do pgmramp $combination 10 10 > ${test_out} || \
+  printf "Expected failure: $combination"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+done
+
+pgmramp -lr     1 > ${test_out} || \
+  printf "Expected failure: insufficient parameters"; \
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmramp -tb 1 1 1 > ${test_out} || \
+  printf "Expected failure: excessive parameters"; \
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pgmtopgm.ok b/test/pgmtopgm.ok
index 53c25a44..38cfd268 100644
--- a/test/pgmtopgm.ok
+++ b/test/pgmtopgm.ok
@@ -1 +1,11 @@
-729348909 237
+Test 1.  Should print two identical PGM images
+P2
+10 1
+255
+0 0 0 0 0 0 0 0 0 0
+P2
+10 1
+255
+0 0 0 0 0 0 0 0 0 0
+Test 2.  Should print 2582999797 3376
+2582999797 3376
diff --git a/test/pgmtopgm.test b/test/pgmtopgm.test
index e919fdac..d81260d8 100755
--- a/test/pgmtopgm.test
+++ b/test/pgmtopgm.test
@@ -1,6 +1,12 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pgmtopgm
-# Also requires:
+# Also requires: pgmmake
 
+echo "Test 1.  Should print two identical PGM images"
 
-pgmtopgm < testgrid.pbm | cksum
+pgmmake -plain 0 10 1
+pgmmake 0 10 1 | pgmtopgm -plain
+
+echo "Test 2.  Should print 2582999797 3376"
+
+pgmtopgm < maze.pbm | cksum
diff --git a/test/pgmtoppm.ok b/test/pgmtoppm.ok
index 55e5af95..2484c487 100644
--- a/test/pgmtoppm.ok
+++ b/test/pgmtoppm.ok
@@ -1,3 +1,39 @@
+Test 1.  Should print 1767073524 779 twice, then 1676700883 779
+1767073524 779
 1767073524 779
 1676700883 779
+Test 2.  Should print 718580145 779 twice
+718580145 779
+718580145 779
+Test 3.  Should print 718580145 779 twice
+718580145 779
 718580145 779
+Test 4.  Should print 829921912 685 seven times
+829921912 685
+829921912 685
+829921912 685
+829921912 685
+829921912 685
+829921912 685
+829921912 685
+Test 5.  Should print 934505096 685 four times
+934505096 685
+934505096 685
+934505096 685
+934505096 685
+Test 6. Should print 3083028153 685 three times
+3083028153 685
+3083028153 685
+3083028153 685
+Test 7 Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
+Expected failure 7 1
+Expected failure 8 1
+Expected failure 9 1
+Expected failure 10 1
+Expected failure 11 1
diff --git a/test/pgmtoppm.test b/test/pgmtoppm.test
index 70df0d97..36f63de7 100755
--- a/test/pgmtoppm.test
+++ b/test/pgmtoppm.test
@@ -1,22 +1,139 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pgmtoppm
-# Also requires: pamseq pamtopnm pgmramp
-
+# Also requires: pamtopnm pnminvert pamseq pgmramp
 
 tmpdir=${tmpdir:-/tmp}
 
+echo "Test 1.  Should print 1767073524 779 twice, then 1676700883 779"
+
 test_pgm=${tmpdir}/test.pgm
-palette=${tmpdir}/palette
+palette_pam=${tmpdir}/palette.pam
+palette_ppm=${tmpdir}/palette.ppm
 
-pgmramp -maxval=5 -lr 256 1 >${test_pgm}
-pamseq 3 5 -tupletype=RGB | pamtopnm \
-  >${palette}
+pgmramp -maxval=5 -lr 256 1 > ${test_pgm}
 
-# Test 1.
 pgmtoppm green ${test_pgm} | cksum
-
+pgmtoppm black-green ${test_pgm} | cksum
 pgmtoppm yellow-blue ${test_pgm} | cksum
 
-pgmtoppm -map=${palette} ${test_pgm} | cksum
 
-rm ${test_pgm} ${palette}
+echo "Test 2.  Should print 718580145 779 twice"
+pamseq 3 5 -tupletype=RGB | tee ${palette_pam} | pamtopnm > ${palette_ppm}
+pgmtoppm -map=${palette_pam} ${test_pgm} | cksum
+pgmtoppm -map=${palette_ppm} ${test_pgm} | cksum
+
+rm ${palette_pam}
+
+echo "Test 3.  Should print 718580145 779 twice"
+
+pgmtoppm white-black ${test_pgm} | pnminvert | cksum
+pnminvert ${test_pgm} | pgmtoppm white-black | cksum
+
+rm ${test_pgm}
+
+echo "Test 4.  Should print 829921912 685 seven times"
+
+pgmtoppm white testgrid.pbm | cksum
+pgmtoppm black-white testgrid.pbm | cksum
+pgmtoppm rgb:ff/ff/ff testgrid.pbm | cksum
+pgmtoppm -white=rgb-255:255/255/255 testgrid.pbm | cksum
+pgmtoppm rgb:00/00/00-rgb:ff/ff/ff testgrid.pbm | cksum
+pgmtoppm rgbi:0/0/0-rgbi:1/1/1 testgrid.pbm | cksum
+pgmtoppm -black=rgb-255:0/0/0 -white=rgb-255:255/255/255 testgrid.pbm | cksum
+
+echo "Test 5.  Should print 934505096 685 four times"
+
+pgmtoppm white-black testgrid.pbm | cksum
+pgmtoppm white testgrid.pbm | pnminvert| cksum
+pnminvert testgrid.pbm | pgmtoppm black-white | cksum
+pnminvert testgrid.pbm | pgmtoppm white | cksum
+
+echo "Test 6. Should print 3083028153 685 three times"
+
+pgmtoppm black testgrid.pbm | cksum
+pgmtoppm black-black testgrid.pbm | cksum
+pgmtoppm rgbi:0/0/0-rgbi:0/0/0 testgrid.pbm | cksum
+
+echo "Test 7 Invalid"
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pgmtoppm white testimg.ppm > \
+  ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmtoppm -map=/dev/null testgrid.pbm > \
+  ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmtoppm black white testgrid.pbm > \
+  ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmtoppm hwite testgrid.pbm > \
+  ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmtoppm off-color testgrid.pbm > \
+  ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmtoppm rgb-255:7/7/7 testgrid.pbm > \
+  ${test_out} || \
+  printf "Expected failure 6"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmtoppm -black=black -white=white white testgrid.pbm > \
+  ${test_out} || \
+  printf "Expected failure 7"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmtoppm -black=rgb:0/0/0 -map=${palette_ppm} testgrid.pbm > \
+  ${test_out} || \
+  printf "Expected failure 8"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmtoppm -white=rgb:ff/ff/ff -map=${palette_ppm} testgrid.pbm > \
+  ${test_out} || \
+  printf "Expected failure 9"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmtoppm rgb:ff/ff/ff -map=${palette_ppm} testgrid.pbm > \
+  ${test_out} || \
+  printf "Expected failure 10"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pgmtoppm rgb:00/00/00-rgb:ff/ff/ff -map=${palette_ppm} testgrid.pbm > \
+  ${test_out} || \
+  printf "Expected failure 11"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+#pgmtoppm rgb-255:7/7/7 testgrid.pbm > \
+#  ${test_out} || \
+#  printf "Expected failure 12"
+#  test -s ${test_out}; echo " "$?
+#  rm -f ${test_out}
+
+rm -f ${palette_ppm}
diff --git a/test/pi3-roundtrip.ok b/test/pi3-roundtrip.ok
index 3fde31b1..c4351b83 100644
--- a/test/pi3-roundtrip.ok
+++ b/test/pi3-roundtrip.ok
@@ -1,2 +1,5 @@
+Test 1. Should print: 3139449799 32011 twice
 3139449799 32011
-2425386270 41
+3139449799 32011
+Test 2. Should print: 281226646 481, cksum of maze.pbm
+281226646 481
diff --git a/test/pi3-roundtrip.test b/test/pi3-roundtrip.test
index 5700337d..d795157d 100755
--- a/test/pi3-roundtrip.test
+++ b/test/pi3-roundtrip.test
@@ -1,16 +1,15 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pbmtopi3 pi3topbm
-# Also requires: pbmmake pamcut
-
+# Also requires: pbmmake pamcut pamfile
 
 # The pi3 image format specifies a fixed image size of 640x400.
 # Pbmtopi3 rejects images that do not conform.
 
-# Test
-# Should print: 3139449799 32011
+echo "Test 1. Should print: 3139449799 32011 twice"
+pbmmake -g 640 400 | cksum
 pbmmake -g 640 400 | pbmtopi3 | pi3topbm | cksum
 
-# Test 2.
-# Should print: 2425386270 41
-pamcut -pad 0 0 640 400 testgrid.pbm | \
-  pbmtopi3 | pi3topbm | pamcut 0 0 14 16 | cksum
+echo "Test 2. Should print: 281226646 481, cksum of maze.pbm"
+size=$(pamfile -size maze.pbm | awk '{print "-width="$1,"-height="$2}')
+pamcut -pad -left=0 -top=0 -width=640 -height=400 maze.pbm | \
+  pbmtopi3 | pi3topbm | pamcut -left=0 -top=0 ${size} | cksum
diff --git a/test/pict-roundtrip.test b/test/pict-roundtrip.test
index cd207d48..b4910064 100755
--- a/test/pict-roundtrip.test
+++ b/test/pict-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: picttoppm ppmtopict
 # Also requires: pamseq pamdepth pamtopnm pnmremap
 
diff --git a/test/pj-roundtrip.ok b/test/pj-roundtrip.ok
new file mode 100644
index 00000000..195443ba
--- /dev/null
+++ b/test/pj-roundtrip.ok
@@ -0,0 +1,4 @@
+Test 1. Should print:  0 0 0 0 : 0
+0 0 0 0 : 0
+Test 2. Should print:  0 0 : 0
+0 0 : 0
diff --git a/test/pj-roundtrip.test b/test/pj-roundtrip.test
new file mode 100755
index 00000000..3ed30927
--- /dev/null
+++ b/test/pj-roundtrip.test
@@ -0,0 +1,26 @@
+#! /bin/bash
+# This script tests: ppmtopj pjtoppm
+# Also requires: pamseq pnmremap pamtopnm pamdepth ppmtoppm
+
+echo "Test 1. Should print:  0 0 0 0 : 0"
+
+tmpdir=${tmpdir:-/tmp}
+test8_ppm=${tmpdir}/testimg8.ppm
+
+pamseq 3 1 | pnmremap -map - testimg.ppm | pamtopnm -assume > ${test8_ppm}
+
+ppmtopj ${test8_ppm} | pjtoppm | pamdepth 1 | \
+  cmp -s - ${test8_ppm} > /dev/null
+  echo ${PIPESTATUS[@]} ":" $?
+
+rm ${test8_ppm}
+
+echo "Test 2. Should print:  0 0 : 0"
+
+testout_ppm=${tmpdir}/testout.ppm
+
+ppmtopj maze.pbm | pjtoppm > ${testout_ppm}
+  ppmtoppm < maze.pbm | cmp -s - ${testout_ppm} > /dev/null
+  echo ${PIPESTATUS[@]} ":" $?
+
+rm ${testout_ppm}
diff --git a/test/png-roundtrip.ok b/test/png-roundtrip.ok
index 28b8c057..ec0a1937 100644
--- a/test/png-roundtrip.ok
+++ b/test/png-roundtrip.ok
@@ -16,21 +16,21 @@
 1926073387 101484
 1926073387 101484
 1926073387 101484
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
diff --git a/test/png-roundtrip.test b/test/png-roundtrip.test
index 7e7c4a9b..97cf9b2c 100755
--- a/test/png-roundtrip.test
+++ b/test/png-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pngtopam pnmtopng
 # Also requires:
 
@@ -28,7 +28,7 @@ for flags in "" -interlace \
 pnmtopng testimg.ppm $flags | pngtopam | cksum
 done
 
-# Test 2.  Should print 2425386270 41 18 times
+# Test 2.  Should print 281226646 481 18 times
 for flags in "" -interlace \
   -gamma=.45 \
   -hist \
@@ -47,5 +47,5 @@ for flags in "" -interlace \
   -comp_strategy=filtered \
   -force
   do
-  pnmtopng testgrid.pbm $flags | pngtopam | cksum
+  pnmtopng maze.pbm $flags | pngtopam | cksum
   done
diff --git a/test/png-roundtrip2.ok b/test/png-roundtrip2.ok
index 0e712ce7..764cadfa 100644
--- a/test/png-roundtrip2.ok
+++ b/test/png-roundtrip2.ok
@@ -1,4 +1,4 @@
 1926073387 101484
 1926073387 101484
-2425386270 41
-2425386270 41
+281226646 481
+281226646 481
diff --git a/test/png-roundtrip2.test b/test/png-roundtrip2.test
index af2ad029..85149a91 100755
--- a/test/png-roundtrip2.test
+++ b/test/png-roundtrip2.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pngtopam pamtopng
 # Also requires:
 
@@ -15,8 +15,8 @@ for flags in "" -gamma=.45
   pamtopng testimg.ppm $flags | pngtopam | cksum
   done
 
-# Test 2.  Should print 2425386270 41 twice
+# Test 2.  Should print 281226646 481 twice
 for flags in "" -gamma=.45
   do
-  pamtopng testgrid.pbm $flags | pngtopam | cksum
+  pamtopng maze.pbm $flags | pngtopam | cksum
   done
diff --git a/test/pnm-pam-roundtrip.ok b/test/pnm-pam-roundtrip.ok
index 67f7a1fe..ace97410 100644
--- a/test/pnm-pam-roundtrip.ok
+++ b/test/pnm-pam-roundtrip.ok
@@ -1,2 +1,2 @@
 1926073387 101484
-2425386270 41
+281226646 481
diff --git a/test/pnm-pam-roundtrip.test b/test/pnm-pam-roundtrip.test
index b8e60c88..da3021f9 100755
--- a/test/pnm-pam-roundtrip.test
+++ b/test/pnm-pam-roundtrip.test
@@ -1,7 +1,7 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamtopam pamtopnm
 # Also requires:
 
 
 pamtopam < testimg.ppm | pamtopnm | cksum
-pamtopam < testgrid.pbm | pamtopnm | cksum
+pamtopam < maze.pbm | pamtopnm | cksum
diff --git a/test/pnm-plain-roundtrip.ok b/test/pnm-plain-roundtrip.ok
index 67f7a1fe..ace97410 100644
--- a/test/pnm-plain-roundtrip.ok
+++ b/test/pnm-plain-roundtrip.ok
@@ -1,2 +1,2 @@
 1926073387 101484
-2425386270 41
+281226646 481
diff --git a/test/pnm-plain-roundtrip.test b/test/pnm-plain-roundtrip.test
index 3779d761..14b8ca57 100755
--- a/test/pnm-plain-roundtrip.test
+++ b/test/pnm-plain-roundtrip.test
@@ -1,9 +1,9 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamtopnm
 #
 
 
 pamtopnm -plain testimg.ppm | \
   pamtopnm | cksum
-pamtopnm -plain testgrid.pbm | \
+pamtopnm -plain maze.pbm | \
   pamtopnm | cksum
diff --git a/test/pnmcat.ok b/test/pnmcat.ok
index 68052957..96e2b884 100644
--- a/test/pnmcat.ok
+++ b/test/pnmcat.ok
@@ -1,4 +1,98 @@
-1704087873 73
-4150323653 73
-1522490272 202953
-2862441566 202953
+Test 1.  Should print a simple PBM image five times
+P1
+2 2
+01
+10
+P1
+2 2
+01
+10
+P1
+2 2
+01
+10
+P1
+2 2
+01
+10
+P1
+2 2
+01
+10
+Test 2.  Should print 2197356643 895 twice
+2197356643 895
+2197356643 895
+Test 3.  Should print 3313353797 954
+3313353797 954
+Test 4.  Should print 1731660895 1308 three times
+1731660895 1308
+1731660895 1308
+1731660895 1308
+Test 5.  Should print 2985957591 1426 three times
+2985957591 1426
+2985957591 1426
+2985957591 1426
+Test 6.  Should print a simple PGM image three times
+P2
+4 4
+3
+0 0 1 1
+0 1 1 2
+1 1 2 2
+1 2 2 3
+P2
+4 4
+3
+0 0 1 1
+0 1 1 2
+1 1 2 2
+1 2 2 3
+P2
+4 4
+3
+0 0 1 1
+0 1 1 2
+1 1 2 2
+1 2 2 3
+Test 7.  Should print 2097565808 394 twice
+2097565808 394
+2097565808 394
+Test 8.  Should print 3086569577 394
+3086569577 394
+Test 9.  Should print 4288335051 586 three times
+4288335051 586
+4288335051 586
+4288335051 586
+Test 10.  Should print 642720605 586 three times
+642720605 586
+642720605 586
+642720605 586
+Test 11.  Should print 3622741282 1019 twice
+3622741282 1019
+3622741282 1019
+Test 12.  Should print 1401081637 1019
+1401081637 1019
+Test 13.  Should print 2756501917 1019
+2756501917 1019
+Test 14. Should print 587933655 107742 twice
+587933655 107742
+587933655 107742
+Test 15.  Should print 3948141157 107742
+3948141157 107742
+Test 16.  Should print 3910239002 107742
+3910239002 107742
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
+Expected failure 7 1
+Expected failure 8 1
+Expected failure 9 1
+Expected failure 10 1
+Expected failure 11 1
+Expected failure 12 1
+Expected failure 13 1
+Expected failure 14 1
diff --git a/test/pnmcat.test b/test/pnmcat.test
index c643320d..bf40ada2 100755
--- a/test/pnmcat.test
+++ b/test/pnmcat.test
@@ -1,10 +1,184 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pnmcat
-# Also requires:
+# Also requires: pbmmake pgmramp ppmtoppm pamcat
 
+if [ ${CHECK_TYPE} = tree ]
+  then echo "Skipping." 1>&2
+       echo "Running \"make package; make check\" is recommended." 1>&2
+  exit 80;
+fi
 
-pnmcat -lr testgrid.pbm testgrid.pbm | cksum
-pnmcat -tb testgrid.pbm testgrid.pbm | cksum
+tmpdir=${tmpdir:-/tmp}
+check2x2_pbm=${tmpdir}/check2x2.pbm
+maze2lr_pbm=${tmpdir}/maze2lr.pbm
+maze2tb_pbm=${tmpdir}/maze2tb.pbm
+diag_pgm=${tmpdir}/diag.pgm
+diag_ppm=${tmpdir}/diag.ppm
+diag2lr_ppm=${tmpdir}/diag2lr.ppm
+diag2tb_ppm=${tmpdir}/diag2tb.ppm
 
-pnmcat -lr testimg.ppm testimg.ppm | cksum
-pnmcat -tb testimg.ppm testimg.ppm | cksum
+echo "Test 1.  Should print a simple PBM image five times"
+# Check input from stdin and from designated input file
+# Similar to tests in stdin-p?m.test
+
+pbmmake -g 2 2 | tee ${check2x2_pbm} | pnmcat -lr -plain
+pnmcat -tb -plain ${check2x2_pbm}
+pnmcat -tb -plain < ${check2x2_pbm}
+pnmcat -lr -black -plain ${check2x2_pbm}
+cat ${check2x2_pbm} | pnmcat -tb -white -plain
+
+rm ${check2x2_pbm}
+
+echo "Test 2.  Should print 2197356643 895 twice"
+pnmcat -lr -white maze.pbm maze.pbm | tee ${maze2lr_pbm} | cksum
+cat maze.pbm | pnmcat -lr -black maze.pbm - | cksum
+
+echo "Test 3.  Should print 3313353797 954"
+pnmcat -tb maze.pbm maze.pbm | tee ${maze2tb_pbm} | cksum
+
+echo "Test 4.  Should print 1731660895 1308 three times"
+pnmcat -lr maze.pbm maze.pbm maze.pbm | cksum
+pnmcat -lr ${maze2lr_pbm} maze.pbm | cksum
+cat ${maze2lr_pbm} | pnmcat -lr - maze.pbm | cksum
+
+echo "Test 5.  Should print 2985957591 1426 three times"
+pnmcat -tb maze.pbm maze.pbm maze.pbm | cksum
+pnmcat -tb maze.pbm ${maze2tb_pbm} | cksum
+cat maze.pbm | pnmcat -tb - ${maze2tb_pbm} | cksum
+
+rm ${maze2lr_pbm} ${maze2tb_pbm}
+
+echo "Test 6.  Should print a simple PGM image three times"
+# Use sed to scrape off space at line end for compatibility
+# with older versions of pnmcat
+
+pgmramp -diag 4 4 -maxval=3 | tee ${diag_pgm} | pnmcat -lr -plain |\
+  sed 's/ *$//'
+pnmcat -tb -plain ${diag_pgm} | sed 's/ *$//'
+cat ${diag_pgm} | pnmcat -tb -plain | sed 's/ *$//'
+
+rm ${diag_pgm}
+
+pgmramp -diag 8 8 -maxval 7 | ppmtoppm > ${diag_ppm} 
+
+echo "Test 7.  Should print 2097565808 394 twice"
+pnmcat -lr -black ${diag_ppm} ${diag_ppm} | tee ${diag2lr_ppm} | cksum
+cat ${diag_ppm} | pnmcat -lr -white ${diag_ppm} - | cksum
+
+echo "Test 8.  Should print 3086569577 394"
+pnmcat -tb ${diag_ppm} ${diag_ppm} | tee ${diag2tb_ppm} | cksum
+
+echo "Test 9.  Should print 4288335051 586 three times"
+pnmcat -lr ${diag_ppm} ${diag_ppm} ${diag_ppm} | cksum
+pnmcat -lr ${diag_ppm}  ${diag2lr_ppm} | cksum 
+cat ${diag2lr_ppm} | pnmcat -lr - ${diag_ppm} | cksum
+
+echo "Test 10.  Should print 642720605 586 three times"
+pnmcat -tb ${diag_ppm} ${diag_ppm} ${diag_ppm} | cksum
+pnmcat -tb ${diag2tb_ppm} ${diag_ppm} | cksum
+cat ${diag_ppm} | pnmcat -tb ${diag2tb_ppm} - | cksum
+
+rm ${diag2lr_ppm} ${diag2tb_ppm}
+
+echo "Test 11.  Should print 3622741282 1019 twice"
+pnmcat -tb -white testgrid.pbm ${diag_ppm} | cksum
+pnmcat -tb -jcenter -white testgrid.pbm ${diag_ppm} | cksum
+echo "Test 12.  Should print 1401081637 1019"
+pnmcat -tb -jleft -white testgrid.pbm ${diag_ppm}  | cksum
+echo "Test 13.  Should print 2756501917 1019"
+pnmcat -tb -jright -white testgrid.pbm ${diag_ppm} | cksum
+
+echo "Test 14. Should print 587933655 107742 twice"
+pnmcat -lr -black testgrid.pbm testimg.ppm | cksum
+pnmcat -lr -jcenter -black testgrid.pbm testimg.ppm | cksum
+echo "Test 15.  Should print 3948141157 107742"
+pnmcat -lr -jtop -black testgrid.pbm testimg.ppm | cksum
+echo "Test 16.  Should print 3910239002 107742"
+pnmcat -lr -jbottom -black testgrid.pbm testimg.ppm | cksum
+
+rm ${diag_ppm}
+
+echo "Test Invalid"
+
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+# direction not specified
+pnmcat testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# both directions specified
+pnmcat -topbottom -leftright testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# both pad colors specified
+pnmcat -topbottom -white -black testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# justification parameters overspecified
+pnmcat -lr -jtop -jbottom testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmcat -lr -jtop -jcenter testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmcat -lr -jcenter -jbottom testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 6"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmcat -tb -jleft -jright testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 7"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmcat -tb -jleft -jcenter testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 8"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmcat -tb -jcenter -jright testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 9"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# justification parameter in the wrong direction
+pnmcat -lr -jleft    testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 10"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmcat -lr -jright   testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 11"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmcat -tb -jtop     testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 12"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmcat -tb -jbottom  testgrid.pbm testimg.ppm > ${test_out} || \
+  printf "Expected failure 13"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# more than one input image from standard input
+cat testgrid.pbm | pnmcat -lr - - testimg.ppm > ${test_out} || \
+  printf "Expected failure 14"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pnmcolormap.ok b/test/pnmcolormap.ok
new file mode 100644
index 00000000..0c6f0d71
--- /dev/null
+++ b/test/pnmcolormap.ok
@@ -0,0 +1,40 @@
+Test 1.
+P1
+2 1
+10
+
+P1
+2 1
+10
+
+P1
+2 1
+10
+
+Test 2.
+P3
+3 1
+255
+0 0 255 64 0 191 128 0 128 
+
+P3
+2 2
+255
+0 0 255 64 0 191 
+128 0 128 128 0 128 
+
+Test 3.
+ok
+ok
+ok
+ok
+ok
+
+Test Invalid.
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
+Expected failure 7 1
diff --git a/test/pnmcolormap.test b/test/pnmcolormap.test
new file mode 100755
index 00000000..11d47385
--- /dev/null
+++ b/test/pnmcolormap.test
@@ -0,0 +1,80 @@
+#! /bin/sh
+# This script tests: pnmcolormap
+# Also requires: ppmpat
+
+echo "Test 1."
+
+pnmcolormap -plain -sort 2 maze.pbm
+echo
+pnmcolormap -plain -sort -square 2 maze.pbm
+echo
+pnmcolormap -plain -sort all maze.pbm
+echo
+tmpdir=${tmpdir:-/tmp}
+tartan_ppm=${tmpdir}/tartan.ppm
+
+echo "Test 2."
+
+ppmpat -tartan -color="rgb:00/00/ff,rgb:00/80/ff,rgb:80/00/80" 20 20 |\
+    tee ${tartan_ppm} | pnmcolormap -plain -sort all
+echo
+pnmcolormap -plain -sort -square all ${tartan_ppm}
+rm ${tartan_ppm}
+echo
+echo "Test 3."
+# Explicitly specify default options.  Output should not vary.
+
+map=${tmpdir}/map.ppm
+
+pnmcolormap 64 testimg.ppm > ${map} && echo ok || echo bad
+test -s ${map} && echo ok || echo bad
+pnmcolormap -center 64 testimg.ppm | cmp -s ${map} - && echo ok || echo bad
+pnmcolormap -spreadbrightness 64 testimg.ppm | cmp -s ${map} - && echo ok || echo bad
+pnmcolormap -splitpixelct 64 testimg.ppm | cmp -s ${map} - && echo ok || echo bad
+rm ${map}
+echo
+echo "Test Invalid."
+
+echo 1>&2
+echo "Invalid command-line arguments." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+pnmcolormap 0 testimg.ppm   > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmcolormap -1 testimg.ppm  > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmcolormap 0.1 testimg.ppm > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmcolormap -center -meancolor 16 testimg.ppm    > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmcolormap -center -meanpixel 16 testimg.ppm    > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmcolormap -meancolor -meanpixel 16 testimg.ppm > ${test_out} || \
+  printf "Expected failure 6"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmcolormap -spreadbrightness -spreadluminosity 16 \
+  testimg.ppm > ${test_out} || \
+  printf "Expected failure 7"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pnmcolormap2.ok b/test/pnmcolormap2.ok
new file mode 100644
index 00000000..2eab38b8
--- /dev/null
+++ b/test/pnmcolormap2.ok
@@ -0,0 +1,9 @@
+Test.  Should print 'match' eight times.
+match
+match
+match
+match
+match
+match
+match
+match
diff --git a/test/pnmcolormap2.test b/test/pnmcolormap2.test
new file mode 100755
index 00000000..bb870e7f
--- /dev/null
+++ b/test/pnmcolormap2.test
@@ -0,0 +1,55 @@
+#! /bin/sh
+# This script tests: pnmcolormap
+# Also requires: pnmremap pnmpsnr
+
+tmpdir=${tmpdir:-/tmp}
+map=${tmpdir}/map.ppm
+
+echo "Test.  Should print 'match' eight times."
+# Threshold values (targetN=xx.xx) here were produced by calculating
+# the S/N ratio with reduced colors.
+
+# colors in following tests / colors for calculating threshold
+# 100 /  90
+# 200 / 180
+#  30 /  25
+
+pnmcolormap 100 testimg.ppm > ${map}
+pnmremap -mapfile=${map} testimg.ppm |\
+  pnmpsnr -target1=33.42 -target2=35.14 -target3=34.35 testimg.ppm -
+rm ${map}
+
+pnmcolormap -meancolor 100 testimg.ppm > ${map}
+pnmremap -mapfile=${map} testimg.ppm |\
+  pnmpsnr -target1=34.91 -target2=36.86 -target3=35.84 testimg.ppm -
+rm ${map}
+
+pnmcolormap -meanpixel 100 testimg.ppm > ${map}
+pnmremap -mapfile=${map} testimg.ppm |\
+  pnmpsnr -target1=34.95 -target2=36.77 -target3=35.81 testimg.ppm -
+rm ${map}
+
+pnmcolormap -spreadluminosity 100 testimg.ppm > ${map}
+pnmremap -mapfile=${map} testimg.ppm |\
+  pnmpsnr -target1=33.71 -target2=32.91 -target3=33.93 testimg.ppm -
+rm ${map}
+
+pnmcolormap -splitcolorct 100 testimg.ppm > ${map}
+pnmremap -mapfile=${map} testimg.ppm |\
+  pnmpsnr -target1=33.97 -target2=35.34 -target3=34.23 testimg.ppm -
+rm ${map}
+
+pnmcolormap -splitspread 100 testimg.ppm > ${map}
+pnmremap -mapfile=${map} testimg.ppm |\
+  pnmpsnr -target1=32.98 -target2=35.06 -target3=33.19 testimg.ppm -
+rm ${map}
+
+pnmcolormap 200 testimg.ppm > ${map}
+pnmremap -mapfile=${map} testimg.ppm |\
+  pnmpsnr -target1=36.14 -target2=36.87 -target3=36.79 testimg.ppm -
+rm ${map}
+
+pnmcolormap 30 testimg.ppm > ${map}
+pnmremap -mapfile=${map} testimg.ppm |\
+  pnmpsnr -target1=28.53 -target2=31.62 -target3=29.99 testimg.ppm -
+rm ${map}
diff --git a/test/pnmcrop-blank.ok b/test/pnmcrop-blank.ok
new file mode 100644
index 00000000..55103acb
--- /dev/null
+++ b/test/pnmcrop-blank.ok
@@ -0,0 +1,130 @@
+Test 1
+-blank-image=pass
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+-blank-image=minimize
+-7 -7 -7 -6 1 1
+0 0 0 0 15 14
+-7 -7 -7 -6 1 1
+-7 -7 -7 -6 1 1
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+-7 -7 -7 -6 1 1
+-blank-image=minimize -top
+0 0 -13 0 15 1
+0 0 0 0 15 14
+0 0 -13 0 15 1
+0 0 -13 0 15 1
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 -13 0 15 1
+-blank-image=minimize -bottom
+0 0 0 -13 15 1
+0 0 0 0 15 14
+0 0 0 -13 15 1
+0 0 0 -13 15 1
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 -13 15 1
+-blank-image=minimize -left
+-14 0 0 0 1 14
+0 0 0 0 15 14
+-14 0 0 0 1 14
+-14 0 0 0 1 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+-14 0 0 0 1 14
+-blank-image=minimize -right
+0 -14 0 0 1 14
+0 0 0 0 15 14
+0 -14 0 0 1 14
+0 -14 0 0 1 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 -14 0 0 1 14
+-blank-image=minimize -left -right
+-7 -7 0 0 1 14
+0 0 0 0 15 14
+-7 -7 0 0 1 14
+-7 -7 0 0 1 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+-7 -7 0 0 1 14
+-blank-image=maxcrop
+-15 -15 -14 -14 15 14
+0 0 0 0 15 14
+-15 -15 -14 -14 15 14
+-15 -15 -14 -14 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+-15 -15 -14 -14 15 14
+-blank-image=abort
+fail1
+fail2
+0 0 0 0 15 14
+0 0 0 0 15 14
+fail3
+
+fail1
+fail2
+0 0 0 0 15 14
+0 0 0 0 15 14
+fail3
+Test 2
+-blank-image=maxcrop -top
+0 0 -99 0 100 99
+0 0 -99 0 100 99
+0 0 0 0 100 99
+-blank-image=minimize
+-50 -49 -49 -49 1 1
+-50 -49 -49 -49 1 1
+0 0 0 0 100 99
+-blank-image=maxcrop
+-100 -100 -99 -99 100 99
+-100 -100 -99 -99 100 99
+0 0 0 0 100 99
+-blank-image=maxcrop -top
+0 0 -99 0 100 99
+0 0 -99 0 100 99
+0 0 0 0 100 99
+-blank-image=maxcrop -bottom
+0 0 0 -99 100 99
+0 0 0 -99 100 99
+0 0 0 0 100 99
+-blank-image=maxcrop -left
+-100 0 0 0 100 99
+-100 0 0 0 100 99
+0 0 0 0 100 99
+-blank-image=maxcrop -right
+0 -100 0 0 100 99
+0 -100 0 0 100 99
+0 0 0 0 100 99
+-blank-image=maxcrop -top -bottom -right
+0 -100 -99 -99 100 99
+0 -100 -99 -99 100 99
+0 0 0 0 100 99
+
+fail4
+fail5
+0 0 0 0 100 99
diff --git a/test/pnmcrop-blank.test b/test/pnmcrop-blank.test
new file mode 100755
index 00000000..bb26bdc0
--- /dev/null
+++ b/test/pnmcrop-blank.test
@@ -0,0 +1,55 @@
+#! /bin/sh
+# This script tests: pnmcrop
+# Also requires: pbmmake ppmmake
+
+tmpdir=${tmpdir:-/tmp}
+
+test_pbm=${tmpdir}/test.pbm
+test_ppm=${tmpdir}/test.ppm
+
+echo "Error messages should appear below the line." 1>&2
+echo "--------------------------------------------" 1>&2
+
+#Test 1
+echo Test 1
+
+( pbmmake -white 15 14; pbmmake -gray 15 14; pbmmake -black 15 14 ) > \
+  ${test_pbm}
+for type in    "-blank-image=pass" \
+               "-blank-image=minimize" \
+               "-blank-image=minimize -top" \
+               "-blank-image=minimize -bottom" \
+               "-blank-image=minimize -left" \
+               "-blank-image=minimize -right" \
+               "-blank-image=minimize -left -right" \
+               "-blank-image=maxcrop" \
+               "-blank-image=abort" ""
+  do
+  echo ${type}
+  pnmcrop -reportsize ${type} ${test_pbm} || echo "fail1"
+  pnmcrop -reportsize ${type} -white ${test_pbm} || echo "fail2"
+  pnmcrop -reportsize ${type} -black ${test_pbm} || echo "fail3"
+  done
+
+rm ${test_pbm}
+
+
+#Test 2
+
+ppmmake rgb:ff/ff/ff 100 99 > ${test_ppm}
+echo Test 2
+for type in    "-blank-image=maxcrop -top" \
+               "-blank-image=minimize" "-blank-image=maxcrop" \
+               "-blank-image=maxcrop -top" \
+               "-blank-image=maxcrop -bottom" \
+               "-blank-image=maxcrop -left" \
+               "-blank-image=maxcrop -right" \
+               "-blank-image=maxcrop -top -bottom -right" ""
+  do
+  echo ${type}
+  pnmcrop -reportsize ${type} ${test_ppm} || echo "fail4"
+  pnmcrop -reportsize ${type} -white ${test_ppm} || echo "fail5"
+  pnmcrop -reportsize ${type} -black ${test_ppm} || echo "fail6"
+  done
+
+rm ${test_ppm}
\ No newline at end of file
diff --git a/test/pnmcrop1.ok b/test/pnmcrop1.ok
new file mode 100644
index 00000000..d979d2db
--- /dev/null
+++ b/test/pnmcrop1.ok
@@ -0,0 +1,82 @@
+Test 1
+file: maze.pbm option: 
+0 0 -7 0 71 68 rgb-1:1/1/1 0.000000
+file: maze.pbm option: -white
+0 0 -7 0 71 68 rgb-1:1/1/1 0.000000
+file: maze.pbm option: -black
+0 0 0 -2 71 73 rgb-1:0/0/0 0.000000
+file: maze.pbm option: -sides
+0 0 -7 0 71 68 rgb-1:1/1/1 0.000000
+file: maze.pbm option: -top
+0 0 -7 0 71 68 rgb-1:1/1/1 0.000000
+file: maze.pbm option: -bottom
+0 0 0 0 71 75 rgb-1:1/1/1 0.000000
+file: maze.pbm option: -left
+0 0 0 0 71 75 rgb-1:1/1/1 0.000000
+file: maze.pbm option: -right
+0 0 0 0 71 75 rgb-1:1/1/1 0.000000
+file: maze.pbm option: -top -bottom
+0 0 -7 0 71 68 rgb-1:1/1/1 0.000000
+file: maze.pbm option: -bottom -bg-corner=bottomright
+0 0 0 -2 71 73 rgb-1:0/0/0 0.000000
+file: maze.pbm option: -right -bg-corner=bottomright
+0 0 0 0 71 75 rgb-1:0/0/0 0.000000
+file: maze.pbm option: -bg-color=white
+0 0 0 0 71 75 rgb-1:1/1/1 0.000000
+file: maze.pbm option: -bg-color=black
+0 0 0 -2 71 73 rgb-1:0/0/0 0.000000
+file: maze.pbm option: -bg-color=red
+0 0 0 0 71 75 rgb-1:0/0/0 0.000000
+file: rose.ppm option: 
+0 0 0 0 250 161 rgb-255:127/127/127 0.000000
+file: rose.ppm option: -white
+-6 0 0 0 244 161 rgb-255:255/255/255 0.000000
+file: rose.ppm option: -black
+0 -11 0 0 239 161 rgb-255:0/0/0 0.000000
+file: rose.ppm option: -sides
+-6 0 0 0 244 161 rgb-255:255/255/255 0.000000
+file: rose.ppm option: -top
+0 0 0 0 250 161 rgb-255:127/127/127 0.000000
+file: rose.ppm option: -bottom
+0 0 0 0 250 161 rgb-255:127/127/127 0.000000
+file: rose.ppm option: -left
+0 0 0 0 250 161 rgb-255:127/127/127 0.000000
+file: rose.ppm option: -right
+0 0 0 0 250 161 rgb-255:127/127/127 0.000000
+file: rose.ppm option: -top -bottom
+0 0 0 0 250 161 rgb-255:127/127/127 0.000000
+file: rose.ppm option: -bottom -bg-corner=bottomright
+0 0 0 0 250 161 rgb-255:0/0/0 0.000000
+file: rose.ppm option: -right -bg-corner=bottomright
+0 -11 0 0 239 161 rgb-255:0/0/0 0.000000
+file: rose.ppm option: -bg-color=white
+-6 0 0 0 244 161 rgb-255:255/255/255 0.000000
+file: rose.ppm option: -bg-color=black
+0 -11 0 0 239 161 rgb-255:0/0/0 0.000000
+file: rose.ppm option: -bg-color=red
+0 0 0 0 250 161 rgb-255:255/0/0 0.000000
+Test 2.  Should print 0 six times
+file: maze.pbm option:
+0
+file: maze.pbm option: -white
+0
+file: maze.pbm option: -top
+0
+file: rose.ppm option:
+0
+file: rose.ppm option: -white
+0
+file: rose.ppm option: -top
+0
+Test Invalid
+Expected failure:  -reportfull -reportsize 1
+Expected failure:  -reportfull -borderfile=testgrid.pbm 1
+Expected failure:  -reportsize -borderfile=testgrid.pbm 1
+Expected failure:  -black -white 1
+Expected failure:  -black -sides 1
+Expected failure:  -white -bg-color=red 1
+Expected failure:  -white -bg-corner=topleft 1
+Expected failure:  -white -bg-corner=top 1
+Expected failure:  -blank-image=pasturize 1
+Expected failure:  -bg-color=black -closeness=-1 1
+Expected failure:  -bg-color=black -closeness=101 1
diff --git a/test/pnmcrop1.test b/test/pnmcrop1.test
new file mode 100755
index 00000000..3c86efd7
--- /dev/null
+++ b/test/pnmcrop1.test
@@ -0,0 +1,84 @@
+ #! /bin/sh
+# This script tests: pnmcrop
+# Also requires: pnmpad pnmmargin pamcut
+
+tmpdir=${tmpdir:-/tmp}
+
+test_pbm=${tmpdir}/maze.pbm
+test_ppm=${tmpdir}/rose.ppm
+
+pnmmargin -white 7 maze.pbm | pnmpad -black -bottom=2  > ${test_pbm}
+pnmmargin -white 6 testimg.ppm  | pnmpad -black -right=11  > ${test_ppm}
+
+#Test 1
+echo Test 1
+
+for input_file in ${test_pbm} ${test_ppm}
+  do
+  bfile=`basename ${input_file}`
+  for option in "" "-white" "-black" "-sides" \
+              "-top" "-bottom" "-left" "-right" "-top -bottom" \
+              "-bottom -bg-corner=bottomright" \
+              "-right -bg-corner=bottomright" \
+              "-bg-color=white" "-bg-color=black" "-bg-color=red"
+    do
+    echo "file: ${bfile} option: ${option}"
+    pnmcrop -reportfull ${option} ${input_file} || echo fail
+    done
+  done
+
+#Test 2
+echo "Test 2.  Should print 0 six times"
+
+out_pnm=${tmpdir}/out.pnm
+
+for input_file in ${test_pbm} ${test_ppm}
+  do
+  bfile=`basename ${input_file}`
+  for option in "" "-white" "-top"
+    do
+    echo file: ${bfile} option: ${option}
+    # Normal crop operation
+    pnmcrop ${option} ${input_file} > ${out_pnm}
+
+    # Compute edge extents with pnmcrop; let pamcut do the actual cropping
+    pamcut ${input_file} `pnmcrop -reportsize ${option} ${input_file} | \
+        awk 'NF==6 && NR==1 && \
+             $1<=0 && $2<=0 && $3<=0 && $4<=0 && $5>=0 && $6>=0 \
+             { printf("-cropleft=%d -cropright=%d ", -$1, -$2);
+               printf("-croptop=%d -cropbottom=%d ", -$3, -$4) }' ` | \
+        cmp -s - ${out_pnm}
+    echo $?
+    rm ${out_pnm}
+    done
+  done
+
+rm ${test_pbm} ${test_ppm}
+
+# Test 3
+echo "Test Invalid"
+
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+for option in "-reportfull -reportsize" \
+              "-reportfull -borderfile=testgrid.pbm" \
+              "-reportsize -borderfile=testgrid.pbm" \
+              "-black -white" \
+              "-black -sides" \
+              "-white -bg-color=red" \
+              "-white -bg-corner=topleft" \
+              "-white -bg-corner=top" \
+              "-blank-image=pasturize" \
+              "-bg-color=black -closeness=-1" \
+              "-bg-color=black -closeness=101"
+    do
+    pnmcrop -reportfull ${option} testgrid.pbm > ${test_out} || \
+        printf "Expected failure:  %s" "${option}"
+        test -s ${test_out}; echo " "$?
+        rm ${test_out}
+    done
diff --git a/test/pnmcrop2.ok b/test/pnmcrop2.ok
new file mode 100644
index 00000000..4eff830d
--- /dev/null
+++ b/test/pnmcrop2.ok
@@ -0,0 +1,29 @@
+Test 1
+
+0 0 0 0 5 5 rgb-200:2/2/2 0.000000
+-sides
+0 0 0 0 5 5 rgb-200:6/6/6 0.000000
+Test 2
+topleft
+0 0 0 0 5 5 rgb-200:0/0/0 0.000000
+topright
+0 0 0 0 5 5 rgb-200:4/4/4 0.000000
+bottomleft
+0 0 0 0 5 5 rgb-200:8/8/8 0.000000
+bottomright
+0 0 0 0 5 5 rgb-200:15/15/15 0.000000
+Test 3
+0
+0 0 0 0 5 5 rgb-200:0/0/0 0.000000
+1
+0 0 0 0 5 5 rgb-200:0/0/0 1.000000
+2
+0 0 -1 0 5 4 rgb-200:0/0/0 2.000000
+3
+-1 0 -1 0 4 4 rgb-200:0/0/0 3.000000
+4
+-1 0 -1 0 4 4 rgb-200:0/0/0 4.000000
+5
+-1 -1 -1 -1 3 3 rgb-200:0/0/0 5.000000
+6
+-1 -1 -1 -1 3 3 rgb-200:0/0/0 6.000000
diff --git a/test/pnmcrop2.test b/test/pnmcrop2.test
new file mode 100755
index 00000000..3d402a57
--- /dev/null
+++ b/test/pnmcrop2.test
@@ -0,0 +1,55 @@
+#! /bin/sh
+# This script tests: pnmcrop
+# Also requires:
+
+tmpdir=${tmpdir:-/tmp}
+test_pgm=${tmpdir}/test.pgm
+
+cat > ${test_pgm} << EOF
+P2
+5 5
+200
+0 1 2 3 4
+5 199 199 199 9
+6 199 199 199 10
+7 199 199 199 11
+8 12 13 14 15
+EOF
+
+# Test 1
+# Test color detection; none of the sides are cropped
+
+echo Test 1
+
+for option in "" "-sides"
+  do
+  echo ${option}
+  pnmcrop -reportfull ${option} ${test_pgm} || echo fail1
+  done
+
+# Test 2
+# Test color detection; none of the sides are cropped
+echo Test 2
+
+for corner in topleft topright bottomleft bottomright
+  do
+  echo ${corner}
+  pnmcrop -reportfull -bg-corner=${corner} ${test_pgm} || echo fail2
+  done
+
+# Test 3
+# Left edge   is cropped at closeness 2% and above
+# Top  edge   is cropped at closeness 3% and above
+# All  edges are cropped at closeness 5% and above
+
+echo Test 3
+
+for closeness in 0 1 2 3 4 5 6  # for closeness in `seq 0 6`
+  do
+  echo ${closeness}
+  pnmcrop -reportfull -bg-corner=topleft -closeness=${closeness} ${test_pgm} \
+    || echo fail3
+  done
+
+rm ${test_pgm}
+
diff --git a/test/pnmcrop3.ok b/test/pnmcrop3.ok
new file mode 100644
index 00000000..5a86139c
--- /dev/null
+++ b/test/pnmcrop3.ok
@@ -0,0 +1,90 @@
+Test 1
+test.pbm
+-left
+-12 0 0 0 15 24
+-right
+0 -2 0 0 25 24
+-top
+0 0 -3 0 27 21
+-bottom
+0 0 0 -6 27 18
+-left -right
+-12 -2 0 0 13 24
+-left -bottom
+-12 0 0 -6 15 18
+-right -bottom
+0 -2 0 -6 25 18
+test.ppm
+-left
+-21 0 0 0 236 161
+-right
+0 -9 0 0 248 161
+-top
+0 0 -11 0 257 150
+-bottom
+0 0 0 -1 257 160
+-left -right
+-21 -9 0 0 227 161
+-left -bottom
+-21 0 0 -1 236 160
+-right -bottom
+0 -9 0 -1 248 160
+Test 2
+test.pbm
+-12 -2 -3 -6 13 15
+-11 -1 -2 -5 15 17
+-10 0 -1 -4 17 19
+-9 +1 0 -3 19 21
+-8 +2 +1 -2 21 23
+-7 +3 +2 -1 23 25
+test.ppm
+-21 -9 -11 -1 227 149
+-20 -8 -10 0 229 151
+-19 -7 -9 +1 231 153
+-18 -6 -8 +2 233 155
+-17 -5 -7 +3 235 157
+-16 -4 -6 +4 237 159
+Test 3
+13 15
+P2
+13 15
+255
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+13 15
+0 0 0 0 13 15
+13 15
+P1
+13 15
+1111111111111
+1110101010101
+1111111111111
+1110101010101
+1111111111111
+1110101010101
+1111111111111
+1110101010101
+1111111111111
+1110101010101
+1111111111111
+1110101010101
+1111111111111
+1110101010101
+1111111111111
+-3 -1 -1 -1 9 13
+544280424 101484
+Expected failure 1 1
+Expected failure 2 1
diff --git a/test/pnmcrop3.test b/test/pnmcrop3.test
new file mode 100755
index 00000000..1e8da345
--- /dev/null
+++ b/test/pnmcrop3.test
@@ -0,0 +1,80 @@
+#! /bin/sh
+# This script tests: pnmcrop
+# Also requires: pnmpad pamfile pgmmake
+
+tmpdir=${tmpdir:-/tmp}
+
+test_pbm=${tmpdir}/test.pbm
+test_ppm=${tmpdir}/test.ppm
+border_pbm=${tmpdir}/border.pbm
+border_ppm=${tmpdir}/border.ppm
+gray_pgm=${tmpdir}/gray.pgm
+
+pnmpad -top=3 -bottom=5 -left=11 -right=2 testgrid.pbm > ${test_pbm}
+pnmpad -top=11 -bottom=1 -left=21 -right=9 testimg.ppm > ${test_ppm}
+
+pnmpad -top=4 -bottom=4 -left=8 -right=5 testgrid.pbm > ${border_pbm}
+pnmpad -top=7 -bottom=5 -left=30 -right=0 testimg.ppm > ${border_ppm}
+
+pgmmake 0.5 $(pamfile -size ${test_pbm}) > ${gray_pgm}
+
+# Test 1
+echo Test 1
+
+for input_file in ${test_pbm} ${test_ppm}
+  do
+  echo `basename ${input_file}`
+  for option in "-left" "-right" "-top" "-bottom" \
+            "-left -right" "-left -bottom" "-right -bottom"
+    do
+    echo ${option}
+    pnmcrop -reportsize ${option} ${input_file} || echo fail1
+    done
+  done
+
+# Test 2
+echo Test 2
+
+for input_file in ${test_pbm} ${test_ppm}
+  do
+  echo `basename ${input_file}`
+  for margin in 0 1 2 3 4 5  # for margin in `seq 0 5`
+    do
+    pnmcrop -reportsize -margin=${margin} ${input_file} || echo fail2
+    done
+  done
+
+# Test 3
+echo Test 3
+
+pnmcrop -borderfile=${border_pbm} ${gray_pgm} | pamfile -size
+pnmcrop -borderfile=${border_pbm} ${gray_pgm} -plain 
+
+pnmcrop -borderfile=${test_pbm} ${test_pbm}   | pamfile -size
+pnmcrop -borderfile=${test_pbm} ${test_pbm}   | pnmcrop -black -reportsize
+
+pnmcrop -borderfile=${border_pbm} ${test_pbm} | pamfile -size
+pnmcrop -borderfile=${border_pbm} ${test_pbm} -plain
+pnmcrop -borderfile=${border_pbm} ${test_pbm} | pnmcrop -black -reportsize
+
+pnmcrop -borderfile=${border_ppm} ${test_ppm} | cksum 
+
+test_out=${tmpdir}/test_out
+
+# The following two cases are expected to fail
+
+echo "Border file size mismatch" 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "--------------------------------------------" 1>&2
+
+pnmcrop -borderfile=${border_ppm} ${test_pbm} > ${test_out} || \
+        printf "Expected failure 1";
+        test -s ${test_out}; echo " "$?
+        rm ${test_out}
+
+pnmcrop -borderfile=${border_pbm} ${test_ppm} > ${test_out} || \
+        printf "Expected failure 2";
+        test -s ${test_out}; echo " "$?
+        rm ${test_out}
+
+rm ${test_pbm} ${test_ppm} ${border_pbm} ${border_ppm} ${gray_pgm}
diff --git a/test/pnminvert-roundtrip.ok b/test/pnminvert-roundtrip.ok
index 67f7a1fe..ace97410 100644
--- a/test/pnminvert-roundtrip.ok
+++ b/test/pnminvert-roundtrip.ok
@@ -1,2 +1,2 @@
 1926073387 101484
-2425386270 41
+281226646 481
diff --git a/test/pnminvert-roundtrip.test b/test/pnminvert-roundtrip.test
index 52d15039..c0f702c2 100755
--- a/test/pnminvert-roundtrip.test
+++ b/test/pnminvert-roundtrip.test
@@ -1,7 +1,7 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pnminvert
 # Also requires:
 
 
 pnminvert testimg.ppm | pnminvert | cksum
-pnminvert testgrid.pbm | pnminvert | cksum
+pnminvert maze.pbm | pnminvert | cksum
diff --git a/test/pnminvert.ok b/test/pnminvert.ok
index 6cf5f011..d35b30b9 100644
--- a/test/pnminvert.ok
+++ b/test/pnminvert.ok
@@ -1,7 +1,12 @@
-1240379484 41
+Test 1.  Should print 1739442872 481
+1739442872 481
+Test 2.  Should print 1416115901 101484
 1416115901 101484
+Test 3.  Should print 1174803406 33838
 1174803406 33838
+Test 4.  Should print 2595564405 14 three times
 2595564405 14
 2595564405 14
 2595564405 14
+Test 7.  Should print 2896726098 15
 2896726098 15
diff --git a/test/pnminvert.test b/test/pnminvert.test
index b80716ef..d2789bdf 100755
--- a/test/pnminvert.test
+++ b/test/pnminvert.test
@@ -1,26 +1,21 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pnminvert
 # Also requires: pbmmake pamchannel pamtopnm
 
+echo "Test 1.  Should print 1739442872 481"
+pnminvert maze.pbm | cksum
 
-# Test 1.  Should print 1240379484 41
-pnminvert testgrid.pbm | cksum
-
-# Test 2.  Should print 1416115901 101484
+echo "Test 2.  Should print 1416115901 101484"
 pnminvert testimg.ppm | cksum
 
-# Test 3.  Should print 1174803406 33838
+echo "Test 3.  Should print 1174803406 33838"
 pamchannel -infile=testimg.ppm -tupletype="GRAYSCALE" 0 | pamtopnm | \
   pnminvert | cksum
 
-# Test 4.  Should print 2595564405 14
+echo "Test 4.  Should print 2595564405 14 three times"
 pbmmake -w 7 7 | pnminvert | cksum
-
-# Test 5.  Should print 2595564405 14
 pbmmake -b 7 7 | cksum
-
-# Test 6.  Should print 2595564405 14
 pbmmake -b 7 7 | pnminvert | pnminvert | cksum
 
-# Test 7.  Should print 2896726098 15
+echo "Test 7.  Should print 2896726098 15"
 pbmmake -g 8 8 | pnminvert | cksum
diff --git a/test/pnmpad-reportonly.ok b/test/pnmpad-reportonly.ok
new file mode 100644
index 00000000..e7d0a0d1
--- /dev/null
+++ b/test/pnmpad-reportonly.ok
@@ -0,0 +1,67 @@
+Test 1.  Should print 0 0 0 0 227 149 six times
+0 0 0 0 227 149
+0 0 0 0 227 149
+0 0 0 0 227 149
+0 0 0 0 227 149
+0 0 0 0 227 149
+0 0 0 0 227 149
+Test 2.  Should print 10 0 0 0 110 17 seven times
+10 0 0 0 110 17
+10 0 0 0 110 17
+10 0 0 0 110 17
+10 0 0 0 110 17
+10 0 0 0 110 17
+10 0 0 0 110 17
+10 0 0 0 110 17
+Test 3.  Should print 0 10 0 0 110 19 eight times
+0 10 0 0 110 19
+0 10 0 0 110 19
+0 10 0 0 110 19
+0 10 0 0 110 19
+0 10 0 0 110 19
+0 10 0 0 110 19
+0 10 0 0 110 19
+0 10 0 0 110 19
+Test 4.  Should print 10 10 0 0 120 19 four times
+10 10 0 0 120 19
+10 10 0 0 120 19
+10 10 0 0 120 19
+10 10 0 0 120 19
+Test 5.  Should print 0 0 10 0 27 110 seven times
+0 0 10 0 27 110
+0 0 10 0 27 110
+0 0 10 0 27 110
+0 0 10 0 27 110
+0 0 10 0 27 110
+0 0 10 0 27 110
+0 0 10 0 27 110
+Test 6.  Should print 0 0 0 10 19 110 eight times
+0 0 0 10 19 110
+0 0 0 10 19 110
+0 0 0 10 19 110
+0 0 0 10 19 110
+0 0 0 10 19 110
+0 0 0 10 19 110
+0 0 0 10 19 110
+0 0 0 10 19 110
+Test 7.  Should print 0 0 12 12 27 124 four times
+0 0 12 12 27 124
+0 0 12 12 27 124
+0 0 12 12 27 124
+0 0 12 12 27 124
+Test 8.  Should print 5 10 0 0 115 17 seven times
+5 10 0 0 115 17
+5 10 0 0 115 17
+5 10 0 0 115 17
+5 10 0 0 115 17
+5 10 0 0 115 17
+5 10 0 0 115 17
+5 10 0 0 115 17
+Test 9.  Should print 0 0 4 8 19 112 seven times
+0 0 4 8 19 112
+0 0 4 8 19 112
+0 0 4 8 19 112
+0 0 4 8 19 112
+0 0 4 8 19 112
+0 0 4 8 19 112
+0 0 4 8 19 112
diff --git a/test/pnmpad-reportonly.test b/test/pnmpad-reportonly.test
new file mode 100755
index 00000000..ccd79e69
--- /dev/null
+++ b/test/pnmpad-reportonly.test
@@ -0,0 +1,129 @@
+#! /bin/sh
+# This script tests: pnmpad
+# Also requires: pbmmake pgmmake ppmmake pamfile
+
+tmpdir=${tmpdir:-/tmp}
+
+test1_pbm=${tmpdir}/test1.pbm
+test2_pbm=${tmpdir}/test2.pbm
+test_pgm=${tmpdir}/test.pgm
+test_ppm=${tmpdir}/test.ppm
+
+testimg_size=$(pamfile -size testimg.ppm) 
+
+echo "Test 1.  Should print 0 0 0 0 ${testimg_size} six times" 
+
+for pad in "" "-left=0" "-right=0" "-top=0" "-bottom=0" \
+           "-left=0 -right=0 -top=0 -bottom=0"
+  do
+  pnmpad -reportonly ${pad} testimg.ppm || echo "failure"
+  done
+
+
+echo "Test 2.  Should print 10 0 0 0 110 17 seven times" 
+ 
+pbmmake -w 100 17 > ${test1_pbm}
+for pad in "-left=10" \
+           "-left=10 -right=0" \
+           "-left=10 -width=90" \
+           "-left=10 -width=105" \
+           "-left=10 -width=110" \
+           "-right=0 -width=110" \
+           "-halign=1.0 -width=110"
+  do
+  pnmpad -reportonly ${pad} ${test1_pbm} || echo "failure"
+  done
+
+
+echo "Test 3.  Should print 0 10 0 0 110 19 eight times" 
+pgmmake 0.5 100 19 > ${test_pgm}
+for pad in "-right=10" \
+           "-right=10 -left=0" \
+           "-right=10 -width=90" \
+           "-right=10 -width=105" \
+           "-right=10 -width=110" \
+           "-left=0 -width=110" \
+           "-halign=0.0 -width=110" \
+           "-right=1 -mwidth=11"
+  do
+  pnmpad -reportonly ${pad} ${test_pgm} || echo "failure"
+  done
+
+
+echo "Test 4.  Should print 10 10 0 0 120 19 four times" 
+for pad in "-left=10 -right=10" \
+           "-right=10 -width=120" \
+           "-halign=0.5 -width=120" \
+           "-left=1 -right=1 -mwidth=30"
+  do
+  pnmpad -reportonly ${pad} ${test_pgm} || echo "failure"
+  done
+
+
+echo "Test 5.  Should print 0 0 10 0 27 110 seven times" 
+ 
+pbmmake -w 27 100 > ${test2_pbm}
+for pad in "-top=10" \
+           "-top=10 -bottom=0" \
+           "-top=10 -height=50" \
+           "-top=10 -height=101" \
+           "-top=10 -height=110" \
+           "-bottom=0 -height=110" \
+           "-valign=1.0 -height=110"
+  do
+  pnmpad -reportonly ${pad} ${test2_pbm} || echo "failure"
+  done
+
+
+echo "Test 6.  Should print 0 0 0 10 19 110 eight times" 
+ppmmake rgb:33/44/55 19 100 > ${test_ppm}
+for pad in "-bottom=10" \
+           "-bottom=10 -top=0" \
+           "-bottom=10 -height=10" \
+           "-bottom=10 -height=107" \
+           "-bottom=10 -height=110" \
+           "-top=0 -height=110" \
+           "-valign=0.0 -height=110" \
+           "-bottom=1 -mheight=10"
+  do
+  pnmpad -reportonly ${pad} ${test_ppm} || echo "failure"
+  done
+
+
+echo "Test 7.  Should print 0 0 12 12 27 124 four times" 
+for pad in "-top=12 -bottom=12" \
+           "-top=12 -height=124" \
+           "-valign=0.5 -height=124" \
+           "-top=11 -bottom=11 -mheight=4"
+  do
+  pnmpad -reportonly ${pad} ${test2_pbm} || echo "failure"
+  done
+
+
+echo "Test 8.  Should print 5 10 0 0 115 17 seven times"
+for pad in "-l 5 -r 10 -w 115" \
+           "-l 5       -w 115" \
+           "     -r 10 -w 115" \
+           "-l 5 -r 10       " \
+           "-halign 0.333 -w 115 " \
+           "-l 2 -r 4 -mw 23" \
+           "-halign 0.333 -mw 23"
+  do
+  pnmpad -reportonly ${pad} ${test1_pbm} || echo "failure"
+  done
+
+
+echo "Test 9.  Should print 0 0 4 8 19 112 seven times"
+for pad in "-t 4 -b 8 -h 112" \
+           "-t 4      -h 112" \
+           "     -b 8 -h 112" \
+           "-t 4 -b 8       " \
+           "-t 4 -b 8 -mh 14" \
+           "-valign 0.333 -mh 14" \
+           "-valign 0.333 -h 112"
+  do
+  pnmpad -reportonly ${pad} ${test_ppm} || echo "failure"
+  done
+
+
+rm ${test1_pbm} ${test2_pbm} ${test_pgm} ${test_ppm}
diff --git a/test/pnmpaste-pbm.test b/test/pnmpaste-pbm.test
index b75797af..70f2b266 100755
--- a/test/pnmpaste-pbm.test
+++ b/test/pnmpaste-pbm.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pnmpaste
 # Also requires: pbmmake
 
diff --git a/test/pnmpsnr.ok b/test/pnmpsnr.ok
index 3469f836..7042f86c 100644
--- a/test/pnmpsnr.ok
+++ b/test/pnmpsnr.ok
@@ -1,7 +1,14 @@
+Test 1
 0.00
 inf
 1000.00
 match
+Test 2
 300.00 300.00 300.00
 match
 match
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
diff --git a/test/pnmpsnr.test b/test/pnmpsnr.test
index f24c08aa..ae6ba3cc 100755
--- a/test/pnmpsnr.test
+++ b/test/pnmpsnr.test
@@ -1,23 +1,58 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pnmpsnr
 # Also requires: pbmmake
 
 
 tmpdir=${tmpdir:-/tmp}
 
-
 w_pbm=${tmpdir}/w.pbm
 b_pbm=${tmpdir}/b.pbm
 
 pbmmake -w 10 10 > ${w_pbm}
 pbmmake -b 10 10 > ${b_pbm}
 
+echo "Test 1"
+
 pnmpsnr  ${w_pbm}  ${b_pbm} -machine
 pnmpsnr  ${w_pbm}  ${w_pbm} -machine
 pnmpsnr  ${w_pbm}  ${w_pbm} -machine -max=1000
 pnmpsnr  ${w_pbm}  ${w_pbm} -target=1000
+
+echo "Test 2"
+
 pnmpsnr  testimg.ppm  testimg.ppm -machine -max=300
 pnmpsnr  testimg.ppm  testimg.ppm -target=1000
 pnmpsnr  testimg.ppm  testimg.ppm -target1=1000 -target2=1000 -target3=1000
 
+
+echo "Test Invalid"
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pnmpsnr ${b_pbm} ${w_pbm} ${b_pbm}     > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmpsnr ${b_pbm}                       > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmpsnr ${b_pbm} ${w_pbm} -target1=100 > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmpsnr                   -machine     > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
 rm ${b_pbm} ${w_pbm}
diff --git a/test/pnmquant.ok b/test/pnmquant.ok
new file mode 100644
index 00000000..407d42a3
--- /dev/null
+++ b/test/pnmquant.ok
@@ -0,0 +1,18 @@
+Test 1
+1 1
+1 1
+1 1
+1 1
+1 1
+1 1
+1 1
+1 1
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
+Expected failure 7 1
+Expected failure 8 1
diff --git a/test/pnmquant.test b/test/pnmquant.test
new file mode 100755
index 00000000..cbe69f5c
--- /dev/null
+++ b/test/pnmquant.test
@@ -0,0 +1,82 @@
+#! /bin/sh
+# This script tests: pnmquant
+# Also requires: ppmhist
+
+echo "Test 1"
+
+# Count colors in output image.
+
+pnmquant 256 testimg.ppm | ppmhist | \
+  awk 'NR==1 {print ($2 <= 256) , ($2 > 256 * 0.95)}'
+
+pnmquant -center 256 testimg.ppm | ppmhist | \
+  awk 'NR==1 {print ($2 <= 256) , ($2 > 256 * 0.95)}'
+
+pnmquant -spreadbrightness 256 testimg.ppm | ppmhist | \
+  awk 'NR==1 {print ($2 <= 256) , ($2 > 256 * 0.95)}'
+
+pnmquant -spreadluminosity 128 testimg.ppm | ppmhist | \
+  awk 'NR==1 {print ($2 <= 128) , ($2 > 128 * 0.95)}'
+
+pnmquant -floyd -randomseed=0 128 testimg.ppm | ppmhist | \
+  awk 'NR==1 {print ($2 <= 128) , ($2 > 128 * 0.95)}'
+
+pnmquant 64 -meanpixel testimg.ppm | ppmhist | \
+  awk 'NR==1 {print ($2 <= 64) , ($2 > 64 * 0.9)}'
+
+pnmquant 16 -meancolor testimg.ppm | ppmhist | \
+  awk 'NR==1 {print ($2 <= 16) , ($2 > 16 * 0.9)}'
+
+
+pnmquant 2 testgrid.pbm | ppmhist | \
+  awk 'NR==1 {print ($2 <= 2) , ($2 == 2) }'
+
+echo "Test Invalid"
+
+echo 1>&2
+echo "Invalid command-line arguments." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+pnmquant 0 testimg.ppm   > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmquant testimg.ppm  > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmquant 10.5 testimg.ppm > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmquant -center -meancolor 16 testimg.ppm > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmquant -center -meanpixel 16 testimg.ppm    > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmquant -meancolor -meanpixel 16 testimg.ppm > ${test_out} || \
+  printf "Expected failure 6"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmquant -spreadbrightness -spreadluminosity 16 testimg.ppm > ${test_out} || \
+  printf "Expected failure 7"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmquant -randomseed 1 -norandom 10 testimg.ppm > ${test_out} || \
+  printf "Expected failure 8"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pnmquantall.ok b/test/pnmquantall.ok
index 172eb0aa..5885d370 100644
--- a/test/pnmquantall.ok
+++ b/test/pnmquantall.ok
@@ -1,5 +1,9 @@
-got color map
 2373957371 33838
 3892560659 33838
 1383839923 33838
 1
+Expected failure 1
+Expected failure 1.rm
+Expected failure 2
+Expected failure 2.rm
+Expected failure 3
diff --git a/test/pnmquantall.test b/test/pnmquantall.test
index cd01bb8d..f047e856 100755
--- a/test/pnmquantall.test
+++ b/test/pnmquantall.test
@@ -1,27 +1,47 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pnmquantall
-# Also requires: ppmtorgb3 pgmhist
+# Also requires: ppmtorgb3 pgmhist pamcat
 
 tmpdir=${tmpdir:-/tmp}
-test_ppm=${tmpdir}/testimg.ppm
+rose_ppm=${tmpdir}/rose.ppm
 
-cp testimg.ppm ${tmpdir} &&
-ppmtorgb3 ${test_ppm}
+cp testimg.ppm ${rose_ppm} &&
+ppmtorgb3 ${rose_ppm}
 
-test_red=${tmpdir}/testimg.red
-test_grn=${tmpdir}/testimg.grn
-test_blu=${tmpdir}/testimg.blu
+rose_red=${tmpdir}/rose.red
+rose_grn=${tmpdir}/rose.grn
+rose_blu=${tmpdir}/rose.blu
 
-pnmquantall 20 ${test_red} ${test_grn} ${test_blu}
+pnmquantall 20 ${rose_red} ${rose_grn} ${rose_blu}
 
-for i in ${test_red} ${test_grn} ${test_blu}
+for i in ${rose_red} ${rose_grn} ${rose_blu}
 do
 cat $i | cksum
 done
 
 # Should print 1
 
-pnmcat ${test_red} ${test_grn} ${test_blu} -tb | \
+pamcat ${rose_red} ${rose_grn} ${rose_blu} -tb | \
     pgmhist -m | awk '$2>0 {s++}; END { print (s<=20) }'
 
-rm ${test_red} ${test_grn} ${test_blu} ${test_ppm}
\ No newline at end of file
+
+tmpdir=${tmpdir:-/tmp}
+rose_out=${tmpdir}/rose_out
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pnmquantall -ext xx 0 ${rose_red} ${rose_grn} ${rose_blu} || \
+   echo "Expected failure 1"
+rm ${rose_red}xx ${rose_grn}xx ${rose_blu}xx || \
+   echo "Expected failure 1.rm"
+pnmquantall -ext xx 1 ${rose_red} ${rose_grn} ${rose_blu} || \
+   echo "Expected failure 2"
+rm ${rose_red}xx ${rose_grn}xx ${rose_blu}xx || \
+   echo "Expected failure 2.rm"
+pnmquantall -ext xx 2 || \
+   echo "Expected failure 3"
+
+rm ${rose_red} ${rose_grn} ${rose_blu} ${rose_ppm}
diff --git a/test/pnmremap1.ok b/test/pnmremap1.ok
index 07954684..23a9dddd 100644
--- a/test/pnmremap1.ok
+++ b/test/pnmremap1.ok
@@ -1 +1,7 @@
 3602410851 101482
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
diff --git a/test/pnmremap1.test b/test/pnmremap1.test
index d7c5189c..8626c50f 100755
--- a/test/pnmremap1.test
+++ b/test/pnmremap1.test
@@ -1,8 +1,7 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pnmremap
 # Also requires: pamseq pamtopnm
 
-
 tmpdir=${tmpdir:-/tmp}
 palette=${tmpdir}/palette
 #palette255=${tmpdir}/palette255
@@ -24,3 +23,42 @@ pnmremap -mapfile=${palette} -floyd -norandom \
 # testimg.ppm | cksum
 
 rm ${palette} # ${palette255}
+
+echo 1>&2
+echo "Invalid command-line arguments." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+pnmremap -mapfile=/dev/null testimg.ppm > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmremap -mapfile=/dev/zero testimg.ppm > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmremap testimg.ppm                    > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmremap -fs -nofs testimg.ppm          > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmremap -mapfile=testgrid.pbm -missingcolor=rgb:00/ff/00 testimg.ppm \
+ > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmremap -mapfile=testgrid.pbm -firstisdefault testimg.ppm > ${test_out} || \
+  printf "Expected failure 6"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pnmremap2.test b/test/pnmremap2.test
index 76c2d566..7eea2c4a 100755
--- a/test/pnmremap2.test
+++ b/test/pnmremap2.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pnmremap
 # Also requires: pamdepth pamseq pamtopnm
 
diff --git a/test/pnmshear.test b/test/pnmshear.test
index a19a9852..42e5c816 100755
--- a/test/pnmshear.test
+++ b/test/pnmshear.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pnmshear
 # Also requires: pbmmake pnmpad
 
diff --git a/test/pnmtile.ok b/test/pnmtile.ok
index 4a29e0dc..d28fafa3 100644
--- a/test/pnmtile.ok
+++ b/test/pnmtile.ok
@@ -1,2 +1,6 @@
 4228632379 259
-0 0 : 0
+0 0 0 : 0
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
diff --git a/test/pnmtile.test b/test/pnmtile.test
index e297da66..b72ef946 100755
--- a/test/pnmtile.test
+++ b/test/pnmtile.test
@@ -1,6 +1,6 @@
 #! /bin/bash
 # This script tests: pnmtile
-# Also requires: pnmcat
+# Also requires: pamcat
 
 
 # Test 1.  Should print 4228632379 259
@@ -8,15 +8,42 @@ pnmtile 40 50 testgrid.pbm | cksum
 
 tmpdir=${tmpdir:-/tmp}
 
-# Test 2.  Compare 2x2 tile images produced by pnmtile and pnmcat
+# Test 2.  Compare 2x2 tile images produced by pnmtile and pamcat
 # Should print 0
 testimg2_ppm=${tmpdir}/testimg2.ppm
 testimg4_ppm=${tmpdir}/testimg4.ppm
 
 pnmtile 454 298 testimg.ppm > ${testimg4_ppm} &&
-pnmcat -lr testimg.ppm testimg.ppm > ${testimg2_ppm} &&
-pnmcat -tb ${testimg2_ppm} ${testimg2_ppm} | \
+pamcat -lr testimg.ppm testimg.ppm > ${testimg2_ppm} &&
+pamcat -tb ${testimg2_ppm} ${testimg2_ppm} | pamtopnm --assume |\
 cmp -s - ${testimg4_ppm}
 echo ${PIPESTATUS[@]} ":" $?
 
 rm ${testimg2_ppm} ${testimg4_ppm}
+
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pnmtile 100 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmtile 100 0 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmtile 0 100 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+pnmtile 100 100 100 testgrid.pbm > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/pnmtopnm-plain.ok b/test/pnmtopnm-plain.ok
index 02d99f1e..640f0964 100644
--- a/test/pnmtopnm-plain.ok
+++ b/test/pnmtopnm-plain.ok
@@ -1,48 +1,51 @@
+Test.  Should print three identical images in plain format, twice each
 P1
-14 16
-10101010101010
-11111111111111
-10101010101010
-11111111111111
-10101010101010
-11111111111111
-10101010101010
-11111111111111
-10101010101010
-11111111111111
-10101010101010
-11111111111111
-10101010101010
-11111111111111
-10101010101010
-11111111111111
+5 5
+01010
+10101
+01010
+10101
+01010
+P1
+5 5
+01010
+10101
+01010
+10101
+01010
+P2
+8 8
+7
+0 0 1 1 2 2 3 3
+0 1 1 2 2 3 3 4
+1 1 2 2 3 3 4 4
+1 2 2 3 3 4 4 5
+2 2 3 3 4 4 5 5
+2 3 3 4 4 5 5 6
+3 3 4 4 5 5 6 6
+3 4 4 5 5 6 6 7
 P2
-14 16
+8 8
+7
+0 0 1 1 2 2 3 3 
+0 1 1 2 2 3 3 4 
+1 1 2 2 3 3 4 4 
+1 2 2 3 3 4 4 5 
+2 2 3 3 4 4 5 5 
+2 3 3 4 4 5 5 6 
+3 3 4 4 5 5 6 6 
+3 4 4 5 5 6 6 7 
+P3
+4 4
 255
-0 255 0 255 0 255 0 255 0 255 0 255 0 255 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 255 0 255 0 255 0 255 0 255 0 255 0 255 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 255 0 255 0 255 0 255 0 255 0 255 0 255 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 255 0 255 0 255 0 255 0 255 0 255 0 255 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 255 0 255 0 255 0 255 0 255 0 255 0 255 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 255 0 255 0 255 0 255 0 255 0 255 0 255 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 255 0 255 0 255 0 255 0 255 0 255 0 255 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 255 0 255 0 255 0 255 0 255 0 255 0 255 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+0 31 255  0 31 255  63 0 0  0 31 255
+0 31 255  0 31 255  0 31 255  63 0 0
+0 31 255  63 0 0  63 0 0  63 0 0
+63 0 0  0 31 255  63 0 0  63 0 0
 P3
-14 16
+4 4
 255
-0 0 0 255 255 255 0 0 0 255 255 255 0 0 0 255 255 255 0 0 0 255 255 255 
-0 0 0 255 255 255 0 0 0 255 255 255 0 0 0 255 255 255 
-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 255 255 255 0 0 0 255 255 255 0 0 0 255 255 255 0 0 0 255 255 255 
-0 0 0 255 255 255 0 0 0 255 255 255 0 0 0 255 255 255 
-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 31 255 0 31 255 63 0 0 0 31 255 
+0 31 255 0 31 255 0 31 255 63 0 0 
+0 31 255 63 0 0 63 0 0 63 0 0 
+63 0 0 0 31 255 63 0 0 63 0 0 
diff --git a/test/pnmtopnm-plain.test b/test/pnmtopnm-plain.test
index 5b7e4b48..87b74064 100755
--- a/test/pnmtopnm-plain.test
+++ b/test/pnmtopnm-plain.test
@@ -1,10 +1,14 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamtopnm
-# Also requires: pgmtopgm ppmtoppm
+# Also requires: pbmmake pgmramp ppmpat
 
-pamtopnm -plain testgrid.pbm
+echo "Test.  Should print three identical images in plain format, twice each"
 
-pgmtopgm < testgrid.pbm | pamtopnm -plain
+pbmmake -g 5 5 -plain
+pbmmake -g 5 5 | pamtopnm -plain
 
-ppmtoppm < testgrid.pbm | pamtopnm -plain | \
-  head -n11
+pgmramp -maxval 7 -diag 8 8 -plain
+pgmramp -maxval 7 -diag 8 8 | pamtopnm -plain
+
+ppmpat -g2 -color=rgb:00/1f/ff,rgb:3f/00/00 -mesh 4 4 -plain
+ppmpat -g2 -color=rgb:00/1f/ff,rgb:3f/00/00 -mesh 4 4 | pamtopnm -plain
diff --git a/test/ppmbrighten.ok b/test/ppmbrighten.ok
index 376e71d3..3895dbd0 100644
--- a/test/ppmbrighten.ok
+++ b/test/ppmbrighten.ok
@@ -1,3 +1,11 @@
+Test 1: Should print 1969633344 101484
 1969633344 101484
-3688219243 101484
+Test 2: Should print 295150171 101484
 295150171 101484
+Test 3: Should print 1
+1
+Test Error: Should print 1 four times
+1
+1
+1
+1
diff --git a/test/ppmbrighten.test b/test/ppmbrighten.test
index 46c5cab5..e346d1d0 100755
--- a/test/ppmbrighten.test
+++ b/test/ppmbrighten.test
@@ -1,12 +1,41 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmbrighten
-# Also requires:
+# Also requires: pnmnorm pambrighten pamsumm 
 
 # Failure message
 ## Ppmbrighten is sensitive to subtle differences in floating point math.
 ## If this test fails, please run the program and visually examine
 ## the output.
 
+echo "Test 1: Should print 1969633344 101484"
+
 ppmbrighten -v 100 testimg.ppm | cksum
-ppmbrighten -v 100 -normalize testimg.ppm | cksum
+
+echo "Test 2: Should print 295150171 101484"
+
 ppmbrighten -s 100 -v -50 testimg.ppm | cksum
+
+echo "Test 3: Should print 1"
+
+ppmbrighten -v 100 -normalize testimg.ppm | pamsumm --mean | \
+ awk '{print ($NF > 132.0) && ($NF < 132.2)}'
+
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+echo "Test Error: Should print 1 four times"
+
+tmpdir=${tmpdir:-/tmp}
+output_ppm=${tmpdir}/output.ppm
+
+pambrighten -v -120 testimg.ppm > ${output_ppm}
+echo $?
+test -s ${output_ppm}
+echo $?
+pambrighten -s -120 testimg.ppm > ${output_ppm}
+echo $?
+test -s ${output_ppm}
+echo $?
+
+rm ${output_ppm}
diff --git a/test/ppmchange-roundtrip.ok b/test/ppmchange-roundtrip.ok
index a676a1f2..4fb7d428 100644
--- a/test/ppmchange-roundtrip.ok
+++ b/test/ppmchange-roundtrip.ok
@@ -1,2 +1,2 @@
-2425386270 41
-2425386270 41
+281226646 481
+281226646 481
diff --git a/test/ppmchange-roundtrip.test b/test/ppmchange-roundtrip.test
index 78f5b548..5bd18150 100755
--- a/test/ppmchange-roundtrip.test
+++ b/test/ppmchange-roundtrip.test
@@ -1,12 +1,12 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmchange
 # Also requires: pgmtopbm pnminvert ppmtopgm
 
 
-ppmchange black white white black testgrid.pbm | \
+ppmchange black white white black maze.pbm | \
 pnminvert | ppmtopgm | \
 pgmtopbm -th -val=0.5 | cksum
 
-ppmchange  black white white black testgrid.pbm | \
+ppmchange  black white white black maze.pbm | \
 ppmchange  black white white black | \
 ppmtopgm | pgmtopbm -th -val=0.5 | cksum
diff --git a/test/ppmchange.test b/test/ppmchange.test
index a749a5d2..a579631b 100755
--- a/test/ppmchange.test
+++ b/test/ppmchange.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmchange
 # Also requires: ppmrainbow pgmramp ppmhist
 
diff --git a/test/ppmcie.test b/test/ppmcie.test
index 0ce69dea..dd7f121f 100755
--- a/test/ppmcie.test
+++ b/test/ppmcie.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmcie
 # Also requires: pamsumm pamsharpness
 
diff --git a/test/ppmdfont.test b/test/ppmdfont.test
index 7d894789..e6b461f1 100755
--- a/test/ppmdfont.test
+++ b/test/ppmdfont.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmdmkfont ppmddumpfont ppmdcfont
 # Also requires:
 
diff --git a/test/ppmdim.test b/test/ppmdim.test
index 848e2e9f..48d9e891 100755
--- a/test/ppmdim.test
+++ b/test/ppmdim.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmdim
 # Also requires: pamfunc pamarith pamsumm
 
diff --git a/test/ppmdither.test b/test/ppmdither.test
index 7e32ef59..f82c34ff 100755
--- a/test/ppmdither.test
+++ b/test/ppmdither.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmdither
 # Also requires:
 
diff --git a/test/ppmforge-parameters.ok b/test/ppmforge-parameters.ok
new file mode 100644
index 00000000..c8edc5dd
--- /dev/null
+++ b/test/ppmforge-parameters.ok
@@ -0,0 +1,14 @@
+Test 1: Should print 256 256
+256 256
+Test 2: Should print 40 30
+40 30
+Test 3: Should print 90 90
+90 90
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
+Expected failure 7 1
diff --git a/test/ppmforge-parameters.test b/test/ppmforge-parameters.test
new file mode 100755
index 00000000..e5822673
--- /dev/null
+++ b/test/ppmforge-parameters.test
@@ -0,0 +1,65 @@
+#! /bin/sh
+# This script tests: ppmforge
+# Also requires: pamfile
+
+echo "Test 1: Should print 256 256"
+
+# Default size is 256 256
+ppmforge -night | pamfile -size
+
+echo "Test 2: Should print 40 30"
+
+# Width is adjusted if not even
+# becomes 40 in this case
+ppmforge -night -width=39 -height=30 | pamfile -size
+
+echo "Test 3: Should print 90 90"
+
+# Width is adjusted if smaller than height
+# brought up to 90 in this case
+ppmforge -night -width=80 -height=90 | pamfile -size
+
+echo "Test Invalid"
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line arguments." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+ppmforge -night  -dimension=0  > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmforge  -dimension=10  > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmforge  -dimension=-1  > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmforge -clouds -mesh=1.99    > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmforge -clouds -power=0      > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmforge         -ice=-1       > ${test_out} || \
+  printf "Expected failure 6"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmforge         -glaciers=-1  > ${test_out} || \
+  printf "Expected failure 7"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/ppmforge.ok b/test/ppmforge.ok
new file mode 100644
index 00000000..2f3f9501
--- /dev/null
+++ b/test/ppmforge.ok
@@ -0,0 +1,10 @@
+Test 1. Should print: 547829788 196623  (Mersenne Twister)
+547829788 196623
+Test 2.
+match
+Test 3.
+match
+Test 4.
+match
+Test 5.
+match
diff --git a/test/ppmforge.rand-ok b/test/ppmforge.rand-ok
deleted file mode 100644
index c8b3ac9f..00000000
--- a/test/ppmforge.rand-ok
+++ /dev/null
@@ -1,3 +0,0 @@
-000|0
-081|3634219838 196623
-082|3262664440 196623
diff --git a/test/ppmforge.test b/test/ppmforge.test
index 3ebea88c..75de7cf7 100755
--- a/test/ppmforge.test
+++ b/test/ppmforge.test
@@ -1,9 +1,52 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmforge
-# Also requires:
+# Also requires: pnmpsnr
 
-# Use small x y values to avoid floating point issues.
-
-# Should print: 3634219838 196623 (Glibc)
-#               3262664440 196623 (MAC OS)
+echo "Test 1. Should print: 547829788 196623  (Mersenne Twister)" 
+#               3634219838 196623 (Glibc rand() )
+#               3262664440 196623 (MAC OS rand() )
 ppmforge -night -seed 1 | cksum
+
+tmpdir=${tmpdir:-/tmp}
+test_ppm=${tmpdir}/test.ppm
+
+
+# Target values for following tests were determined by running the
+# ppmforge command pairs 30 times with different seeds, finding
+# the minimum (or "poorest match") for each component and 
+# subtracting 0.01 dB.   As such these are weak tests.
+
+
+echo "Test 2."
+ppmforge -cloud -seed 1 -power 0.75 > ${test_ppm}
+ppmforge -cloud -seed 1 -power 0.74 | \
+  pnmpsnr -rgb -target1=41.15 -target2=41.15 -target3=999 - ${test_ppm}
+
+rm ${test_ppm}
+
+echo "Test 3."
+ppmforge -cloud -seed 1 -dimension 2.15 > ${test_ppm}
+ppmforge -cloud -seed 1 -dimension 2.175 | \
+  pnmpsnr -rgb -target1=43.39 -target2=43.39 -target3=999 - ${test_ppm}
+
+  # Note that there should be no difference for the target3: blue.
+
+
+
+rm ${test_ppm}
+
+echo "Test 4."
+ppmforge -seed 1 -stars 0 -ice 0.01 -power 1.18 -hour 10 >  ${test_ppm}
+ppmforge -seed 1 -stars 0 -ice 0.01 -power 1.22 -hour 10 | \
+  pnmpsnr -target1=27.89 -target2=24.25 -target3=37.87 - ${test_ppm}
+
+rm ${test_ppm}
+
+echo "Test 5."
+ppmforge -seed 1 -stars 0 -ice 0.01 \
+    -inclination 9  -hour 12 -power 200 > ${test_ppm} 
+ppmforge -seed 1 -stars 0 -ice 0.01 \
+    -inclination 10 -hour 12 -power 200 | \
+  pnmpsnr -target1=46.07 -target2=52.00 -target3=67.77 - ${test_ppm}
+
+rm ${test_ppm}
diff --git a/test/ppmhist.ok b/test/ppmhist.ok
index f2ba637b..468bd317 100644
--- a/test/ppmhist.ok
+++ b/test/ppmhist.ok
@@ -1,3 +1,4 @@
+Test 1
      0     0     0	    0	      2 
      1     1     1	    1	      2 
      2     2     2	    2	      2 
@@ -7,6 +8,7 @@
      6     6     6	    6	      2 
      8     8     8	    8	      2 
 3081591280 60957
+Test 2
  Summary: 1 colors: 1 black, 0 white, 0 gray, 0 color
  Summary: 1 colors: 0 black, 1 white, 0 gray, 0 color
  Summary: 2 colors: 1 black, 1 white, 0 gray, 0 color
@@ -17,3 +19,7 @@
  Summary: 6 colors: 0 black, 0 white, 0 gray, 6 color
  Summary: 6 colors: 1 black, 0 white, 0 gray, 5 color
  Summary: 6 colors: 1 black, 1 white, 1 gray, 3 color
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
diff --git a/test/ppmhist.test b/test/ppmhist.test
index 27d31562..8c2eedbc 100755
--- a/test/ppmhist.test
+++ b/test/ppmhist.test
@@ -1,12 +1,16 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmhist
 # Also requires: pgmramp pamtopnm pbmmake pamseq ppmpat
 
+echo "Test 1"
+
 pgmramp -maxval=8 -lr 8 2 | ppmhist -sort=rgb -noheader
 ppmhist -map -sort=rgb -noheader testimg.ppm | pamtopnm | cksum
 
 # Test summary header
 
+echo "Test 2"
+
 pbmmake -b 2 1 | ppmhist   | head -n1
 pbmmake -w 2 1 | ppmhist   | head -n1
 pbmmake -g 2 1 | ppmhist   | head -n1
@@ -19,4 +23,29 @@ ppmpat -madras --color=rgb:32/0d/b7,rgb:31/58/a3,rgb:e9/5e/d4 25 25 | \
 ppmpat -madras --color=rgb:00/00/00,rgb:31/58/a3,rgb:e9/5e/d4 25 25 | \
   ppmhist | head -n1
 ppmpat -madras --color=rgb:00/00/00,rgb:31/58/a3,rgb:ff/ff/ff 25 25 | \
-  ppmhist | head -n1
\ No newline at end of file
+  ppmhist | head -n1
+
+echo "Test Invalid"
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+ppmhist -hexcolor -float testimg.ppm > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmhist -hexcolor -map   testimg.ppm > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmhist -float    -map   testimg.ppm > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/ppmmake.ok b/test/ppmmake.ok
index 0e871732..6d559c8d 100644
--- a/test/ppmmake.ok
+++ b/test/ppmmake.ok
@@ -1,2 +1,15 @@
+Test 1
 2477651508 15012
+4294967295 0
 2378991101 7513
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
+Expected failure 7 1
+Expected failure 8 1
+Expected failure 9 1
+Expected failure 10 1
diff --git a/test/ppmmake.test b/test/ppmmake.test
index 879a367e..30eb596a 100755
--- a/test/ppmmake.test
+++ b/test/ppmmake.test
@@ -1,7 +1,69 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmmake
 # Also requires:
 
+echo "Test 1"
 
 ppmmake rgb:ff/80/80 50 100 -maxval=5 | cksum
+ppmmake rgbi:0.5/1.0/0 2   | cksum
 ppmmake red 50 50  | cksum
+
+echo "Test Invalid"
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+ppmmake rgb:gg/00/00  2 2  > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmmake rgb:ff/ff/00  2    > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmmake rgbi:1.1/0/0  2 2  > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmmake rgbi:1.0/.5   2 2  > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmmake rainbow       2 2  > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmmake               2 2  > ${test_out} || \
+  printf "Expected failure 6"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmmake blue -maxval=0 2 2  > ${test_out} || \
+  printf "Expected failure 7"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmmake blue -maxval=-1 2 2  > ${test_out} || \
+  printf "Expected failure 8"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmmake blue -maxval=65536 2 2  > ${test_out} || \
+  printf "Expected failure 9"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+RGBDEF=/dev/null ppmmake red 2 2 > ${test_out} || \
+  printf "Expected failure 10"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/ppmmix.test b/test/ppmmix.test
index e1c6486b..c3900baf 100755
--- a/test/ppmmix.test
+++ b/test/ppmmix.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmmix
 # Also requires: pamdepth pamenlarge pamsumm pbmmake
 # Also requires: pgmtopgm pnminvert ppmtopgm
diff --git a/test/ppmpat-random.ok b/test/ppmpat-random.ok
new file mode 100755
index 00000000..71f631e5
--- /dev/null
+++ b/test/ppmpat-random.ok
@@ -0,0 +1,6 @@
+Test 1. Should print: 1366170000 36015
+1366170000 36015
+Test 2. Should print: 4073196212 16813
+4073196212 16813
+Test 3. Should print: 2292015301 16813
+2292015301 16813
diff --git a/test/ppmpat-random.rand-ok b/test/ppmpat-random.rand-ok
deleted file mode 100644
index eb8779ab..00000000
--- a/test/ppmpat-random.rand-ok
+++ /dev/null
@@ -1,7 +0,0 @@
-000|0
-081|2219119109 36015
-081|3436846137 16813
-081|908097729 16813
-082|3606254242 36015
-082|3615722579 16813
-082|1756684515 16813
diff --git a/test/ppmpat-random.test b/test/ppmpat-random.test
index a6daa982..b1b78d94 100755
--- a/test/ppmpat-random.test
+++ b/test/ppmpat-random.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmpat
 # Also requires:
 
@@ -7,16 +7,22 @@
 
 # These tests require random numbers.
 
-# Test 1. Should print: 2219119109 36015 (glibc)
-#                       3606254242 36015 (MAC OS)
+echo "Test 1. Should print: 1366170000 36015" # Mersenne Twister
+#                           2219119109 36015 (glibc rand())
+#                           3606254242 36015 (MAC OS rand())
+
 ppmpat --randomseed=0 -camo 100 120 | cksum
 
-# Test 2. Should print: 3436846137 16813 (glibc)
-#                       3615722579 16813 (MAC OS)
+echo "Test 2. Should print: 4073196212 16813" # Mersenne Twister
+#                       3436846137 16813 (glibc)
+#                       3615722579 16813 (MAC OS rand())
+
 ppmpat --randomseed=0 -anticamo 80 70 | cksum
 
-# Test 3. Should print: 908097729 16813 (glibc)
-#                       1756684515 16813 (MAC OS)
+echo "Test 3. Should print: 2292015301 16813" # Mersenne Twister 
+#                       908097729 16813 (glibc rand())
+#                       1756684515 16813 (MAC OS rand())
+
 ppmpat --randomseed=0 --color \
   rgb:55/c0/34,rgb:0/ff/0,rgb:0/ee/0,rgb:0/cd/0,rgb:0/8b/0,rgb:4f/4f/2f \
   -camo 80 70 | cksum
diff --git a/test/ppmpat.ok b/test/ppmpat.ok
index bb940aee..f2b355a9 100644
--- a/test/ppmpat.ok
+++ b/test/ppmpat.ok
@@ -1,6 +1,47 @@
+Test 1. Should print: 4008533639 781
 4008533639 781
+Test 2. Should print: 738714211 781
+738714211 781
+Test 3. Should print: 3805937800 9613
 3805937800 9613
+Test 4. Should print: 1586690955 9613
+1586690955 9613
+Test 5. Should print: 2698433077 1549
 2698433077 1549
+Test 6. Should print: 1526189097 1549
+1526189097 1549
+Test 7. Should print: 3705929501 781
 3705929501 781
+Test 8. Should print: 1996587666 781
+1996587666 781
+Test 9. Should print: 3057513592 661
 3057513592 661
+Test 10. Should print: 1861389287 661
 1861389287 661
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
+Expected failure 7 1
+Expected failure 8 1
+Expected failure 9 1
+Expected failure 10 1
+Expected failure 11 1
+Expected failure 12 1
+Expected failure 13 1
+Expected failure 14 1
+Expected failure 15 1
+Expected failure 16 1
+Expected failure 17 1
+Expected failure 18 1
+Expected failure 19 1
+Expected failure 20 1
+Expected failure 21 1
+Expected failure 22 1
+Expected failure 23 1
+Expected failure 24 1
+Expected failure 25 1
+Expected failure 26 1
diff --git a/test/ppmpat.test b/test/ppmpat.test
index cd00c0f1..ced2e64a 100755
--- a/test/ppmpat.test
+++ b/test/ppmpat.test
@@ -1,21 +1,189 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmpat
 # Also requires:
 
-# Test 1. Should print: 4008533639 781
-ppmpat -g2 --color=rgb:32/0d/b7,rgb:31/58/a3 16 16 | cksum
+echo "Test 1. Should print: 4008533639 781"
+ppmpat -gingham2 \
+       -color=rgb:32/0d/b7,rgb:31/58/a3 16 16 | cksum
 
-# Test 2. Should print: 3805937800 9613
-ppmpat -g3 --color=rgb:32/0d/b7,rgb:31/58/a3,rgb:e9/5e/d4 64 50 | cksum
+echo "Test 2. Should print: 738714211 781"
+ppmpat -g2 -mesh \
+       --color=rgb:32/0d/b7,rgb:31/58/a3 16 16 | cksum
 
-# Test 3. Should print: 2698433077 1549
-ppmpat -madras --color=rgb:32/0d/b7,rgb:31/58/a3,rgb:e9/5e/d4 32 16 | cksum
+echo "Test 3. Should print: 3805937800 9613"
+ppmpat -gingham3 \
+       -color=rgb:32/0d/b7,rgb:31/58/a3,rgb:e9/5e/d4 64 50 | cksum
 
-# Test 4. Should print: 3705929501 781
+echo "Test 4. Should print: 1586690955 9613"
+ppmpat -g3 -mesh \
+       -color=rgb:32/0d/b7,rgb:31/58/a3,rgb:e9/5e/d4 64 50 | cksum
+
+echo "Test 5. Should print: 2698433077 1549"
+ppmpat -madras \
+       --color=rgb:32/0d/b7,rgb:31/58/a3,rgb:e9/5e/d4 32 16 | cksum
+
+echo "Test 6. Should print: 1526189097 1549"
+ppmpat -madras -mesh \
+       --color=rgb:32/0d/b7,rgb:31/58/a3,rgb:e9/5e/d4 32 16 | cksum
+
+echo "Test 7. Should print: 3705929501 781"
 ppmpat -tartan --color=rgb:32/0d/b7,rgb:31/58/a3,rgb:e9/5e/d4 16 16 | cksum
 
-# Test 5. Should print: 3057513592 661
+echo "Test 8. Should print: 1996587666 781"
+ppmpat -tartan -mesh \
+       --color=rgb:32/0d/b7,rgb:31/58/a3,rgb:e9/5e/d4 16 16 | cksum
+
+echo "Test 9. Should print: 3057513592 661"
 ppmpat -argyle1 --color=rgb:ff/ff/ff,rgb:ff/0/0 12 18 | cksum
 
-# Test 6. Should print: 1861389287 661
+echo "Test 10. Should print: 1861389287 661"
 ppmpat -argyle2 --color=rgb:00/00/00,rgb:ff/80/80,rgb:e0/e0/e0 12 18 | cksum
+
+echo "Test Invalid"
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+ppmpat -g2 -g3 10 10 > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmpat -madras -tartan 10 10 > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmpat -poles -squig 10 10 > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmpat -camo -anticamo 10 10 > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmpat -argyle1 -argyle2 10 10 > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmpat 10 10 > ${test_out} || \
+  printf "Expected failure 6"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmpat -g2 10 > ${test_out} || \
+  printf "Expected failure 7"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmpat -g2 10 10 10 > ${test_out} || \
+  printf "Expected failure 8"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmpat -g2 10 > ${test_out} || \
+  printf "Expected failure 9"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+clist1="-color=rgb:00/00/00"
+clist2="-color=rgb:00/00/00,rgb:00/00/ff"
+clist3="-color=rgb:00/00/00,rgb:00/00/ff,rgb:00/ff/ff"
+clist4="-color=rgb:00/00/00,rgb:00/00/ff,rgb:00/ff/ff,rgb:ff/ff/ff"
+
+# These patterns require exactly 2 colors
+ppmpat -gingham2 ${clist1} 10 10 > ${test_out} || \
+  printf "Expected failure 10"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmpat -argyle1  ${clist1} 10 10 > ${test_out} || \
+  printf "Expected failure 11"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmpat -gingham2 ${clist3} 10 10 > ${test_out} || \
+  printf "Expected failure 12"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmpat -argyle1  ${clist3} 10 10 > ${test_out} || \
+  printf "Expected failure 13"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# These require exactly 3 colors
+ppmpat -gingham3 ${clist2} 10 10 > ${test_out} || \
+  printf "Expected failure 14"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmpat -argyle2  ${clist2} 10 10 > ${test_out} || \
+  printf "Expected failure 15"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmpat -madras   ${clist2} 10 10 > ${test_out} || \
+  printf "Expected failure 16"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmpat -tartan   ${clist2} 10 10 > ${test_out} || \
+  printf "Expected failure 17"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmpat -gingham3 ${clist4} 10 10 > ${test_out} || \
+  printf "Expected failure 18"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmpat -argyle2  ${clist4} 10 10 > ${test_out} || \
+  printf "Expected failure 19"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmpat -madras   ${clist4} 10 10 > ${test_out} || \
+  printf "Expected failure 20"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmpat -tartan   ${clist4} 10 10 > ${test_out} || \
+  printf "Expected failure 21"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# These require at least 3 colors
+ppmpat -squig    ${clist2} 10 10 > ${test_out} || \
+  printf "Expected failure 22"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmpat -camo     ${clist2} 10 10 > ${test_out} || \
+  printf "Expected failure 23"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmpat -anticamo ${clist2} 10 10 > ${test_out} || \
+  printf "Expected failure 24"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# The squig pattern has an aspect ratio restriction
+ppmpat -squig ${clist3} 10 250  > ${test_out} || \
+  printf "Expected failure 25"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmpat -squig ${clist3} 500 20  > ${test_out} || \
+  printf "Expected failure 26"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/ppmrelief.test b/test/ppmrelief.test
index 3467dcde..c7241663 100755
--- a/test/ppmrelief.test
+++ b/test/ppmrelief.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmrelief
 # Also requires: pbmmake pgmramp pamflip
 
diff --git a/test/ppmrough.ok b/test/ppmrough.ok
new file mode 100755
index 00000000..83643849
--- /dev/null
+++ b/test/ppmrough.ok
@@ -0,0 +1 @@
+378403602 30015
diff --git a/test/ppmrough.rand-ok b/test/ppmrough.rand-ok
deleted file mode 100644
index 216545c7..00000000
--- a/test/ppmrough.rand-ok
+++ /dev/null
@@ -1,3 +0,0 @@
-000|0
-081|378403602 30015
-082|378403602 30015
diff --git a/test/ppmrough.test b/test/ppmrough.test
index bd4211a3..b10ba941 100755
--- a/test/ppmrough.test
+++ b/test/ppmrough.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmrough
 # Also requires:
 
diff --git a/test/ppmshift.ok b/test/ppmshift.ok
new file mode 100755
index 00000000..735ac445
--- /dev/null
+++ b/test/ppmshift.ok
@@ -0,0 +1,23 @@
+Test 1. Should print: 3705777303 101484
+3705777303 101484
+Test 2. Should print: 202790723 685
+202790723 685
+Test 3. Should print: 0 0 : 0
+0 0 : 0
+Test 4.  Should print: 0 0 : 0
+0 0 : 0
+Test 5. (1) Should print: 1 twice
+1
+1
+Test 5. (15) Should print: 1 twice
+1
+1
+Test 5. (16) Should print: 1 twice
+1
+1
+Test 5. (20) Should print: 1 twice
+1
+1
+Test 5. (1000) Should print: 1 twice
+1
+1
diff --git a/test/ppmshift.test b/test/ppmshift.test
new file mode 100755
index 00000000..fff193b3
--- /dev/null
+++ b/test/ppmshift.test
@@ -0,0 +1,42 @@
+#! /bin/bash
+# This script tests: ppmshift
+# Also requires: pgmtoppm
+
+echo "Test 1. Should print: 3705777303 101484"
+ppmshift -seed=1 10 testimg.ppm | cksum
+
+echo "Test 2. Should print: 202790723 685"
+ppmshift -seed=1 1 testgrid.pbm | cksum
+
+echo "Test 3. Should print: 0 0 : 0"
+ppmshift -seed=1 0 testimg.ppm | cmp -s - testimg.ppm
+  echo ${PIPESTATUS[@]} ":" $?
+
+tmpdir=${tmpdir:-/tmp}
+test0_ppm=${tmpdir}/test0.ppm
+test14_ppm=${tmpdir}/test14.ppm
+
+pgmtoppm < maze.pbm > ${test0_ppm}
+
+echo "Test 4.  Should print: 0 0 : 0"
+  ppmshift -seed=2 0 maze.pbm | cmp -s - ${test0_ppm}
+    echo ${PIPESTATUS[@]} ":" $?
+
+ppmshift -seed=2 14 maze.pbm > ${test14_ppm}
+
+for i in 1 15 16 20 1000
+  do
+  echo "Test 5. ("$i") Should print: 1 twice"
+  ppmshift -seed=2 $i maze.pbm | cmp -s - ${test0_ppm}
+    echo $?
+  ppmshift -seed=2 $i maze.pbm | cmp -s - ${test14_ppm}
+    echo $?
+  done
+
+# In Test 5 the image files are not supposed to match.
+# When cmp finds a difference, it may terminate and stop reading input from
+# the pipe at that point.  This may cause a "broken pipe" exception; however
+# this does not always happen.  The broken pipe shows up as a non-zero value
+# for ${PIPESTATUS[0]}.
+
+rm ${test0_ppm} ${test14_ppm}
diff --git a/test/ppmspread.ok b/test/ppmspread.ok
new file mode 100755
index 00000000..40f44465
--- /dev/null
+++ b/test/ppmspread.ok
@@ -0,0 +1,12 @@
+Test 1.
+stdin: PPM RAW 227 149 3 255 RGB
+stdin: PPM RAW 227 149 3 255 RGB
+Test 2.
+57 59
+57 59
+Test 3. Should print 281226646 481
+281226646 481
+Test 4. Should print 639729144 101484
+639729144 101484
+Test 5. Should print 3278353642 685
+3278353642 685
diff --git a/test/ppmspread.test b/test/ppmspread.test
new file mode 100755
index 00000000..d7e0fb37
--- /dev/null
+++ b/test/ppmspread.test
@@ -0,0 +1,28 @@
+#! /bin/sh
+# This script tests: ppmspread
+# Also requires: pamfile ppmtopgm pgmtopbm
+
+# Input/output size does not change
+
+echo "Test 1."
+cat testimg.ppm | pamfile -machine
+ppmspread -randomseed=100 20 testimg.ppm | pamfile -machine
+
+echo "Test 2."
+pamfile -size maze.pbm
+ppmspread -randomseed=100 20 maze.pbm | pamfile -size
+
+# No change when spread distance value is 0
+
+echo "Test 3. Should print 281226646 481"
+ppmspread -randomseed=1 0 maze.pbm | ppmtopgm | pgmtopbm | cksum
+
+# The following tests will fail when changes are made to the random
+# number generator
+
+echo "Test 4. Should print 639729144 101484"
+ppmspread -randomseed=1 10 testimg.ppm | cksum
+
+echo "Test 5. Should print 3278353642 685"
+ppmspread -randomseed=1 1 testgrid.pbm | cksum
+
diff --git a/test/ppmtoapplevol.ok b/test/ppmtoapplevol.ok
new file mode 100644
index 00000000..46acda60
--- /dev/null
+++ b/test/ppmtoapplevol.ok
@@ -0,0 +1,6 @@
+Test: should print 1518149010 3065
+1518149010 3065
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
diff --git a/test/ppmtoapplevol.test b/test/ppmtoapplevol.test
new file mode 100755
index 00000000..4964ede8
--- /dev/null
+++ b/test/ppmtoapplevol.test
@@ -0,0 +1,30 @@
+#! /bin/sh
+# This script tests: ppmtoapplevol 
+# Also requires: ppmmake pbmmake
+
+echo "Test: should print 1518149010 3065"
+ppmmake rgb:0/0/0 255 12 | ppmtoapplevol | cksum
+
+echo "Invalid input." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+echo "Test Invalid"
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+pbmmake 10 11 | ppmtoapplevol > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+ 
+pbmmake 10 13 | ppmtoapplevol > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+ 
+pbmmake 256 12 | ppmtoapplevol > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/ppmtoarbtxt-roundtrip.test b/test/ppmtoarbtxt-roundtrip.test
index dff78250..f63aabe2 100755
--- a/test/ppmtoarbtxt-roundtrip.test
+++ b/test/ppmtoarbtxt-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmtoarbtxt
 # Also requires: pnminvert pamtopnm
 
@@ -30,5 +30,4 @@ ppmtoarbtxt ${bodyskl} -hd ${headskl} testimg.ppm | tee ${inv_ppm} |
 
 cat ${inv_ppm} | ppmtoarbtxt ${bodyskl} -hd ${headskl} | pamtopnm | cksum
 
-
-rm ${bodyskl} ${headskl}
+rm ${inv_ppm} ${bodyskl} ${headskl}
diff --git a/test/ppmtopgm.test b/test/ppmtopgm.test
index 8503194b..696b660c 100755
--- a/test/ppmtopgm.test
+++ b/test/ppmtopgm.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmtopgm
 # Also requires:
 
diff --git a/test/ppmtoppm.ok b/test/ppmtoppm.ok
index 764a3464..2b4ad9f8 100644
--- a/test/ppmtoppm.ok
+++ b/test/ppmtoppm.ok
@@ -1 +1,23 @@
-829921912 685
+Test 1.  Should print a simple 4 x 3 pattern
+P3
+4 3
+255
+255 255 255  0 0 0  255 255 255  0 0 0
+0 0 0  255 255 255  0 0 0  255 255 255
+255 255 255  0 0 0  255 255 255  0 0 0
+Test 2.  Should print a simple 6 x 8 pattern
+P3
+6 8
+5
+0 0 0  0 0 0  0 0 0  1 1 1  1 1 1  2 2 2
+0 0 0  0 0 0  1 1 1  1 1 1  2 2 2  2 2 2
+0 0 0  1 1 1  1 1 1  2 2 2  2 2 2  2 2 2
+1 1 1  1 1 1  2 2 2  2 2 2  2 2 2  3 3 3
+1 1 1  2 2 2  2 2 2  2 2 2  3 3 3  3 3 3
+2 2 2  2 2 2  2 2 2  3 3 3  3 3 3  4 4 4
+2 2 2  2 2 2  3 3 3  3 3 3  4 4 4  4 4 4
+2 2 2  3 3 3  3 3 3  4 4 4  4 4 4  5 5 5
+Test 3.  Should print 669206373 10102
+669206373 10102
+Test 4.  Should print 1926073387 101484
+1926073387 101484
diff --git a/test/ppmtoppm.test b/test/ppmtoppm.test
index 797c733d..90ff2ddf 100755
--- a/test/ppmtoppm.test
+++ b/test/ppmtoppm.test
@@ -1,6 +1,15 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmtoppm
-# Also requires:
+# Also requires: pbmmake pgmramp
 
+echo "Test 1.  Should print a simple 4 x 3 pattern"
+pbmmake -g 4 3 | ppmtoppm -plain
 
-ppmtoppm < testgrid.pbm | cksum
+echo "Test 2.  Should print a simple 6 x 8 pattern"
+pgmramp -diagonal -maxval=5 6 8 | ppmtoppm -plain
+
+echo "Test 3.  Should print 669206373 10102"
+ppmtoppm < maze.pbm | cksum
+
+echo "Test 4.  Should print 1926073387 101484"
+ppmtoppm < testimg.ppm | cksum
\ No newline at end of file
diff --git a/test/ppmwheel.ok b/test/ppmwheel.ok
index 24756d1e..790a19cb 100644
--- a/test/ppmwheel.ok
+++ b/test/ppmwheel.ok
@@ -1,2 +1,9 @@
+Test 1.
 1537578995 59
 875938089 86
+Test Invalid.
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
diff --git a/test/ppmwheel.test b/test/ppmwheel.test
index f528e209..c6583f97 100755
--- a/test/ppmwheel.test
+++ b/test/ppmwheel.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmwheel
 # Also requires:
 
@@ -6,6 +6,8 @@
 # For values 6 and above, x86(-32) and x86-64 produce different output.
 # SSE floating-point math is the probable cause.
 
+echo "Test 1."
+
 for i in 4 5
 do
 ppmwheel $i | cksum
@@ -108,3 +110,38 @@ done
 #  98:  4086203619 28825    1961862620 28825
 #  99:  3656777902 29416    2475351252 29416
 # 100:  2246720411 30015    4055518595 30015
+
+echo "Test Invalid."
+
+tmpdir=${tmpdir:-/tmp}
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+ppmwheel 10 -huevalue -huesaturation > ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmwheel 0 > ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmwheel 3 > ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmwheel > ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+ppmwheel 10 10 > ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
diff --git a/test/ps-alt-roundtrip.ok b/test/ps-alt-roundtrip.ok
index 1cd73f75..a23005f9 100644
--- a/test/ps-alt-roundtrip.ok
+++ b/test/ps-alt-roundtrip.ok
@@ -1,3 +1,4 @@
+Test 1.  Should print: 281226646 481
 2425386270 41
-2425386270 41
-2916080186 235
+Test 2.  Should print: 2154092425 3374
+2154092425 3374
diff --git a/test/ps-alt-roundtrip.test b/test/ps-alt-roundtrip.test
index d90c4ddb..bdecaffd 100755
--- a/test/ps-alt-roundtrip.test
+++ b/test/ps-alt-roundtrip.test
@@ -1,27 +1,32 @@
-#! /bin/bash
-# This script tests: pbmtoepsi pbmtopsg3 pbmtolps psidtopgm pstopnm
+#! /bin/sh
+# This script tests: pbmtoepsi pbmtopsg3 psidtopgm pstopnm
 # Also requires: gs pnmcrop
 
 
 # This script is for testing alternative (or minor) utilities that
 # read/write Postscript and encapsulated Postscript:
-# pbmtoepsi, pbmtopsg3, pbmtolps and psidtopgm.
+# pbmtoepsi, pbmtopsg3 and psidtopgm.
 #
 # We keep these tests separate from those for pnmtops and pstopnm
 # which are far more popular.
 #
-# pbmtopsg3 and pbmtolps produce output that require pstopnm for decoding.
+# pbmtopsg3 produces output that requires pstopnm for decoding.
+#
+# We used to test pbmtolps here, but moved it out when gs changed its
+# rendering formula.
 #
 # Failure message
 ## If ps-roundtrip.test succeeds and this test fails, it is most likely
 ## a problem with one of the alternate Postscipt utilities:
-## pbmtoepsi, pbmtopsg3, pbmtolps or psidtopgm.
+## pbmtoepsi, pbmtopsg3, or psidtopgm.
 ## If both tests fail it indicates a problem with pstopnm or gs.
 
 # pstopnm does not use libnetpbm functions for output.
 # Output is filtered through at least one Netpbm program.
 
-# Test 1. Should print: 2425386270 41
+echo "Test 1.  Should print: 281226646 481"
+
+tmpdir=${tmpdir:-/tmp}
 testgrid1_ps=${tmpdir}/testgrid1.ps
 
 pbmtopsg3 -dpi=72 testgrid.pbm \
@@ -33,23 +38,12 @@ pstopnm -xborder=0 -yborder=0 -llx=0 -lly=-16 -urx=14 \
 rm ${testgrid1_ps}
 
 
-# Test 2. Should print: 2425386270 41
-testgrid2_ps=${tmpdir}/testgrid2.ps
-
-pbmtolps -dpi 72 testgrid.pbm \
-     > ${testgrid2_ps} && \
-pstopnm -xborder=0 -yborder=0 -dpi=72 -stdout \
-    -quiet ${testgrid2_ps} -pbm | \
-  pnmcrop | cksum
-
-rm ${testgrid2_ps}
-
-# Test 3. Should print: 2916080186 235
+echo "Test 2.  Should print: 2154092425 3374"
 # Output is pgm maxval=1 with black and white inverted.
-#
+
 testgrid_epsi=${tmpdir}/testgrid.epsi
 
-pbmtoepsi testgrid.pbm > ${testgrid_epsi} && \
+pbmtoepsi maze.pbm > ${testgrid_epsi} && \
 xysizebps=`awk  '/BeginPreview/ {print $2,$3,$4}' \
     ${testgrid_epsi}` && \
 awk '/^%%BeginPreview:/ { p=1; next } /^%%EndImage/ { p=0; next } \
diff --git a/test/ps-flate-roundtrip.ok b/test/ps-flate-roundtrip.ok
index 57fb124f..0fdf23f2 100644
--- a/test/ps-flate-roundtrip.ok
+++ b/test/ps-flate-roundtrip.ok
@@ -1,3 +1,5 @@
+Test 1.  Should print: 1926073387 101484 twice
 1926073387 101484
 1926073387 101484
-1386192571 507420
+Test 2. Should print 1831481505 608904
+1831481505 608904
diff --git a/test/ps-flate-roundtrip.test b/test/ps-flate-roundtrip.test
index de1105f0..9fc24ddb 100755
--- a/test/ps-flate-roundtrip.test
+++ b/test/ps-flate-roundtrip.test
@@ -1,11 +1,11 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pnmtops pstopnm
 # Also requires: pamtopnm gs zlib
 
 # This script tests the optional flate (zlib) compression feature of
 # pstopnm.
 # Flate compression allows you to make smaller output (.ps) files:
-# it is useful, but not essential.  Flate compression is not neccessary for
+# it is useful, but not essential.  Flate compression is not necessary for
 # printing pages with postscript printers - which is why many people need
 # pnmtops on their systems.
 
@@ -17,7 +17,7 @@ tmpdir=${tmpdir:-/tmp}
 # pstopnm does not use libnetpbm functions for output.
 # Output is filtered through pamtopnm.
 
-# Test 1.  Should print: 1926073387 101484 twice
+echo "Test 1.  Should print: 1926073387 101484 twice"
 test1_ps=${tmpdir}/testimg1.ps
 
 for flag in "-ps -flate" "-ps -rle -ascii -flate"
@@ -32,16 +32,17 @@ for flag in "-ps -flate" "-ps -rle -ascii -flate"
 
 rm ${test1_ps}
 
-# Test 2. Should print: 1386192571 507420
+echo "Test 2. Should print 1831481505 608904"
 # See comments in ps-roundtrip.test
 
 test3_ps=${tmpdir}/testimg3.ps
 flag="-ps -bitspersample=12 -flate -rle -vmreclaim"
-cat testimg.ppm testimg.ppm testimg.ppm testgrid.pbm testgrid.pbm | \
-pnmtops -nocenter -equalpixels -dpi 72 -noturn -setpage ${flag} \
-  > ${test3_ps} &&
+cat testimg.ppm testimg.ppm testimg.ppm maze.pbm \
+  testgrid.pbm testgrid.pbm | \
+  pnmtops -nocenter -equalpixels -dpi 72 -noturn -setpage ${flag} \
+    > ${test3_ps} &&
 xysize3=`awk  '/BoundingBox/ {print "-xsize="$4,"-ysize="$5 ; exit}' \
-  ${test3_ps}` &&
+    ${test3_ps}` &&
 pstopnm -portrait -xborder=0 -yborder=0 $xysize3 -stdout  ${test3_ps} | \
   pamtopnm | cksum
 
diff --git a/test/ps-roundtrip.ok b/test/ps-roundtrip.ok
index 5ef66cc4..1a69224d 100644
--- a/test/ps-roundtrip.ok
+++ b/test/ps-roundtrip.ok
@@ -1,7 +1,9 @@
+Test 1.  Should print 1926073387 101484 four times
 1926073387 101484
 1926073387 101484
 1926073387 101484
 1926073387 101484
+Test 2.  Should print 2918318199 62 seven times
 2918318199 62
 2918318199 62
 2918318199 62
@@ -9,6 +11,7 @@
 2918318199 62
 2918318199 62
 2918318199 62
-1386192571 507420
-1386192571 507420
-1386192571 507420
+Test 3. Should print 1831481505 608904 three times
+1831481505 608904
+1831481505 608904
+1831481505 608904
diff --git a/test/ps-roundtrip.test b/test/ps-roundtrip.test
index 207646cc..5d7b7d65 100755
--- a/test/ps-roundtrip.test
+++ b/test/ps-roundtrip.test
@@ -1,6 +1,6 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pnmtops pstopnm
-# Also requires: pamtopnm gs pbmmake pnmshear pnmpad pnmcat
+# Also requires: pamtopnm gs pbmmake pnmshear pnmpad pamcat
 
 
 # Failure message
@@ -11,7 +11,7 @@ tmpdir=${tmpdir:-/tmp}
 # pstopnm does not use libnetpbm functions for output.
 # Output is filtered through pamtopnm.
 
-# Test 1.  Should print: 1926073387 101484 four times
+echo "Test 1.  Should print 1926073387 101484 four times"
 test1_ps=${tmpdir}/testimg1.ps
 
 for flag in "" "-ps" "-rle" "-ps -ascii"
@@ -25,9 +25,9 @@ for flag in "" "-ps" "-rle" "-ps -ascii"
   done
 
 rm ${test1_ps}
-# Test 2.  Should print: 2918318199 62 seven times
+
+echo "Test 2.  Should print 2918318199 62 seven times"
 # Test image designed to detect problems with run-length compression
-#
 
 g_pbm=${tmpdir}/g.pbm
 t_pbm=${tmpdir}/t.pbm
@@ -37,7 +37,7 @@ pbmmake -g 2 2 > ${g_pbm}
 pbmmake -g 8 4 | \
   pnmshear 45 -noantialias -background=black | \
   pnmpad -right 60 | \
-  pnmcat -tb -jright - ${g_pbm} > ${t_pbm} &&
+  pamcat -tb -jright - ${g_pbm} > ${t_pbm} &&
 for flag in "" "-rle" "-ps -rle -ascii" \
             "-bitspersample=2 -rle" "-ps -bitspersample=4 -rle" \
             "-bitspersample=8 -rle" "-ps -bitspersample=12 -rle -dict"
@@ -52,8 +52,8 @@ for flag in "" "-rle" "-ps -rle -ascii" \
 
 rm ${grid_ps} ${g_pbm} ${t_pbm}
 
-#Test 3. Should print: 1386192571 507420 three times
-#
+echo "Test 3. Should print 1831481505 608904 three times"
+
 # Special care is needed when conducting round-trips with multiple-image
 # files as input.
 # (1) pnmtops: -setpage is mandatory
@@ -61,16 +61,16 @@ rm ${grid_ps} ${g_pbm} ${t_pbm}
 #          Subsequent BoundingBox values are ignored.
 # (3) pstopnm: input must be an ordinary file.  Input from stdin
 #     (by pipe or input redirection: "< file" ) does not work.
-#
 
 test3_ps=${tmpdir}/testimg3.ps
 
 for flag in "" "-ps" \
             "-ps -bitspersample=12 -rle -vmreclaim"
   do
-cat testimg.ppm testimg.ppm testimg.ppm testgrid.pbm testgrid.pbm | \
-pnmtops -nocenter -equalpixels -dpi 72 -noturn -setpage ${flag} \
-  > ${test3_ps} &&
+cat testimg.ppm testimg.ppm testimg.ppm maze.pbm \
+  testgrid.pbm testgrid.pbm | \
+  pnmtops -nocenter -equalpixels -dpi 72 -noturn -setpage ${flag} \
+    > ${test3_ps} &&
 xysize3=`awk  '/BoundingBox/ {print "-xsize="$4,"-ysize="$5 ; exit}' \
   ${test3_ps}` &&
 pstopnm -portrait -xborder=0 -yborder=0 $xysize3 -stdout  ${test3_ps} | \
diff --git a/test/qoi-roundtrip.ok b/test/qoi-roundtrip.ok
new file mode 100644
index 00000000..faa7601f
--- /dev/null
+++ b/test/qoi-roundtrip.ok
@@ -0,0 +1,34 @@
+Test 1.  Should print 1.N 0 0
+1.0 0 0
+1.1 0 0
+1.2 0 0
+1.3 0 0
+1.4 0 0
+Test 2.  Should print 2.N 0 0
+2.0 0 0
+2.1 0 0
+2.2 0 0
+2.3 0 0
+2.4 0 0
+Test 3.  Should print 3.N 0 0
+3.0 0 0
+3.1 0 0
+3.2 0 0
+3.3 0 0
+3.4 0 0
+Test Invalid
+Should print: Expected failure N 1
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
+Expected failure 7 1
+Expected failure 8 1
+------------------------------
+Should print: Expected failure N 0
+Expected failure 9 0
+Expected failure 10 0
+Expected failure 11 0
+Expected failure 12 0
diff --git a/test/qoi-roundtrip.test b/test/qoi-roundtrip.test
new file mode 100755
index 00000000..f758abcc
--- /dev/null
+++ b/test/qoi-roundtrip.test
@@ -0,0 +1,254 @@
+#! /bin/bash
+# This script tests: qoitopam pamtoqoi
+# Also requires: pamdepth pamfile pamseq pamstack pamtopnm pbmmake
+# Also requires: pgmnoise ppmpat ppmtopgm
+
+# Ensure that sed operates in original narrow-character mode
+
+LANG=C
+LC_ALL=C
+export LANG LC_ALL
+
+tmpdir=${tmpdir:-/tmp}
+
+maze_qoi=${tmpdir}/maze.qoi
+maze_bw_alpha=${tmpdir}/maze_bw_alpha.pam
+maze_rgb=${tmpdir}/maze_rgb.pam
+maze_rgb_alpha=${tmpdir}/maze_rgb_alpha.pam
+
+echo "Test 1.  Should print 1.N 0 0"
+
+pbmmake -g $(pamfile -size maze.pbm) |\
+  pamstack -tupletype="BLACKANDWHITE_ALPHA" maze.pbm - > ${maze_bw_alpha}
+
+pbmmake -g $(pamfile -size maze.pbm) |\
+  pamstack -tupletype="RGB" maze.pbm maze.pbm maze.pbm |\
+  pamdepth 255 > ${maze_rgb}
+printf "1.0 $? "
+
+pbmmake -g $(pamfile -size maze.pbm) |\
+  pamstack -tupletype="RGB_ALPHA" maze.pbm maze.pbm maze.pbm - |\
+  pamdepth 255 > ${maze_rgb_alpha}
+echo $?
+
+# PBM, PBM + alpha
+
+pamtoqoi maze.pbm | tee ${maze_qoi} | qoitopam | cmp -s - ${maze_rgb}
+printf "1.1 $? "
+test -s ${maze_qoi}
+echo $?
+
+pamdepth 8 maze.pbm | pamtoqoi | qoitopam | cmp -s - ${maze_rgb}
+printf "1.2 $? "
+test -s ${maze_rgb}
+echo $?
+
+pamtoqoi ${maze_bw_alpha} | qoitopam | cmp -s - ${maze_rgb_alpha}
+printf "1.3 $? "
+test -s ${maze_bw_alpha}
+echo $?
+
+pamdepth 2 ${maze_bw_alpha} | pamstack -tupletype="GRAYSCALE_ALPHA" |\
+  pamtoqoi | qoitopam | cmp -s - ${maze_rgb_alpha}
+printf "1.4 $? "
+test -s ${maze_rgb_alpha}
+echo $?
+
+rm ${maze_rgb} ${maze_rgb_alpha} ${maze_bw_alpha}
+
+echo "Test 2.  Should print 2.N 0 0"
+
+# ---- PGM, PGM + alpha
+
+noise1_pgm=${tmpdir}/noise1.pgm
+noise2_pgm=${tmpdir}/noise2.pgm
+test_gray_alpha=${tmpdir}/test_gray_alpha.pam
+res_gray_alpha=${tmpdir}/res_gray_alpha.pam
+
+pgmnoise --randomseed=0 20 20 > ${noise1_pgm}
+pgmnoise --randomseed=1 20 20 | tee ${noise2_pgm} |\
+  pamstack -tupletype="GRAYSCALE_ALPHA" ${noise1_pgm} - \
+  > ${test_gray_alpha}
+printf "2.0 $? "
+
+pamstack -tupletype="RGB_ALPHA" \
+  ${noise1_pgm} ${noise1_pgm} ${noise1_pgm} ${noise2_pgm} > ${res_gray_alpha}
+echo $?
+
+rm ${noise2_pgm}
+
+pamtoqoi ${noise1_pgm} | qoitopam | pamtopnm | ppmtopgm |\
+  cmp -s - ${noise1_pgm}
+printf "2.1 $? "
+test -s ${noise1_pgm}
+echo $?
+
+
+pamdepth 65535 ${noise1_pgm} | pamtoqoi | qoitopam | pamtopnm | ppmtopgm |\
+  cmp -s - ${noise1_pgm}
+printf "2.2 $? "
+test -s ${noise1_pgm}
+echo $?
+
+pamtoqoi ${test_gray_alpha} | qoitopam | cmp -s - ${res_gray_alpha}
+printf "2.3 $? "
+test -s ${test_gray_alpha}
+echo $?
+
+pamdepth 4095 ${test_gray_alpha} | pamtoqoi | qoitopam |\
+  cmp -s - ${res_gray_alpha}
+printf "2.4 $? "
+test -s ${res_gray_alpha}
+echo $?
+
+rm ${test_gray_alpha} ${res_gray_alpha}
+
+echo "Test 3.  Should print 3.N 0 0"
+
+# rgb rgb-alpha
+
+tartan_ppm=${tmpdir}/tartan.ppm
+tartan_qoi=${tmpdir}/tartan.qoi
+test_rgb_alpha=${tmpdir}/test_rgb_alpha.pam
+
+ppmpat -tartan 20 20 | tee ${tartan_ppm} |\
+  pamstack -tupletype="RGB_ALPHA" - ${noise1_pgm} > ${test_rgb_alpha}
+printf "3.0 $? "
+test -s ${tartan_ppm}
+echo $?
+
+pamtoqoi ${tartan_ppm} | tee ${tartan_qoi} | qoitopam | pamtopnm |\
+  cmp -s - ${tartan_ppm}
+printf "3.1 $? "
+test -s ${tartan_qoi}
+echo $?
+rm ${tartan_qoi}
+
+pamdepth 4095 ${tartan_ppm} | pamtoqoi | tee ${tartan_qoi} |\
+  qoitopam | pamtopnm | cmp -s - ${tartan_ppm}
+printf "3.2 $? "
+test -s ${tartan_qoi}
+echo $?
+rm ${tartan_qoi}
+
+pamtoqoi ${test_rgb_alpha} | qoitopam | cmp -s - ${test_rgb_alpha}
+printf "3.3 $? "
+test -s ${test_rgb_alpha}
+echo $?
+
+pamdepth 511 ${test_rgb_alpha} | pamtoqoi | qoitopam |\
+  cmp -s - ${test_rgb_alpha}
+printf "3.4 $? "
+test -s ${test_rgb_alpha}
+echo $?
+
+rm ${noise1_pgm} ${tartan_ppm} ${test_rgb_alpha}
+
+
+echo "Test Invalid"
+
+test_out=${tmpdir}/test.out
+maze_qoi_size=$(cat ${maze_qoi} | wc -c)
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+echo "Should print: Expected failure N 1"
+
+pamseq -tupletype="void" 1 1 | pamtoqoi > \
+  ${test_out} || \
+  printf "Expected failure 1"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+( echo "P1"; echo "400000001 1" ;
+  head -c 400000001 /dev/zero ) | pamtoqoi > \
+  ${test_out} || \
+  printf "Expected failure 2"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# Replace fields in the qoi file header with invalid values
+  
+( printf "qojf"
+  tail -c +5 ${maze_qoi} ) | qoitopam > \
+  ${test_out} || \
+  printf "Expected failure 3"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+( head -c 4 ${maze_qoi}
+  head -c 4 /dev/zero
+  tail -c +9 ${maze_qoi} ) | qoitopam > \
+  ${test_out} || \
+  printf "Expected failure 4"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+( head -c 8 ${maze_qoi}
+  head -c 4 /dev/zero
+  tail -c +13 ${maze_qoi} ) | qoitopam > \
+  ${test_out} || \
+  printf "Expected failure 5"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+# Following sed construct means: "replace first 8 bytes of input
+# stream."  echo -e -n and printf may be straightforward but
+# unfortunately they are not portable.  Is there any better solution?
+# Suggestions welcome.
+
+( head -c 4 ${maze_qoi}
+  tail -c +5 ${maze_qoi} | \
+  sed '1s/^......../\x00\x00\x4F\xFF\x00\x00\x4F\xFF/' ) | qoitopam > \
+  ${test_out} || \
+  printf "Expected failure 6"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+( head -c 12 ${maze_qoi}
+  tail -c +13 ${maze_qoi} | sed '1s/^./\x01/' ) | qoitopam > \
+  ${test_out} || \
+  printf "Expected failure 7"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+( head -c 13 ${maze_qoi}
+  tail -c +14 ${maze_qoi} | sed '1s/^./\x02/' ) | qoitopam > \
+  ${test_out} || \
+  printf "Expected failure 8"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+echo "------------------------------"
+echo "Should print: Expected failure N 0"
+
+( head -c $(( ${maze_qoi_size} - 9 )) ${maze_qoi}
+  tail -c 9 ${maze_qoi} |   sed '1s/^./\xfd/' ) | qoitopam > \
+  ${test_out} || \
+  printf "Expected failure 9"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+head -c $(( ${maze_qoi_size} - 1 )) ${maze_qoi} | qoitopam > \
+  ${test_out} || \
+  printf "Expected failure 10"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+( head -c $(( ${maze_qoi_size} - 1 )) ${maze_qoi}
+  printf '1' ) | qoitopam > \
+  ${test_out} || \
+  printf "Expected failure 11"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+( cat ${maze_qoi}; printf '1' ) | qoitopam > \
+  ${test_out} || \
+  printf "Expected failure 12"
+  test -s ${test_out}; echo " "$?
+  rm -f ${test_out}
+
+rm ${maze_qoi}
diff --git a/test/random-generator.ok b/test/random-generator.ok
new file mode 100644
index 00000000..e137d901
--- /dev/null
+++ b/test/random-generator.ok
@@ -0,0 +1,219 @@
+Test 1: Should produce:
+P2
+12 1
+1023
+720 296 192 858 101 57 298 629 804 1019 64 617
+Above output is for Mersenne Twister
+P2
+12 1
+1023
+720 296 192 858 101 57 298 629 804 1019 64 617
+
+Test 2: Mersenne Twister random number generator
+Should produce:
+3499211612  581869302 3890346734 3586334585  545404204
+4161255391 3922919429  949333985 2715962298 1323567403
+ ... 
+ 297480282 1101405687 1473439254 2634793792 1341017984
+ Total 1000 integers, 200 lines
+
+3499211612  581869302 3890346734 3586334585  545404204 
+4161255391 3922919429  949333985 2715962298 1323567403 
+ 418932835 2350294565 1196140740  809094426 2348838239 
+4264392720 4112460519 4279768804 4144164697 4156218106 
+ 676943009 3117454609 4168664243 4213834039 4111000746 
+ 471852626 2084672536 3427838553 3437178460 1275731771 
+ 609397212   20544909 1811450929  483031418 3933054126 
+2747762695 3402504553 3772830893 4120988587 2163214728 
+2816384844 3427077306  153380495 1551745920 3646982597 
+ 910208076 4011470445 2926416934 2915145307 1712568902 
+3254469058 3181055693 3191729660 2039073006 1684602222 
+1812852786 2815256116  746745227  735241234 1296707006 
+3032444839 3424291161  136721026 1359573808 1189375152 
+3747053250  198304612  640439652  417177801 4269491673 
+3536724425 3530047642 2984266209  537655879 1361931891 
+3280281326 4081172609 2107063880  147944788 2850164008 
+1884392678  540721923 1638781099  902841100 3287869586 
+ 219972873 3415357582  156513983  802611720 1755486969 
+2103522059 1967048444 1913778154 2094092595 2775893247 
+3410096536 3046698742 3955127111 3241354600 3468319344 
+1185518681 3031277329 2919300778   12105075 2813624502 
+3052449900  698412071 2765791248  511091141 1958646067 
+2140457296 3323948758 4122068897 2464257528 1461945556 
+3765644424 2513705832 3471087299  961264978   76338300 
+3226667454 3527224675 1095625157 3525484323 2173068963 
+4037587209 3002511655 1772389185 3826400342 1817480335 
+4120125281 2495189930 2350272820  678852156  595387438 
+3271610651  641212874  988512770 1105989508 3477783405 
+3610853094 4245667946 1092133642 1427854500 3497326703 
+1287767370 1045931779   58150106 3991156885  933029415 
+1503168825 3897101788  844370145 3644141418 1078396938 
+4101769245 2645891717 3345340191 2032760103 4241106803 
+1510366103  290319951 3568381791 3408475658 2513690134 
+2553373352 2361044915 3147346559 3939316793 2986002498 
+1227669233 2919803768 3252150224 1685003584 3237241796 
+2411870849 1634002467  893645500 2438775379 2265043167 
+ 325791709 1736062366  231714000 1515103006 2279758133 
+2546159170 3346497776 1530490810 4011545318 4144499009 
+ 557942923  663307952 2443079012 1696117849 2016017442 
+1663423246   51119001 3122246755 1447930741 1668894615 
+ 696567687 3983551422 3411426125 1873110678 1336658413 
+3705174600 2270032533 2664425968  711455903  513451233 
+2585492744 2027039028 1129453058 1461232481 2809248324 
+2275654012 2960153730 3075629128 3213286615 4245057188 
+1935061435 3094495853  360010077 3919490483  983448591 
+2171099548 3922754098 2397746050  654458600 2161184684 
+3546856898 1986311591 2312163142 2347594600 4278366025 
+1922360368  335761339 3669839044 1901288696 2595154464 
+ 458070173 2141230976 4131320786 4208748424   19903848 
+ 147391738 3328215103 4196191786 3510290616 1559873971 
+3731015357 2918514861  362649214 1487061100 1717053387 
+3675955720 1116134897  193529268 3436267940 2835191639 
+1852908272 3220971953 3911201640  571213604  781027019 
+4219206494 1133024903  409547355  625085180 1214072539 
+ 584409985 3445042528 3733581611  333104904 2489812253 
+2694595213 2361631596   34763086  622576118 2921810672 
+3663740744 2293225236 2671706445 1884059696 1507329019 
+ 857065948 2204390003  592711182 1725752375 1642107460 
+ 326274448 3274574484 1030432041  173822100  529650788 
+1086437636  789877945 2167974914 1030588245 3533061365 
+1792148406 4216468704  213264131 3536714075 3877136173 
+1296338417 4057830103  205919137 2108245233 1064497347 
+2101324080 2336703164 1450493809 3812754708 3865701845 
+1476779561 1585902852  142887412  477612192  699530444 
+3351157089 3768249319 1673915577  903239649 1038056164 
+1171465372 1734789440 2115022236  414269055  959581346 
+ 566820984 2105828892 4046076449 4101450561 4106566571 
+2800184123 2470502098 3253453343  256751188 1869365987 
+1008372035 2374606708 1516804538  228288551 3527001547 
+1385173098   66157275 1739381798  184785808 3901692666 
+ 725806641 3475217997 2787929747 1109372433 3142723729 
+ 557686578 2782047723 2118822689 1936702581 1625646963 
+2349385293 3085804937 1272688179 1236112995 3198431244 
+2677635414  811555596 3486972196 2949678043 1342211552 
+ 788174404 1656614077 1582629285 1477167035 2687011245 
+3503701453 3351051324 2874557775  348432514 1629591495 
+3991682351 1969229192 3331660584 1304012077 2090754125 
+3910846836 1871998370 2098597104 1918921592 3246092887 
+1315760974  464122393 2184028058 1690455542 2193747147 
+3737423698 3511684278 1549884962 3413774919 3938991454 
+2767325310 2335626851 1626114941  601913200 3485711542 
+ 858447440 2288468476 4075602213 1506361431 4252489875 
+4032981007 1031118352 3762145731   70955369 2362903502 
+1669089455 2673510137 3348740333 2521337794 2047144929 
+ 892246357 2319875070 1293843163   79245769 2022600352 
+3866257397  989939126  835351312 3626278636 3805332945 
+ 836506264 1895040349  970326679  634920763  733185481 
+1028655248  977810701 3434484235 1871311609 2031584214 
+1336174158  385787519 3965885375 2768323462 1847726660 
+2718987737  793780050 2509902580 3886434164 3120956802 
+4207987247 1523159183 1884932179 2922324286  477253416 
+3037922812 1108379444  697195677 1755438379  574393398 
+2555059183 1930828628 1126190880  180621093 2589191337 
+3424652760 3054648512  719646637  952394946 3570038180 
+ 504304985 1395707758 1274213163 2816553213 1369142370 
+1804702100 1821782344 3358274235 2181234724  486158240 
+ 367287522 4267199121 1127352639  779850007 3440331597 
+3276765484  125500149 1142120513 3989398167 1048565860 
+3136747194  432668526 2098559576 1478877150 2484746208 
+1209580219 1019125185 4160278734 1970740713  918146921 
+4136433784 2602441845 2348512686  973030509 2238261365 
+ 815637919  994690313 1724736366 2099799816 1775069742 
+2680317667  730798472 2916864943 1284417767 1698724919 
+2733611686 1578128411  651006053 4243350375 3303874296 
+ 162087183 3796616231 3801767645 4119825424 3922537059 
+  77594039 3419583692 2503306160  423966005 3293613218 
+1124728190 1407880681 1440346680  554334954 2919409323 
+1253962019  586491243 3638308238 3097648541  991125519 
+ 458538714 2155963569 2807866455    6862945 2122460897 
+  53853750 3346001678 1230879976 3071060893  423909157 
+3881450262 1652511030 3826483009 1526211009 1435219366 
+3092251623 3001090498  281084412  849586749 2207008400 
+ 131172352 1820973075 3195774605 2962673849 2147580010 
+1090677336 2061249893 1724513375 3885752424 1135918139 
+2619357288 4012575714 2652856935 2029480458 3691276589 
+2623865075 3459550738 2097670126 2477000057 2209844713 
+ 785646024 1052349661 1030500157 1430246618 3807539761 
+2157629976  123154542 2560049331 2104110449 1332109867 
+ 721241591 4136042859 4203401395  998151922 3060999432 
+3207929139 2149509272 1385268511 2023309182 1366796638 
+ 256061060 4090836236 2929047008 2296609403  182240337 
+3744374619  306855912 4014087816 2240468995 2865233169 
+ 415452309 1244206523 3513921306  281425419 3511338031 
+ 995954022 3102854413 3026765331  643667197  837979907 
+2832983005 1813414171 2227348307 4020325887 4178893912 
+ 610818241 2787397224 2762441380 3437393657 2030369078 
+1949046312 1876612561 1857107382 1049344864 3544695775 
+2172907342  358500115 3895295219  571965125  328582064 
+ 744698407 3066193991 1679065087 2650874932 3570748805 
+ 812110431 3450423805 1705023874  259721746 1192558045 
+1714799045 3685508436 2262914445 3903852862 1790140070 
+2651193482 2821191752  776610414 2697125035 2212010032 
+1254062056 3541766210 1853927671 1543286708   66516686 
+3505195914 4226521519 1260092911  717982876  739240369 
+ 456195732 2116515161 1599487648  838913496  850912042 
+3712172413 2103192411  877020153 1458113119 2646869271 
+4087221703 3771198399 3952796001 1685641891  226245966 
+4065518354 3169076409  715963611 1155859114 4174181651 
+1816065125 2422210778 2353087594 2569974907 4049024520 
+ 563593555 1794197249 2434290377 4222178191 2381045132 
+1294739153 1333544226 3011196239  518183212 2861903570 
+3168787443 2315530531 1042490149 2998340365 3534153126 
+2862715604  796613230  765073073 1342937225  549817636 
+3786981820 4291017601 2895722553  734959362 3175258828 
+ 140019477  268621172 2410334776  565052604 3787587805 
+ 386344800 2874086067   35710270  817904650 1960697289 
+1584484509 2724312018 1978802819 2275314726 4216102886 
+2138332912  671754166 1442240992 3674442465 1085868016 
+2769242611 1003628378 1616076847  743729558  820011032 
+2559719034 1839332599 3121982280 2070268989 3769147733 
+ 518022934 3037227899 2531915367 1008310588  971468687 
+2052976098 1651926578   78218926 2503907441 3209763057 
+1081499040 2812016370 1247433164  335294964 2650385171 
+2030527826 1139372809 4279827824 3540669095 2285341455 
+4220507154 3863048231 3136394663 3319584205 1476940506 
+ 875141230 2508558662 3896001866  462864388 1609807693 
+3892563868 3642514037 3778083990 1403162576 3512254868 
+1403323269 1119818229 2831288053 2552740643 2520136409 
+  96690857  210381252 1826474872 3306977352 1343117402 
+2112059492  693571694 2096734379  767794921 1843084587 
+1816280216 1695342628  404711915 3334843684 2570639553 
+4186538211 2022604264 3214805180 2989079529 2725165355 
+3005995436  310011850 2742468706 2720274646  144327376 
+2271696819  295519962 1272030376 1372670420 1397272558 
+2280044719 2710639434 2810822904 4271368265 1750711132 
+2216408539 3521792518 3111505866 3085328191 1054735512 
+4160317205 1427385632 2282061755 3215251668 1396490078 
+2933318719  453673969 2926038256 2624047458  338625410 
+3344930154 1971116345 1818716442 2998517928  390083048 
+ 291563131 1144486353  296954266  659950561 2263631666 
+1206908601 1125491020 1890151284 2076080514 2264060846 
+ 561805191 1964622705  405620012 3759692386  517035386 
+2225016848 4165419081 4052828294 3248204933 2738939733 
+1151808775 4113264137 3113447491 1033828852 1785686386 
+2903923175 2038900010 1241522880  238119113 2885394101 
+2636011022 2985605703 2107193353  292026696 3884689974 
+1094315383 4016714705  962244585 3943968050 2868319718 
+1304919603 3626636694 3393461291 1479454799  971639318 
+3352306399 1928233566 2900529135 2190901098   28842068 
+ 990556577 2586302532 3057504668 1661169605 4228191763 
+3934152427 2814119472    4943754 1171095774 1986204006 
+2014406505 1822565279   12890078 1979620724 1917376192 
+3307810835 4170173371 1385005883 1308519769 3370429606 
+ 923886311 2024463563 1063369787  153599761 3463680785 
+ 755374878 2088947962 3099927142 1750207400 2033606872 
+ 926120766  655932557 2320365045 1465119024 3105365454 
+2608716819 1218456091  823539591 2331574954 3171519129 
+3246671799 1043031086 1425831588 3940307546 3443545749 
+1155610704 3681098065 3287797558   63959365  810297004 
+3800799806 1234795257 2547289014  391329364  370300179 
+2474800443 3972311925 2935022755 3924395679 2347599539 
+4212318274 1828491430 3865565525 2767860661 4078993078 
+2781496513 4013741232 2916354756   35752471 2730683119 
+3340599926 4059491907  111492530  897368671 2524912702 
+3046341697 2790787159 1014602604 1409764839  512802978 
+ 477082227 2608350570  533747000 1933326657 4182933327 
+1970210993 2290203137 2843031053 2844558050 3308351089 
+3041943368 1504174920  295229952 2843309586  884572473 
+1787387521 1861566286 3616058184   48071792 3577350513 
+ 297480282 1101405687 1473439254 2634793792 1341017984 
diff --git a/test/random-generator.test b/test/random-generator.test
new file mode 100755
index 00000000..14b6f11a
--- /dev/null
+++ b/test/random-generator.test
@@ -0,0 +1,86 @@
+#! /bin/sh
+# This script tests: pgmnoise
+# Also requires:
+
+# These tests are for examining the integrity of the random number
+# generator.  There is some overlap between the tests here and tests
+# in pgmnoise.test, but the tests here are better focused for
+# diagnosing problems with the random number generator.
+#
+# Test 1 is for determining the kind of random number generator in
+# use.
+#
+# Test 2 prints random numbers in an output format close to what the
+# test in the original Mersenne Twister code produces.
+#
+# If these tests fail, subsequent tests which depend on random numbers
+# will fail too.  There is no provision (beyond remarks in the script
+# files) for generators other than the Mersenne Twister in those
+# tests.
+
+echo "Test 1: Should produce:"
+
+echo "P2"
+echo "12 1"
+echo "1023"
+echo "720 296 192 858 101 57 298 629 804 1019 64 617"
+echo "Above output is for Mersenne Twister"
+
+# GNU libc rand(): 593 252 207 990 507 824 961 805 559 110 167 172
+# MAC OS rand():   9 782 60 418 364 654 670 172 1022 515 593 903 
+
+pgmnoise -maxval=1023 -randomseed=3791 -plain 12 1
+
+echo
+echo "Test 2: Mersenne Twister random number generator"
+echo "Should produce:"
+
+echo "3499211612  581869302 3890346734 3586334585  545404204"
+echo "4161255391 3922919429  949333985 2715962298 1323567403"
+echo " ... "
+echo " 297480282 1101405687 1473439254 2634793792 1341017984"
+echo " Total 1000 integers, 200 lines"
+echo
+
+# Use perl to avoid mawk limitation
+# (cannot convert 32 bit integers)
+
+perlPgmProcessorProgram='
+  if (($#F+1) == 10) {
+    for (my $i = 0; $i <= 9; $i += 2) {
+      my $r = $F[$i + 1] * 65536 + $F[$i];
+      printf "%10u ", $r;
+    }
+    print "";
+  }
+'
+
+pgmnoise -randomseed=5489 -plain -maxval=65535 10 200 | \
+  perl -walne "$perlPgmProcessorProgram"
+
+# The above outputs (10 * 200 / 2) = 1000 samples.
+
+#    Method to generate output for Test 2 from original
+#    Mersenne Twister source code
+#
+# Download Mersenne Twister code.  See lib/util/randmersenne.c for URL.
+# Edit mt19937ar.c:
+#   In function main() at bottom of file, replace
+#     init_by_array(init, length);
+#   with
+#     init_genrand(5489UL);
+#
+# We need only the output of genrand_int32().
+# Remove the second loop which produces double-precision floating point
+# random numbers with genrand_real2().
+#
+# Compile: gcc mt19937ar.c -o mt1000
+# Execute: ./mt1000
+
+# 1000 may seem like a large number of samples but there is a reason
+# for this.  The generator produces random integers in batches of 624.
+# The number of samples must be larger than 624 to ensure proper
+# generation in batches after the first.
+
+# If you encounter problems, adjust the 200 (rows) above and tweak
+# the code in mt19937ar.c accordingly to produce more random numbers.
diff --git a/test/rawtoppm.ok b/test/rawtoppm.ok
new file mode 100644
index 00000000..c61e75aa
--- /dev/null
+++ b/test/rawtoppm.ok
@@ -0,0 +1,23 @@
+Test 1: should print '0 0 : 0'
+0 0 : 0
+Test 2: should print '0 0 : 0' five times
+0 0 : 0
+0 0 : 0
+0 0 : 0
+0 0 : 0
+0 0 : 0
+Test 3: should print '0 0 0 : 0' five times
+0 0 0 : 0
+0 0 0 : 0
+0 0 0 : 0
+0 0 0 : 0
+0 0 0 : 0
+Test 4
+P3
+5 5
+255
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 5  5 5 5  5 9 9  9 9 9
+0 1 2  3 4 0  1 2 3  4 0 1  2 3 4
+0 1 2  3 4 1  2 3 4  5 2 3  4 5 6
+9 8 7  6 5 4  3 2 1  0 0 0  0 0 0
diff --git a/test/rawtoppm.test b/test/rawtoppm.test
new file mode 100755
index 00000000..3c309259
--- /dev/null
+++ b/test/rawtoppm.test
@@ -0,0 +1,72 @@
+#! /bin/bash
+# This script tests: rawtoppm
+# Also requires: pamcut ppmtorgb3 rgb3toppm ppmtoppm
+
+# Test 1
+
+echo "Test 1: should print '0 0 : 0'"
+
+rawtoppm -headerskip 15 227 149 testimg.ppm | cmp -s - testimg.ppm
+  echo ${PIPESTATUS[@]} ":" $?
+
+# Test 2
+echo "Test 2: should print '0 0 : 0' five times"
+
+tmpdir=${tmpdir:-/tmp}
+test0_ppm=${tmpdir}/test0.ppm
+
+for i in 0 1 10 99 220
+  do
+  pamcut -cropright $i testimg.ppm > ${test0_ppm}
+  rawtoppm -headerskip 15 -rowskip $((i * 3)) $((227 - i)) 149 testimg.ppm | \
+  cmp -s ${test0_ppm} -
+  echo ${PIPESTATUS[@]} ":" $?
+  done  
+
+rm ${test0_ppm}
+
+
+# Test 3
+echo "Test 3: should print '0 0 0 : 0' five times"
+
+ppmtorgb3 testimg.ppm
+
+rgb3toppm testimg.red testimg.blu testimg.grn | \
+  rawtoppm -headerskip 15 -rbg 227 149  | cmp -s - testimg.ppm
+  echo ${PIPESTATUS[@]} ":" $?
+
+rgb3toppm testimg.grn testimg.red testimg.blu | \
+  rawtoppm -headerskip 15 -grb 227 149 | cmp -s - testimg.ppm
+  echo ${PIPESTATUS[@]} ":" $?
+
+rgb3toppm testimg.grn testimg.blu testimg.red | \
+  rawtoppm -headerskip 15 -gbr 227 149 | cmp -s - testimg.ppm
+  echo ${PIPESTATUS[@]} ":" $?
+
+rgb3toppm testimg.blu testimg.red testimg.grn | \
+  rawtoppm -headerskip 15 -brg 227 149 | cmp -s - testimg.ppm
+  echo ${PIPESTATUS[@]} ":" $?
+
+rgb3toppm testimg.blu testimg.grn testimg.red | \
+  rawtoppm -headerskip 15 -bgr 227 149 | cmp -s - testimg.ppm
+  echo ${PIPESTATUS[@]} ":" $?
+
+# Test 4
+echo "Test 4"
+
+test1_ppm=${tmpdir}/test1.ppm
+
+cat <<EOF > ${test1_ppm}
+P3
+5 5
+9
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 5  5 5 5  5 9 9  9 9 9
+0 1 2  3 4 0  1 2 3  4 0 1  2 3 4
+0 1 2  3 4 1  2 3 4  5 2 3  4 5 6
+9 8 7  6 5 4  3 2 1  0 0 0  0 0 0
+EOF
+
+ppmtoppm < ${test1_ppm} | rawtoppm -headerskip 9 5 5 -plain
+
+rm ${test1_ppm} testimg.red testimg.grn testimg.blu
diff --git a/test/rgb3-roundtrip.ok b/test/rgb3-roundtrip.ok
index 367e5429..cbdb369c 100644
--- a/test/rgb3-roundtrip.ok
+++ b/test/rgb3-roundtrip.ok
@@ -1,6 +1,12 @@
+Test 1.  Should print 1926073387 101484
 1926073387 101484
+Test 2.  Should print 3744829044 101514
 3744829044 101514
-2425386270 41
+Test 3.  Should print 281226646 481 twice
+281226646 481
+281226646 481
+Test 4.  Should print 0 twice
 0
 0
+Test 5.  Should print 0 0 : 0
 0 0 : 0
diff --git a/test/rgb3-roundtrip.test b/test/rgb3-roundtrip.test
index 42fd822f..76bd90f1 100755
--- a/test/rgb3-roundtrip.test
+++ b/test/rgb3-roundtrip.test
@@ -10,37 +10,45 @@
 tmpdir=${tmpdir:-/tmp}
 
 # Test 1.  PPM (color) input
-testimg_ppm=${tmpdir}/testimg.ppm
-testimg_red=${tmpdir}/testimg.red
-testimg_grn=${tmpdir}/testimg.grn
-testimg_blu=${tmpdir}/testimg.blu
-
-cp testimg.ppm ${tmpdir} &&
-ppmtorgb3 ${testimg_ppm} &&
-rgb3toppm ${testimg_red} ${testimg_grn} ${testimg_blu} | cksum
-
-cat ${testimg_red} ${testimg_grn} ${testimg_blu} | cksum
-
-rm ${testimg_ppm} ${testimg_red} ${testimg_grn} ${testimg_blu}
-
-# Test 2.  PBM (monochrome) input
-testgrid_pbm=${tmpdir}/testgrid.pbm
-testgrid_red=${tmpdir}/testgrid.red
-testgrid_grn=${tmpdir}/testgrid.grn
-testgrid_blu=${tmpdir}/testgrid.blu
-
-cp testgrid.pbm ${tmpdir} &&
-ppmtorgb3 ${testgrid_pbm} &&
-rgb3toppm ${testgrid_red} ${testgrid_grn} ${testgrid_blu} | \
+echo "Test 1.  Should print 1926073387 101484"
+rose_ppm=${tmpdir}/rose.ppm
+rose_red=${tmpdir}/rose.red
+rose_grn=${tmpdir}/rose.grn
+rose_blu=${tmpdir}/rose.blu
+
+cp testimg.ppm ${rose_ppm} &&
+ppmtorgb3 ${rose_ppm} &&
+rgb3toppm ${rose_red} ${rose_grn} ${rose_blu} | cksum
+
+# Simple cat of three planes
+echo "Test 2.  Should print 3744829044 101514"
+cat ${rose_red} ${rose_grn} ${rose_blu} | cksum
+
+rm ${rose_ppm} ${rose_red} ${rose_grn} ${rose_blu}
+
+# Test 3.  PBM (monochrome) input
+echo "Test 3.  Should print 281226646 481 twice"
+maze_pbm=${tmpdir}/maze.pbm
+maze_red=${tmpdir}/maze.red
+maze_grn=${tmpdir}/maze.grn
+maze_blu=${tmpdir}/maze.blu
+
+cp maze.pbm ${tmpdir} &&
+ppmtorgb3 ${maze_pbm} &&
+rgb3toppm ${maze_red} ${maze_grn} ${maze_blu} | \
   ppmtopgm | pgmtopbm -th -val=0.5 | cksum
+pgmtopbm -th -val=0.5 ${maze_red} | cksum
 
-# Test 3.
+# Test 4.
 # With PGM or PBM input, the three monochrome planes should be
 # identical.  Test for this.
 
-cmp -s ${testgrid_red} ${testgrid_grn} ; echo $?
-cmp -s ${testgrid_grn} ${testgrid_blu} ; echo $?
-pgmtopgm < testgrid.pbm | cmp -s - ${testgrid_red}
+echo "Test 4.  Should print 0 twice"
+cmp -s ${maze_red} ${maze_grn} ; echo $?
+cmp -s ${maze_grn} ${maze_blu} ; echo $?
+
+echo "Test 5.  Should print 0 0 : 0"
+pgmtopgm < maze.pbm | cmp -s - ${maze_red}
   echo ${PIPESTATUS[@]} ":" $?
 
-rm ${testgrid_pbm} ${testgrid_red} ${testgrid_grn} ${testgrid_blu}
+rm ${maze_pbm} ${maze_red} ${maze_grn} ${maze_blu}
diff --git a/test/sbig-roundtrip.test b/test/sbig-roundtrip.test
index 1fdaccfd..2611fa89 100755
--- a/test/sbig-roundtrip.test
+++ b/test/sbig-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pgmtosbig sbigtopgm
 # Also requires: pamchannel pamtopnm
 
diff --git a/test/sgi-roundtrip.ok b/test/sgi-roundtrip.ok
index b1bd5ba6..3c3f022a 100644
--- a/test/sgi-roundtrip.ok
+++ b/test/sgi-roundtrip.ok
@@ -1,8 +1,13 @@
+Test 1.  Should produce 1926073387 101484 twice
 1926073387 101484
 1926073387 101484
+Test 2.  Should produce 1926073387 101484 twice
 1926073387 101484
 1926073387 101484
-538848130 235
-538848130 235
-2394972481 463
-2394972481 463
+Test 3.  Should produce 281226646 481 twice
+281226646 481
+281226646 481
+Test 4. Should produce 4155890407 6741 three times
+4155890407 6741
+4155890407 6741
+4155890407 6741
diff --git a/test/sgi-roundtrip.test b/test/sgi-roundtrip.test
index 88efb75e..50a9fbc2 100755
--- a/test/sgi-roundtrip.test
+++ b/test/sgi-roundtrip.test
@@ -1,14 +1,14 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pnmtosgi sgitopnm
-# Also requires: rgb3toppm
-
+# Also requires: rgb3toppm pamdepth pamtopnm pgmtopbm
 
+tmpdir=${tmpdir:-/tmp}
 a_sgi=${tmpdir}/a.sgi
 a_red=${tmpdir}/a.red
 a_grn=${tmpdir}/a.grn
 a_blu=${tmpdir}/a.blu
 
-# Test 1.  Should produce 1926073387 101484 twice
+echo "Test 1.  Should produce 1926073387 101484 twice"
 pnmtosgi -rle testimg.ppm | tee ${a_sgi} | sgitopnm  | cksum
 sgitopnm -channel=0  ${a_sgi} > ${a_red}
 sgitopnm -channel=1  ${a_sgi} > ${a_grn}
@@ -21,7 +21,7 @@ b_red=${tmpdir}/b.red
 b_grn=${tmpdir}/b.grn
 b_blu=${tmpdir}/b.blu
 
-# Test 2.  Should produce 1926073387 101484 twice
+echo "Test 2.  Should produce 1926073387 101484 twice"
 pnmtosgi -verbatim testimg.ppm | tee ${b_sgi} | sgitopnm  | cksum
 sgitopnm -channel=0  ${b_sgi} > ${b_red}
 sgitopnm -channel=1  ${b_sgi} > ${b_grn}
@@ -29,15 +29,16 @@ sgitopnm -channel=2  ${b_sgi} > ${b_blu}
 rgb3toppm ${b_red} ${b_grn} ${b_blu} | cksum
 rm ${b_sgi} ${b_red} ${b_grn} ${b_blu}
 
-# Test 3.  Should produce 2425386270 41 twice
-pnmtosgi testgrid.pbm | sgitopnm | cksum             # Defaults to -rle
-pnmtosgi -verbatim testgrid.pbm | sgitopnm | cksum
-
+echo "Test 3.  Should produce 281226646 481 twice"
+pnmtosgi maze.pbm | sgitopnm | pgmtopbm -threshold -value=0.5 | cksum 
+# Defaults to -rle
+pnmtosgi -verbatim maze.pbm | sgitopnm | \
+  pgmtopbm -threshold -value=0.5 | cksum 
 
-testgrid_pgm=${tmpdir}/testgrid.pgm
+maze_pgm=${tmpdir}/maze.pgm
 
-# Test 4. Should produce 2394972481 463 twice
-pamdepth 65535 testgrid.pbm | pamtopnm | tee ${testgrid_pgm} | \
-  pnmtosgi -rle | sgitopnm | cksum
-pnmtosgi -verbatim ${testgrid_pgm} | sgitopnm | cksum
-rm ${testgrid_pgm}
+echo "Test 4. Should produce 4155890407 6741 three times"
+pamdepth 65535 maze.pbm | pamtopnm | tee ${maze_pgm} | cksum
+pnmtosgi -rle ${maze_pgm} | sgitopnm | cksum
+pnmtosgi -verbatim ${maze_pgm} | sgitopnm | cksum
+rm ${maze_pgm}
diff --git a/test/st4-roundtrip.test b/test/st4-roundtrip.test
index ffe8f348..f2e15078 100755
--- a/test/st4-roundtrip.test
+++ b/test/st4-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pgmtost4 st4topgm
 # Also requires: pamchannel pamtopnm pamcut
 
diff --git a/test/stdin-pam1.ok b/test/stdin-pam1.ok
new file mode 100644
index 00000000..10e48622
--- /dev/null
+++ b/test/stdin-pam1.ok
@@ -0,0 +1,44 @@
+pamaddnoise -seed=1: 0 0 0 0
+pamaltsat -strength=1: 0 0 0 0
+pambackground: 0 0 0 0
+pambayer -type=2: 0 0 0 0
+pambrighten: 0 0 0 0
+pamcat -topbottom: 0 0 0 0
+pamcut: 0 0 0 0
+pamdeinterlace: 0 0 0 0
+pamdepth 15: 0 0 0 0
+pamditherbw -threshold: 0 0 0 0
+pamedge: 0 0 0 0
+pamexec cat: 0 0 0 0
+pamfile -size: 0 0 0 0
+pamfind -target=1: 0 0 0 0
+pamfix: 0 0 0 0
+pamflip -lr: 0 0 0 0
+pamfunc -not: 0 0 0 0
+pamhomography -from 0,0,0,1,1,0,1,1: 0 0 0 0
+pamhue -huechange=60: 0 0 0 0
+pamlevels -f1 rgb:0/0/0 -t1 rgb:0/0/0 -f2 rgb:ff/ff/ff -t2 rgb:ff/ff/ff: 0 0 0 0
+pammixinterlace: 0 0 0 0
+pammosaicknit: 0 0 0 0
+pamoil: 0 0 0 0
+pamperspective 0 0 0 1 1 0 1 1: 0 0 0 0
+pamrecolor: 0 0 0 0
+pamrestack: 0 0 0 0
+pamrubber -quad 1 1 2 2: 0 0 0 0
+pamscale 2: 0 0 0 0
+pamshadedrelief: 0 0 0 0
+pamsharpness: 0 0 0 0
+pamshuffle -randomseed=1: 0 0 0 0
+pamsistoaglyph: 0 0 0 0
+pamslice -row=1: 0 0 0 0
+pamstack: 0 0 0 0
+pamstereogram -randomseed=1: 0 0 0 0
+pamstretch 1: 0 0 0 0
+pamstretch-gen 1: 0 0 0 0
+pamsumm -max: 0 0 0 0
+pamsummcol -mean: 0 0 0 0
+pamtable: 0 0 0 0
+pamthreshold: 0 0 0 0
+pamtilt: 0 0 0 0
+pamtopnm: 0 0 0 0
+pamwipeout -tb: 0 0 0 0
diff --git a/test/stdin-pam1.test b/test/stdin-pam1.test
new file mode 100755
index 00000000..7cb15dfc
--- /dev/null
+++ b/test/stdin-pam1.test
@@ -0,0 +1,75 @@
+#! /bin/bash
+# This script tests: pamaddnoise pamaltsat pambackground pambayer
+# This script tests: pambrighten pamcat pamcut pamdeinterlace pamdepth pamditherbw
+# This script tests: pamedge pamexec pamfile pamfind pamfix pamflip
+# This script tests: pamfunc pamhomography pamhue pamlevels
+# This script tests: pammixinterlace pammosaicknit pamoil
+# This script tests: pamperspective pamrecolor pamrestack pamrubber pamscale
+# This script tests: pamshadedrelief pamsharpness pamshuffle pamsistoaglyph
+# This script tests: pamslice pamstack pamstereogram pamstretch
+# This script tests: pamstretch-gen pamsumm pamsummcol pamtable pamthreshold
+# This script tests: pamtilt pamtopnm pamwipeout
+# Also requires: pbmmake
+
+tmpdir=${tmpdir:-/tmp}
+out1=${tmpdir}/out1
+out2=${tmpdir}/out2
+small_pbm=${tmpdir}/small.pbm
+
+pbmmake -g 5 5 > ${small_pbm}
+
+for testprog in \
+    "pamaddnoise -seed=1" \
+    "pamaltsat -strength=1" \
+    pambackground \
+    "pambayer -type=2" \
+    pambrighten \
+    "pamcat -topbottom" \
+    pamcut \
+    pamdeinterlace \
+    "pamdepth 15" \
+    "pamditherbw -threshold" \
+    pamedge \
+    "pamexec cat" \
+    "pamfile -size" \
+    "pamfind -target=1" \
+    pamfix \
+    "pamflip -lr" \
+    "pamfunc -not" \
+    "pamhomography -from 0,0,0,1,1,0,1,1" \
+    "pamhue -huechange=60" \
+    "pamlevels -f1 rgb:0/0/0 -t1 rgb:0/0/0 -f2 rgb:ff/ff/ff -t2 rgb:ff/ff/ff" \
+    pammixinterlace \
+    pammosaicknit \
+    pamoil \
+    "pamperspective 0 0 0 1 1 0 1 1" \
+    pamrecolor \
+    pamrestack \
+    "pamrubber -quad 1 1 2 2" \
+    "pamscale 2" \
+    pamshadedrelief \
+    pamsharpness \
+    "pamshuffle -randomseed=1" \
+    pamsistoaglyph \
+    "pamslice -row=1" \
+    pamstack \
+    "pamstereogram -randomseed=1" \
+    "pamstretch 1" \
+    "pamstretch-gen 1" \
+    "pamsumm -max" \
+    "pamsummcol -mean" \
+    pamtable \
+    pamthreshold \
+    pamtilt \
+    pamtopnm \
+    "pamwipeout -tb"
+  do
+  ${testprog} ${small_pbm} > ${out1};      status1=$?
+  ${testprog} < ${small_pbm} > ${out2};    status2=$?
+  test -s ${out1};                         status3=$?
+  cmp -s ${out1} ${out2}
+  echo ${testprog}": "${status1} ${status2} ${status3} $?
+  rm ${out1} ${out2}
+  done
+
+rm ${small_pbm}
diff --git a/test/stdin-pam2.ok b/test/stdin-pam2.ok
new file mode 100644
index 00000000..dd3148e8
--- /dev/null
+++ b/test/stdin-pam2.ok
@@ -0,0 +1,5 @@
+pammasksharpen: 0 0 0 0
+pammixmulti: 0 0 0 0
+pamdice: 0 0 0 0
+pamlookup: 0 0 0 0
+pamunlookup: 0 0 0 0
diff --git a/test/stdin-pam2.test b/test/stdin-pam2.test
new file mode 100755
index 00000000..f47df604
--- /dev/null
+++ b/test/stdin-pam2.test
@@ -0,0 +1,70 @@
+#! /bin/bash
+# This script tests: pammasksharpen pammixmulti pamdice
+# This script tests: pamlookup pamunlookup
+# Also requires: pbmmake
+
+tmpdir=${tmpdir:-/tmp}
+out1=${tmpdir}/out1
+out2=${tmpdir}/out2
+out3=${tmpdir}/out3
+out4=${tmpdir}/out4
+small_pbm=${tmpdir}/small.pbm
+
+pbmmake -g 3 3 > ${small_pbm}
+
+for testprog in \
+    pammasksharpen \
+    pammixmulti
+  do
+  ${testprog} ${small_pbm}   ${small_pbm} > ${out1};   status1=$?
+  ${testprog} ${small_pbm} < ${small_pbm} > ${out2};   status2=$?
+  test -s ${out1};                                     status3=$?
+  cmp -s ${out1} ${out2}
+  echo ${testprog}": "${status1} ${status2} ${status3} $?
+  rm ${out1} ${out2}
+done
+
+
+  dicestem=${tmpdir}/dice
+
+  testprog="pamdice -outstem=${dicestem}"
+  ${testprog} ${small_pbm};   status1=$?
+  cat ${dicestem}_*_*.pbm > ${out1}
+  rm ${dicestem}_*_*.pbm
+  ${testprog} < ${small_pbm}; status2=$?
+  cat ${dicestem}_*_*.pbm > ${out2}
+  rm ${dicestem}_*_*.pbm
+  test -s ${out1};            status3=$?
+  cmp -s ${out1} ${out2}
+  echo pamdice: ${status1} ${status2} ${status3} $?
+  # Do not use testprog, which contains a variable, in the above
+  # Same for pamlookup, pamunlookup
+  rm ${out1} ${out2}
+
+lookup_ppm=${tmpdir}/lookup.ppm
+
+cat > ${lookup_ppm} <<EOF
+P3
+2 1
+2
+0 0 0
+0 1 2
+EOF
+
+  testprog="pamlookup -lookupfile=${lookup_ppm}"
+  ${testprog}   ${small_pbm} > ${out1}; status1=$?
+  ${testprog} < ${small_pbm} > ${out2}; status2=$?
+  test -s ${out1};                      status3=$?
+  cmp -s ${out1} ${out2}
+  echo pamlookup": "${status1} ${status2} ${status3} $?
+  rm ${out2}
+
+  testprog="pamunlookup -lookupfile=${lookup_ppm}"
+  ${testprog}   ${out1} > ${out3}; status1=$?
+  ${testprog} < ${out1} > ${out4}; status2=$?
+  test -s ${out1};                 status3=$?
+  cmp -s ${out3} ${out4}
+  echo pamunlookup": "${status1} ${status2} ${status3} $?
+  rm ${out1} ${out3} ${out4}
+
+rm ${lookup_ppm} ${small_pbm}
diff --git a/test/stdin-pam3.ok b/test/stdin-pam3.ok
new file mode 100644
index 00000000..516e9554
--- /dev/null
+++ b/test/stdin-pam3.ok
@@ -0,0 +1,34 @@
+Test.  Should print (command): 0 0 0 0
+The following are exceptions: should print (command): 0 0 0 1
+pamtotga, pamtotiff
+
+pamtoavs: 0 0 0 0
+avstopam: 0 0 0 0
+pamtohdiff: 0 0 0 0
+hdifftopam: 0 0 0 0
+pamtojpeg2k: 0 0 0 0
+jpeg2ktopam: 0 0 0 0
+pamtopdbimg -fixedtime: 0 0 0 0
+pdbimgtopam: 0 0 0 0
+pamtopfm: 0 0 0 0
+pfmtopam: 0 0 0 0
+pamtopng: 0 0 0 0
+pngtopam: 0 0 0 0
+pamtoqoi: 0 0 0 0
+qoitopam: 0 0 0 0
+pamtosrf: 0 0 0 0
+srftopam: 0 0 0 0
+pamtosvg: 0 0 0 0
+svgtopam: 0 0 0 0
+pamtowinicon: 0 0 0 0
+winicontopam: 0 0 0 0
+pamtotga: 0 0 0 1
+tgatoppm: 0 0 0 0
+pamtoxvmini: 0 0 0 0
+xvminitoppm: 0 0 0 0
+pamtofits: 0 0 0 0
+fitstopnm: 0 0 0 0
+pamtogif: 0 0 0 0
+giftopnm: 0 0 0 0
+pamtotiff: 0 0 0 1
+tifftopnm: 0 0 0 0
diff --git a/test/stdin-pam3.test b/test/stdin-pam3.test
new file mode 100755
index 00000000..40155671
--- /dev/null
+++ b/test/stdin-pam3.test
@@ -0,0 +1,75 @@
+#! /bin/sh
+# This script tests: pamtoavs avstopam
+# This script tests: pamtohdiff hdifftopam
+# This script tests: pamtojpeg2k jpeg2ktopam
+# This script tests: pamtopdbimg pdbimgtopam
+# This script tests: pamtopfm pfmtopam
+# This script tests: pamtopng pngtopam
+# This script tests: pamtoqoi qoitopam
+# This script tests: pamtosrf srftopam
+# This script tests: pamtosvg svgtopam
+# This script tests: pamtowinicon winicontopam
+# This script tests: pamtotga tgatoppm
+# This script tests: pamtoxvmini xvminitoppm
+# This script tests: pamtofits fitstopnm
+# This script tests: pamtogif giftopnm
+# This script tests: pamtotiff tifftopnm
+# Also requires: pgmmake
+
+tmpdir=${tmpdir:-/tmp}
+test_pgm=${tmpdir}/test.pgm
+out1=${tmpdir}/out1
+out2=${tmpdir}/out2
+out3=${tmpdir}/out3
+out4=${tmpdir}/out4
+
+pgmmake -maxval 3 0.25 32 32 > ${test_pgm}
+
+echo "Test.  Should print (command): 0 0 0 0"
+echo "The following are exceptions: should print (command): 0 0 0 1"
+echo "pamtotga, pamtotiff"
+echo
+
+for fmt in \
+    avs \
+    hdiff \
+    jpeg2k \
+    pdbimg \
+    pfm \
+    png \
+    qoi \
+    srf \
+    svg \
+    winicon \
+    tga \
+    xvmini \
+    fits \
+    gif \
+    tiff
+  do
+
+  if [ ${fmt} = pdbimg ]
+      then testprog1="pamtopdbimg -fixedtime";
+      else testprog1="pamto"${fmt};
+  fi
+
+  case $fmt in
+      "tga" | "xvmini")        testprog2=${fmt}"toppm";;
+      "fits" | "gif" | "tiff") testprog2=${fmt}"topnm";;
+      *) testprog2=${fmt}"topam";
+  esac
+
+  ${testprog1} ${test_pgm} > ${out1};      status1=$?
+  ${testprog1} < ${test_pgm} > ${out2};    status2=$?
+  test -s ${out1};                         status3=$?
+  cmp -s ${out1} ${out2}
+  echo ${testprog1}": "${status1} ${status2} ${status3} $?
+
+  ${testprog2} ${out1} > ${out3};      status4=$?
+  ${testprog2} < ${out1} > ${out4};    status5=$?
+  test -s ${out3};                     status6=$?
+  cmp -s ${out3} ${out4}
+  echo ${testprog2}": "${status4} ${status5} ${status6} $?
+  done
+
+rm ${test_pgm} ${out1} ${out2} ${out3} ${out4}
diff --git a/test/stdin-pbm1.ok b/test/stdin-pbm1.ok
new file mode 100644
index 00000000..0dd83466
--- /dev/null
+++ b/test/stdin-pbm1.ok
@@ -0,0 +1,9 @@
+pbmclean: 0 0 0 0
+pbmlife: 0 0 0 0
+pbmmask: 0 0 0 0
+pbmminkowski: 0 0 0 0
+pbmtoepsi: 0 0 0 0
+pbmtopsg3: 0 0 0 0
+pbmpscale 1 : 0 0 0 0
+pbmreduce -threshold 2 : 0 0 0 0
+pbmtopgm 2 2 : 0 0 0 0
diff --git a/test/stdin-pbm1.test b/test/stdin-pbm1.test
new file mode 100755
index 00000000..4e99ba0b
--- /dev/null
+++ b/test/stdin-pbm1.test
@@ -0,0 +1,45 @@
+#! /bin/sh
+# This script tests: pbmclean pbmlife pbmmask pbmminkowski pbmtoepsi
+# This script tests: pbmtopsg3 pbmpscale pbmreduce pbmtopgm
+# Also requires: pbmmake
+
+# Tests whether output is unchanged when
+# (1) input is a named file: pbm-command input-file
+# (2) input is from stdin:   pbm-command < input-file
+
+tmpdir=${tmpdir:-/tmp}
+out1=${tmpdir}/out1
+out2=${tmpdir}/out2
+out3=${tmpdir}/out3
+out4=${tmpdir}/out4
+small_pbm=${tmpdir}/small.pbm
+
+pbmmake -b 3 3 > ${small_pbm}
+
+for testprog in \
+        pbmclean \
+        pbmlife \
+        pbmmask \
+        pbmminkowski \
+        pbmtoepsi \
+        pbmtopsg3 \
+        "pbmpscale 1 " \
+        "pbmreduce -threshold 2 " \
+        "pbmtopgm 2 2 "
+  do
+  ${testprog} ${small_pbm} > ${out1};      status1=$?
+  ${testprog} < ${small_pbm} > ${out2};    status2=$?
+  test -s ${out1};                         status3=$?
+  cmp -s ${out1} ${out2}
+  echo ${testprog}": "${status1} ${status2} ${status3} $?
+  rm ${out1} ${out2}
+  done
+
+rm ${small_pbm}
+
+# For Pbm converters not tested here see pbm-misc-converters.test
+
+# These programs do not have a converter in the opposite direction:
+# Brushtopbm
+# Ddbugtopbm
+# Thinkjettopbm (?)
diff --git a/test/stdin-pbm2.ok b/test/stdin-pbm2.ok
new file mode 100644
index 00000000..c77f7b13
--- /dev/null
+++ b/test/stdin-pbm2.ok
@@ -0,0 +1,28 @@
+pbmtoatk: 0 0 0 0
+atktopbm: 0 0 0 0
+pbmtocis: 0 0 0 0
+cistopbm: 0 0 0 0
+pbmtocmuwm: 0 0 0 0
+cmuwmtopbm: 0 0 0 0
+pbmtoescp2: 0 0 0 0
+escp2topbm: 0 0 0 0
+pbmtog3: 0 0 0 0
+g3topbm: 0 0 0 0
+pbmtogem: 0 0 0 0
+gemtopnm: 0 0 0 0
+pbmtomacp: 0 0 0 0
+macptopbm: 0 0 0 0
+pbmtomda: 0 0 0 0
+mdatopbm: 0 0 0 0
+pbmtomgr: 0 0 0 0
+mgrtopbm: 0 0 0 0
+pbmtomrf: 0 0 0 0
+mrftopbm: 0 0 0 0
+pbmtopi3: 0 0 0 0
+pi3topbm: 0 0 0 0
+pbmtosunicon: 0 0 0 0
+sunicontopnm: 0 0 0 0
+pbmtowbmp: 0 0 0 0
+wbmptopbm: 0 0 0 0
+pbmtoybm: 0 0 0 0
+ybmtopbm: 0 0 0 0
diff --git a/test/stdin-pbm2.test b/test/stdin-pbm2.test
new file mode 100755
index 00000000..ba585516
--- /dev/null
+++ b/test/stdin-pbm2.test
@@ -0,0 +1,78 @@
+#! /bin/sh
+# This script tests: atktopbm pbmtoatk
+# This script tests: cistopbm pbmtocis
+# This script tests: cmuwmtopbm pbmtocmuwm
+# This script tests: escp2topbm pbmtoescp2
+# This script tests: g3topbm pbmtog3
+# This script tests: gemtopnm pbmtogem
+# This script tests: macptopbm pbmtomacp
+# This script tests: mdatopbm pbmtomda
+# This script tests: mgrtopbm pbmtomgr
+# This script tests: mrftopbm pbmtomrf
+# This script tests: pi3topbm pbmtopi3
+# This script tests: sunicontopnm pbmtosunicon
+# This script tests: wbmptopbm pbmtowbmp
+# This script tests: ybmtopbm pbmtoybm
+# Also requires:
+
+tmpdir=${tmpdir:-/tmp}
+out1=${tmpdir}/out1
+out2=${tmpdir}/out2
+out3=${tmpdir}/out3
+out4=${tmpdir}/out4
+
+for fmt in  \
+        atk \
+        cis \
+        cmuwm \
+        escp2 \
+        g3 \
+        gem \
+        macp \
+        mda \
+        mgr \
+        mrf \
+        pi3 \
+        sunicon \
+        wbmp \
+        ybm
+  do
+  testprog1="pbmto"${fmt}
+
+  if [ ${fmt} = "sunicon" -o ${fmt} = "gem" ];
+    then testprog2=${fmt}"topnm";
+    else testprog2=${fmt}"topbm";
+  fi
+
+  ${testprog1} testgrid.pbm > ${out1};     status1=$?
+  ${testprog1} < testgrid.pbm > ${out2};   status2=$?
+  test -s ${out1};                         status3=$?
+  cmp -s ${out1} ${out2}
+  echo ${testprog1}": "${status1} ${status2} ${status3} $?
+  rm ${out2}
+
+  ${testprog2} ${out1} > ${out3};      status3=$?
+  ${testprog2} < ${out1} > ${out4};    status4=$?
+
+  if [ ${fmt} = "xbm" ];
+    then sed -i '3s/noname/testgrid/' ${out3};
+  fi
+
+  test -s ${out3};                         status5=$?
+  cmp -s ${out3} ${out4}
+  echo ${testprog2}": "${status3} ${status4} ${status5} $?
+  rm ${out1} ${out3} ${out4}
+  done
+
+# We don't test Pbmtopgm Pgmtopbm Asciitopbm Asciitopgm here
+
+# Pbmtopk Pktopbm require resolution output pk file, tk file
+#            some conditions apply to input image dimensions
+
+# These three programs embed the input file name in the output
+# If the input is from stdin, "noname"
+# Pbmtolps tested in lps-roundtrip.test
+# Pbmtoxbm           xbm-roundtrip.test
+# Pbmtozinc          pbm-misc-converters.test
+
+# Icontopbm Pbmtoicon Pbmtox10bm are legacy
diff --git a/test/stdin-pgm1.ok b/test/stdin-pgm1.ok
new file mode 100644
index 00000000..b3159517
--- /dev/null
+++ b/test/stdin-pgm1.ok
@@ -0,0 +1,11 @@
+pgmabel: 0 0 0 0
+pgmbentley: 0 0 0 0
+pgmdeshadow: 0 0 0 0
+pgmenhance: 0 0 0 0
+pgmhist: 0 0 0 0
+pgmmedian: 0 0 0 0
+pgmminkowski: 0 0 0 0
+pgmtexture: 0 0 0 0
+pgmtopbm -th : 0 0 0 0
+pgmtoppm rgb:00/00/00 : 0 0 0 0
+rawtopgm -headerskip 11 3 3 : 0 0 0 0
diff --git a/test/stdin-pgm1.test b/test/stdin-pgm1.test
new file mode 100755
index 00000000..f5980cdc
--- /dev/null
+++ b/test/stdin-pgm1.test
@@ -0,0 +1,47 @@
+#! /bin/sh
+# This script tests: pgmabel pgmbentley pgmdeshadow pgmenhance pgmhist
+# This script tests: pgmmedian pgmminkowski pgmtexture pgmtopbm pgmtoppm
+# This script tests: rawtopgm
+# Also requires: pgmmake
+
+tmpdir=${tmpdir:-/tmp}
+small_pgm=${tmpdir}/small.pgm
+out1=${tmpdir}/out1
+out2=${tmpdir}/out2
+out3=${tmpdir}/out3
+out4=${tmpdir}/out4
+
+pgmmake 0.5 3 3 > ${small_pgm}
+
+for testprog in  \
+        pgmabel \
+        pgmbentley \
+        pgmdeshadow \
+        pgmenhance \
+        pgmhist \
+        pgmmedian \
+        pgmminkowski \
+        pgmtexture \
+        "pgmtopbm -th " \
+        "pgmtoppm rgb:00/00/00 " \
+	"rawtopgm -headerskip 11 3 3 "
+  do
+  ${testprog} ${small_pgm} > ${out1};      status1=$?
+  ${testprog} < ${small_pgm} > ${out2};    status2=$?
+  test -s ${out1};                         status3=$?
+  cmp -s ${out1} ${out2}
+  echo ${testprog}": "${status1} ${status2} ${status3} $?
+  rm ${out1} ${out2}
+  done
+
+rm ${small_pgm}
+
+
+# Pgmtopgm accepts input only from stdin
+
+# These three programs are legacy
+# Pgmedge
+# Pgmnorm
+# Pgmoil
+
+# Pgmmorphconv needs template file
diff --git a/test/stdin-pgm2.ok b/test/stdin-pgm2.ok
new file mode 100644
index 00000000..ee6d8082
--- /dev/null
+++ b/test/stdin-pgm2.ok
@@ -0,0 +1,6 @@
+pgmtofs : 0 0 0 0
+fstopgm : 0 0 0 0
+pgmtolispm : 0 0 0 0
+lispmtopgm : 0 0 0 0
+pgmtost4 : 0 0 0 0
+st4topgm : 0 0 0 0
diff --git a/test/stdin-pgm2.test b/test/stdin-pgm2.test
new file mode 100755
index 00000000..3a6220d8
--- /dev/null
+++ b/test/stdin-pgm2.test
@@ -0,0 +1,49 @@
+#! /bin/sh
+# This script tests: pgmtofs fstopgm
+# This script tests: pgmtolispm lispmtopgm
+# This script tests: pgmtost4 st4topgm
+# Also requires: pgmmake
+
+tmpdir=${tmpdir:-/tmp}
+test_pgm=${tmpdir}/test.pgm
+out1=${tmpdir}/out1
+out2=${tmpdir}/out2
+out3=${tmpdir}/out3
+out4=${tmpdir}/out4
+
+pgmmake 0.75 192 165 > ${test_pgm}
+
+for fmt in  \
+        fs \
+        lispm \
+	st4
+  do
+  testprog1="pgmto"${fmt}
+  testprog2=${fmt}"topgm"
+
+  ${testprog1} ${test_pgm} > ${out1};   status1=$?
+  ${testprog1} < ${test_pgm} > ${out2}; status2=$?
+  test -s ${out1};                      status3=$?
+  cmp -s ${out1} ${out2}
+  echo ${testprog1}" :" ${status1} ${status2} ${status3} $?
+  rm ${out2}
+
+  ${testprog2} ${out1} > ${out3};     status4=$?
+  ${testprog2} < ${out1} > ${out4};   status5=$?
+  test -s ${out3};                    status6=$?
+  cmp -s ${out3} ${out4}
+  echo ${testprog2}" :" ${status4} ${status5} ${status6} $?
+
+  rm ${out1} ${out3} ${out4}
+  done
+
+rm ${test_pgm}
+
+# pgmtost4 size must be 192 x 165
+
+# The following programs do not have converters in the opposite direction:
+# Bioradtopgm
+# Hipstopgm
+# Psidtopgm
+# Rawtopgm
+# Spottopgm
diff --git a/test/stdin-pnm1.ok b/test/stdin-pnm1.ok
new file mode 100644
index 00000000..9f427b23
--- /dev/null
+++ b/test/stdin-pnm1.ok
@@ -0,0 +1,22 @@
+pnmalias: 0 0 0 0
+pnmcolormap all : 0 0 0 0
+pnmconvol -matrix=-1,3,-1 : 0 0 0 0
+pnmcrop: 0 0 0 0
+pnmgamma -ungamma 0.5 : 0 0 0 0
+pnmhisteq: 0 0 0 0
+pnmhistmap: 0 0 0 0
+pnminvert: 0 0 0 0
+pnmmargin 2 : 0 0 0 0
+pnmmercator: 0 0 0 0
+pnmmontage: 0 0 0 0
+pnmnlfilt 0.5 0.5 : 0 0 0 0
+pnmnorm: 0 0 0 0
+pnmpad: 0 0 0 0
+pnmquant 64 : 0 0 0 0
+pnmrotate 90 : 0 0 0 0
+pnmscalefixed 1 : 0 0 0 0
+pnmshear 45 : 0 0 0 0
+pnmsmooth: 0 0 0 0
+pnmtile 4 4 : 0 0 0 0
+pnmtoddif: 0 0 0 0
+pnmtopclxl -colorok : 0 0 0 0
diff --git a/test/stdin-pnm1.test b/test/stdin-pnm1.test
new file mode 100755
index 00000000..ae848752
--- /dev/null
+++ b/test/stdin-pnm1.test
@@ -0,0 +1,59 @@
+#! /bin/sh
+# This script tests: pnmalias pnmcolormap pnmconvol pnmcrop pnmgamma
+# This script tests: pnmhisteq pnmhistmap pnminvert pnmmargin pnmmercator
+# This script tests: pnmmontage pnmnlfilt pnmnorm pnmpad pnmquant pnmrotate
+# This script tests: pnmscalefixed pnmshear pnmsmooth pnmtile pnmtoddif
+# This script tests: pnmtopclxl
+# Also requires: ppmpat pamflip
+
+tmpdir=${tmpdir:-/tmp}
+small_ppm=${tmpdir}/test.ppm
+out1=${tmpdir}/out1
+out2=${tmpdir}/out2
+
+ppmpat -g2 -color=rgb:00/00/ff,rgb:ff/00/00 -mesh 4 4 > ${small_ppm}
+
+for testprog in  \
+        pnmalias \
+        "pnmcolormap all " \
+        "pnmconvol -matrix=-1,3,-1 " \
+        pnmcrop \
+        "pnmgamma -ungamma 0.5 " \
+        pnmhisteq \
+        pnmhistmap \
+        pnminvert \
+        "pnmmargin 2 " \
+        pnmmercator \
+        pnmmontage \
+        "pnmnlfilt 0.5 0.5 " \
+        pnmnorm \
+        pnmpad \
+        "pnmquant 64 " \
+        "pnmrotate 90 " \
+        "pnmscalefixed 1 " \
+        "pnmshear 45 " \
+        pnmsmooth \
+        "pnmtile 4 4 " \
+	pnmtoddif \
+	"pnmtopclxl -colorok "
+  do
+  ${testprog} ${small_ppm} > ${out1};      status1=$?
+  ${testprog} < ${small_ppm} > ${out2};    status2=$?
+  test -s ${out1};                         status3=$?
+  cmp -s ${out1} ${out2}
+  echo ${testprog}": "${status1} ${status2} ${status3} $?
+  rm ${out1} ${out2}
+  done
+
+
+rm ${small_ppm}
+
+# Pnmquantall: overwrites input files
+# Pnmremap: requires -mapfile=file
+# Pnmpsnr : compares two input files
+# Pnmindex: no input from stdin
+# Pnmpaste: requires two input files
+# Pnmstitch: requires two input files
+
+# pnmmargin: uses pamflip
+# pnmsmooth: uses pnmconvol
diff --git a/test/stdin-pnm2.ok b/test/stdin-pnm2.ok
new file mode 100644
index 00000000..093ff3f7
--- /dev/null
+++ b/test/stdin-pnm2.ok
@@ -0,0 +1,28 @@
+Test.  Should print (command): 0 0 0
+The following are exceptions: should print (command): 0 0 0 1
+pnmtops, pstopnm, pnmtoxwd, pnmtotiffcmyk
+
+pnmtofiasco --progress-meter 0 : 0 0 0 0
+fiascotopnm: 0 0 0 0
+pnmtojbig: 0 0 0 0
+jbigtopnm: 0 0 0 0
+pnmtojpeg: 0 0 0 0
+jpegtopnm: 0 0 0 0
+pnmtopalm: 0 0 0 0
+palmtopnm: 0 0 0 0
+pnmtopng: 0 0 0 0
+pngtopam: 0 0 0 0
+pnmtops: 0 0 0 1
+pstopnm -stdout : 0 0 0 1
+pnmtorast: 0 0 0 0
+rasttopnm: 0 0 0 0
+pnmtorle: 0 0 0 0
+rletopnm: 0 0 0 0
+pnmtosgi: 0 0 0 0
+sgitopnm: 0 0 0 0
+pnmtosir: 0 0 0 0
+sirtopnm: 0 0 0 0
+pnmtoxwd: 0 0 0 1
+xwdtopnm: 0 0 0 0
+pnmtotiffcmyk: 0 0 0 1
+tifftopnm: 0 0 0 0
diff --git a/test/stdin-pnm2.test b/test/stdin-pnm2.test
new file mode 100755
index 00000000..7622c279
--- /dev/null
+++ b/test/stdin-pnm2.test
@@ -0,0 +1,91 @@
+#! /bin/sh
+# This script tests: pnmtofiasco fiascotopnm
+# This script tests: pnmtojbig jbigtopnm
+# This script tests: pnmtojpeg jpegtopnm
+# This script tests: pnmtopalm palmtopnm
+# This script tests: pnmtopng pngtopam
+# This script tests: pnmtops pstopnm
+# This script tests: pnmtorast rasttopnm
+# This script tests: pnmtorle rletopnm
+# This script tests: pnmtosgi sgitopnm
+# This script tests: pnmtosir sirtopnm
+# This script tests: pnmtoxwd xwdtopnm
+# This script tests: pnmtotiffcmyk tifftopnm
+# Also requires: pgmramp
+
+tmpdir=${tmpdir:-/tmp}
+test_pgm=${tmpdir}/test.pgm
+out1=${tmpdir}/out1
+out2=${tmpdir}/out2
+out3=${tmpdir}/out3
+out4=${tmpdir}/out4
+
+pgmramp -diag 32 32 > ${test_pgm}
+
+echo "Test.  Should print (command): 0 0 0"
+echo "The following are exceptions: should print (command): 0 0 0 1"
+echo "pnmtops, pstopnm, pnmtoxwd, pnmtotiffcmyk"
+echo
+
+export NO_ADD_RLE_HISTORY=1
+# Suppress command-line sequence, execution time in pnmtorle header
+
+for fmt in  \
+        fiasco \
+        jbig \
+        jpeg \
+        palm \
+        png \
+        ps \
+        rast \
+        rle \
+        sgi \
+        sir \
+        xwd \
+	tiffcmyk
+  do
+
+  if [ ${fmt} = "fiasco" ]
+    then testprog1="pnmto"${fmt}" --progress-meter 0 ";
+  else
+      testprog1="pnmto"${fmt};
+  fi
+
+  if [ ${fmt} = "png" ]
+    then testprog2="pngtopam";
+  elif [ ${fmt} = "ps" ]
+    then testprog2="pstopnm -stdout ";
+  elif [ ${fmt} = "tiffcmyk" ]
+    then testprog2="tifftopnm";
+  else
+    testprog2=${fmt}"topnm";
+  fi
+
+  ${testprog1} ${test_pgm} > ${out1};   status1=$?
+  ${testprog1} < ${test_pgm} > ${out2}; status2=$?
+  test -s ${out1};                      status3=$?
+  cmp -s ${out1} ${out2}
+  echo ${testprog1}": "${status1} ${status2} ${status3} $?
+  rm ${out2}
+
+  ${testprog2} ${out1} > ${out3};       status4=$?
+  ${testprog2} < ${out1} > ${out4};     status5=$?
+  test -s ${out3};                      status6=$?
+  cmp -s ${out3} ${out4}
+  echo ${testprog2}": "${status4} ${status5} ${status6} $?
+  rm ${out1} ${out3} ${out4}
+
+  done
+
+rm ${test_pgm}
+
+
+# pnmtofiasco  width, height must be even and at least 32
+#              use --progressmeter option to suppress progress meter
+#
+# pnmtojbig    input must be bilevel black-white or gray
+# pnmtops      input file name embedded in output
+# pnmtotiffcmyk  input file name embedded in output
+#                "Standard input" if from stdin
+# pnmtoxwd     input file name embedded in output
+#              "stdin" if from stdin
diff --git a/test/stdin-ppm1.ok b/test/stdin-ppm1.ok
new file mode 100644
index 00000000..e84a31ea
--- /dev/null
+++ b/test/stdin-ppm1.ok
@@ -0,0 +1,15 @@
+ppmchange: 0 0 0 0
+ppmcolormask -color=rgb:0/0/ff : 0 0 0 0
+ppmdim 0.5 : 0 0 0 0
+ppmdist: 0 0 0 0
+ppmdither: 0 0 0 0
+ppmflash 0.5 : 0 0 0 0
+ppmglobe 12 : 0 0 0 0
+ppmhist: 0 0 0 0
+ppmlabel: 0 0 0 0
+ppmntsc: 0 0 0 0
+ppmrelief: 0 0 0 0
+ppmshadow: 0 0 0 0
+ppmshift 2 -seed=1 : 0 0 0 0
+ppmspread 2 -randomseed=1 : 0 0 0 0
+ppmtv 0.5 : 0 0 0 0
diff --git a/test/stdin-ppm1.test b/test/stdin-ppm1.test
new file mode 100755
index 00000000..84614326
--- /dev/null
+++ b/test/stdin-ppm1.test
@@ -0,0 +1,58 @@
+#! /bin/sh
+# This script tests: ppmchange ppmcolormask ppmdim ppmdist ppmdither ppmflash
+# This script tests: ppmglobe ppmhist ppmlabel ppmntsc ppmrelief ppmshadow
+# This script tests: ppmshift ppmspread ppmtv
+# Also requires: ppmpat
+
+tmpdir=${tmpdir:-/tmp}
+test_ppm=${tmpdir}/test.ppm
+out1=${tmpdir}/out1
+out2=${tmpdir}/out2
+
+ppmpat -g2 -color=rgb:00/00/ff,rgb:ff/00/00 -mesh 12 12 > ${test_ppm}
+
+for testprog in  \
+        ppmchange \
+        "ppmcolormask -color=rgb:0/0/ff " \
+        "ppmdim 0.5 " \
+        ppmdist \
+        ppmdither \
+        "ppmflash 0.5 " \
+        "ppmglobe 12 " \
+        ppmhist \
+        ppmlabel \
+        ppmntsc \
+        ppmrelief \
+        ppmshadow \
+        "ppmshift 2 -seed=1 " \
+        "ppmspread 2 -randomseed=1 " \
+        "ppmtv 0.5 "
+  do
+  ${testprog} ${test_ppm} > ${out1};      status1=$?
+  ${testprog} < ${test_ppm} > ${out2};    status2=$?
+  test -s ${out1};                        status3=$?
+  cmp -s ${out1} ${out2}
+  echo ${testprog}": "${status1} ${status2} ${status3} $?
+  rm ${out1} ${out2}
+  done
+
+rm ${test_ppm}
+
+# These utlities do not have a counterpart "ppmto*" program
+
+# Gouldtoppm
+# Imgtoppm
+# Mtvtoppm
+# Pc1toppm
+# Pgmtoppm
+# Qrttoppm
+# Rawtoppm
+# Sldtoppm
+# Spctoppm
+# Ximtoppm
+
+# Tgatoppm -> Pamtotga
+# Xvminitoppm -> Pamtoxvmini
+
+# Ppm3d and Ppmmix require input two files
+# Ppmfade produces a series of output files
diff --git a/test/stdin-ppm2.ok b/test/stdin-ppm2.ok
new file mode 100644
index 00000000..e1335bfb
--- /dev/null
+++ b/test/stdin-ppm2.ok
@@ -0,0 +1,11 @@
+ppmtoacad: 0 0 0 0
+ppmtoapplevol: 0 0 0 0
+ppmtoascii: 0 0 0 0
+ppmtoicr -windowname testimage: 0 0 0 0
+ppmtolj: 0 0 0 0
+ppmtomitsu: 0 0 0 0
+ppmtopgm: 0 0 0 0
+ppmtopuzz: 0 0 0 0
+ppmtosixel: 0 0 0 0
+ppmtoterm: 0 0 0 0
+ppmtoyuvsplit: 0 0 0 0
diff --git a/test/stdin-ppm2.test b/test/stdin-ppm2.test
new file mode 100755
index 00000000..e43b6d4c
--- /dev/null
+++ b/test/stdin-ppm2.test
@@ -0,0 +1,58 @@
+#! /bin/sh
+# This script tests: ppmtoacad ppmtoapplevol ppmtoascii ppmtolj ppmtomitsu
+# This script tests: ppmtopgm ppmtopuzz ppmtosixel ppmtoterm
+# This script tests: ppmtoicr ppmtoyuvsplit
+# Also requires: ppmpat
+
+tmpdir=${tmpdir:-/tmp}
+test_ppm=${tmpdir}/test.ppm
+out1=${tmpdir}/out1
+out2=${tmpdir}/out2
+
+ppmpat -g2 -color=rgb:00/00/ff,rgb:ff/00/00 -mesh 12 12 > ${test_ppm}
+
+# These converters do not have counterparts in the reverse direction
+
+for testprog in  \
+        ppmtoacad \
+        ppmtoapplevol \
+        ppmtoascii \
+        "ppmtoicr -windowname testimage" \
+        ppmtolj \
+        ppmtomitsu \
+        ppmtopgm \
+        ppmtopuzz \
+        ppmtosixel \
+        ppmtoterm
+  do
+  ${testprog} ${test_ppm} > ${out1};      status1=$?
+  ${testprog} < ${test_ppm} > ${out2};    status2=$?
+  test -s ${out1};                        status3=$?
+  cmp -s ${out1} ${out2}
+  echo ${testprog}": "${status1} ${status2} ${status3} $?
+  rm ${out1} ${out2}
+  done
+
+rm ${test_ppm}
+
+testprog=ppmtoyuvsplit
+
+# Produces three output files
+
+  ${testprog} ${tmpdir}/base testgrid.pbm;     status1=$?
+  cat ${tmpdir}/base.Y  ${tmpdir}/base.U  ${tmpdir}/base.V > ${out1}
+  rm ${tmpdir}/base.Y  ${tmpdir}/base.U  ${tmpdir}/base.V
+
+  ${testprog} ${tmpdir}/base < testgrid.pbm;   status2=$?
+  cat ${tmpdir}/base.Y  ${tmpdir}/base.U  ${tmpdir}/base.V > ${out2}
+  rm ${tmpdir}/base.Y  ${tmpdir}/base.U  ${tmpdir}/base.V
+  test -s ${out1};                             status3=$?
+  cmp -s ${out1} ${out2}
+  echo ${testprog}": "${status1} ${status2} ${status3} $?
+  rm ${out1} ${out2}
+
+# Ppmtoppm input is from standard input
+
+# Ppmtoapplevol height must be 12
+# Ppmtoarbtxt needs body template file
+# Ppmtompeg parameter file must be given
diff --git a/test/stdin-ppm3.ok b/test/stdin-ppm3.ok
new file mode 100644
index 00000000..42932e92
--- /dev/null
+++ b/test/stdin-ppm3.ok
@@ -0,0 +1,20 @@
+ppmtobmp: 0 0 0 0
+bmptopnm: 0 0 0 0
+ppmtoilbm: 0 0 0 0
+ilbmtoppm: 0 0 0 0
+ppmtoleaf: 0 0 0 0
+leaftoppm: 0 0 0 0
+ppmtoneo: 0 0 0 0
+neotoppm: 0 0 0 0
+ppmtopcx: 0 0 0 0
+pcxtoppm: 0 0 0 0
+ppmtopi1: 0 0 0 0
+pi1toppm: 0 0 0 0
+ppmtopict: 0 0 0 0
+picttoppm: 0 0 0 0
+ppmtopj: 0 0 0 0
+pjtoppm: 0 0 0 0
+ppmtospu: 0 0 0 0
+sputoppm: 0 0 0 0
+ppmtoxpm -name small: 0 0 0 0
+xpmtoppm: 0 0 0 0
diff --git a/test/stdin-ppm3.test b/test/stdin-ppm3.test
new file mode 100755
index 00000000..064e3e22
--- /dev/null
+++ b/test/stdin-ppm3.test
@@ -0,0 +1,75 @@
+o#! /bin/sh
+# This script tests: ppmtobmp bmptopnm
+# This script tests: ppmtoilbm ilbmtoppm
+# This script tests: ppmtoleaf leaftoppm
+# This script tests: ppmtoneo neotoppm
+# This script tests: ppmtopcx pcxtoppm
+# This script tests: ppmtopi1 pi1toppm
+# This script tests: ppmtopict picttoppm
+# This script tests: ppmtopj pjtoppm
+# This script tests: ppmtospu sputoppm
+# This script tests: ppmtoxpm xpmtoppm
+# Also requires: ppmmake
+
+tmpdir=${tmpdir:-/tmp}
+small_ppm=${tmpdir}/small.ppm
+large_ppm=${tmpdir}/large.ppm
+out1=${tmpdir}/out1
+out2=${tmpdir}/out2
+out3=${tmpdir}/out3
+out4=${tmpdir}/out4
+
+ppmmake -maxval 65535 rgb:00/00/00 8 3 > ${small_ppm}
+ppmmake -maxval 7 rgb:00/00/00 320 200 > ${large_ppm}
+
+for fmt in \
+        bmp \
+        ilbm \
+        leaf \
+        neo \
+        pcx \
+        pi1 \
+        pict \
+        pj \
+        spu \
+        xpm
+do
+  if [ ${fmt} = "xpm" ]
+    then testprog1="ppmto${fmt} -name small";
+  else 	 testprog1="ppmto${fmt}";
+  fi
+  if [ ${fmt} = "bmp" ]
+    then testprog2=${fmt}"topnm";
+  else   testprog2=${fmt}"toppm";
+  fi
+
+  if [ ${fmt} = "spu" ]
+    then test_ppm=${large_ppm};
+  else   test_ppm=${small_ppm};
+  fi
+
+  ${testprog1} ${test_ppm} > ${out1};    status1=$?
+  ${testprog1} < ${test_ppm} > ${out2};  status2=$?
+  test -s ${out1};                       status3=$?
+  cmp -s ${out1} ${out2}
+  echo ${testprog1}": "${status1} ${status2} ${status3} $?
+  rm ${out2}
+
+  ${testprog2} ${out1} > ${out3};      status4=$?
+  ${testprog2} < ${out1} > ${out4};    status5=$?
+  test -s ${out1};                     status6=$?
+  cmp -s ${out3} ${out4}
+  echo ${testprog2}": "${status4} ${status5} ${status6} $?
+  rm ${out1} ${out3} ${out4}
+  done
+
+rm ${small_ppm} ${large_ppm}
+
+# ppmtopict width must be 8 or more
+
+# ppmtospu sputoppm width=320 height=200 fixed
+
+# Eyuvtoppm, Yuvtoppm width, height are mandatory
+
+# Ppmtowinicon Winicontoppm legacy
+# Winicontoppm max size 255 255
diff --git a/test/sunicon-roundtrip.ok b/test/sunicon-roundtrip.ok
index 845be5fb..8bfdc3a0 100644
--- a/test/sunicon-roundtrip.ok
+++ b/test/sunicon-roundtrip.ok
@@ -1 +1,4 @@
-2425386270 41
+Test.  Should print 0 three times
+0
+0
+0
diff --git a/test/sunicon-roundtrip.test b/test/sunicon-roundtrip.test
index a52fda68..38513ea8 100755
--- a/test/sunicon-roundtrip.test
+++ b/test/sunicon-roundtrip.test
@@ -1,8 +1,26 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pbmtosunicon sunicontopnm
-# Also requires: pamcut
+# Also requires: pbmnoise
 
-# Width of Sun icons are multiples of 8.
+# Width of a Sun icon is always a multiple of 8.
 
-# Test.  Should print: 2425386270 41
-pbmtosunicon testgrid.pbm | sunicontopnm | pamcut 1 0 14 16 | cksum
+tmpdir=${tmpdir:-/tmp}
+
+noise16_pbm=${tmpdir}/noise16.pbm
+noise32_pbm=${tmpdir}/noise32.pbm
+noise64_pbm=${tmpdir}/noise64.pbm
+
+echo "Test.  Should print 0 three times"
+pbmnoise -randomseed=1 16 16 > ${noise16_pbm} && \
+  pbmtosunicon ${noise16_pbm} | sunicontopnm | cmp -s - ${noise16_pbm}
+  echo $?
+
+pbmnoise -randomseed=1 32 32 > ${noise32_pbm} && \
+  pbmtosunicon ${noise32_pbm} | sunicontopnm | cmp -s - ${noise32_pbm}
+  echo $?
+
+pbmnoise -randomseed=1 64 64 > ${noise64_pbm} && \
+  pbmtosunicon ${noise64_pbm} | sunicontopnm | cmp -s - ${noise64_pbm}
+  echo $?
+
+rm ${noise16_pbm} ${noise32_pbm} ${noise64_pbm}
\ No newline at end of file
diff --git a/test/sunrast-roundtrip.test b/test/sunrast-roundtrip.test
index a5cfa8c7..dfe68402 100755
--- a/test/sunrast-roundtrip.test
+++ b/test/sunrast-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pnmtorast rasttopnm
 # Also requires:
 
diff --git a/test/symmetry.ok b/test/symmetry.ok
index a5945014..111f09cf 100644
--- a/test/symmetry.ok
+++ b/test/symmetry.ok
@@ -1,5 +1,8 @@
+Test 1.
 ok
+Test 2.
 ok
+Test 3.  Should print ok 7 times
 ok
 ok
 ok
@@ -7,7 +10,9 @@ ok
 ok
 ok
 ok
+Test 4.
 ok
+Test 5.  Should print ok 7 times.
 ok
 ok
 ok
@@ -15,4 +20,5 @@ ok
 ok
 ok
 ok
+Test 6.
 ok
diff --git a/test/symmetry.test b/test/symmetry.test
index 52ba6388..3c495778 100755
--- a/test/symmetry.test
+++ b/test/symmetry.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pgmramp pamgauss pgmkernel pbmmake pbmpscale
 # Also requires: pamflip
 
@@ -25,7 +25,7 @@
 
 tmpdir=${tmpdir:-/tmp}
 
-# Test 1.
+echo "Test 1."
 rect_pgm=${tmpdir}/rect.pgm
 
 pgmramp -rect 31 31 > ${rect_pgm}
@@ -37,7 +37,8 @@ pgmramp -rect 31 31 > ${rect_pgm}
 
 rm ${rect_pgm}
 
-# Test 2.
+
+echo "Test 2."
 circle_pgm=${tmpdir}/circle.pgm
 pgmramp -ell 63 63 > ${circle_pgm}
 
@@ -48,7 +49,8 @@ pgmramp -ell 63 63 > ${circle_pgm}
 
 rm ${circle_pgm}
 
-# Test 3.  Should print "ok" 7 times
+
+echo "Test 3.  Should print ok 7 times"
 gauss_pgm=${tmpdir}/gauss.pgm
 for size in 3 4 5 8 13 21 25
 do
@@ -63,7 +65,7 @@ rm ${gauss_pgm}
 done
 
 
-# Test 4.
+echo "Test 4."
 kernel_pgm=${tmpdir}/kernel.pgm
 pgmkernel 15 15 > ${kernel_pgm}
 
@@ -74,12 +76,12 @@ pgmkernel 15 15 > ${kernel_pgm}
 
 rm ${kernel_pgm}
 
-# Test 5.
-# Should print "ok" 7 times.
+
+echo "Test 5.  Should print ok 7 times."
 pscale_pbm=${tmpdir}/pscale.pbm
-for size in `seq 1 7`
-do
-pbmmake -g 5 5 | pbmpscale $size > ${pscale_pbm}
+for size in 1 2 3 4 5 6 7  # for size in `seq 7`
+  do
+  pbmmake -g 5 5 | pbmpscale ${size} > ${pscale_pbm}
 
 ( for op in -null -tb -lr -r90
     do pamflip $op ${pscale_pbm} | cksum
@@ -89,7 +91,8 @@ pbmmake -g 5 5 | pbmpscale $size > ${pscale_pbm}
 rm ${pscale_pbm}
 done
 
-# Test 6.
+
+echo "Test 6."
 ell_pgm=${tmpdir}/ell.pgm
 pgmramp -ell 101 33 > ${ell_pgm}
 
diff --git a/test/targa-roundtrip.ok b/test/targa-roundtrip.ok
index 514f970f..beb6700e 100644
--- a/test/targa-roundtrip.ok
+++ b/test/targa-roundtrip.ok
@@ -1,15 +1,15 @@
-Test 1
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-2425386270 41
-Test 2
+Test 1:  Should print 281226646 481 ten times
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+281226646 481
+Test 2:  Should produce 1571496937 33838 ten times
 1571496937 33838
 1571496937 33838
 1571496937 33838
@@ -20,19 +20,19 @@ Test 2
 1571496937 33838
 1571496937 33838
 1571496937 33838
-Test 3
+Test 3.  Should print 1926073387 101484 four times
 1926073387 101484
 1926073387 101484
 1926073387 101484
 1926073387 101484
-Test 4
+Test 4.  Should print 0 0 0 : 0 six times
 0 0 0 : 0
 0 0 0 : 0
 0 0 0 : 0
 0 0 0 : 0
 0 0 0 : 0
 0 0 0 : 0
-Test 5
+Test 4.  Should print 0 0 0 : 0 twice, then 0 0 0 0 : 0 six times
 0 0 0 : 0
 0 0 0 : 0
 0 0 0 0 : 0
diff --git a/test/targa-roundtrip.test b/test/targa-roundtrip.test
index 79b01b61..2dd04e91 100755
--- a/test/targa-roundtrip.test
+++ b/test/targa-roundtrip.test
@@ -4,25 +4,21 @@
 
 tmpdir=${tmpdir:-/tmp}
 
-#Test 1: Should print 2425386270 41, cksum of testgrid.pbm, ten times
-
-echo "Test 1"
+echo "Test 1:  Should print 281226646 481 ten times"
 
 for mode in "-mono" "-mono -norle" \
             "-cmap" "-cmap -norle" "-cmap16" "-cmap16 -norle" \
             "-rgb"  "-rgb  -norle" "" "-norle"
   do
-  pamtotga ${mode} testgrid.pbm | \
+  pamtotga ${mode} maze.pbm | \
     tgatoppm | ppmtopgm | \
     pgmtopbm -threshold -val 0.5 | cksum
   done
 
-#Test 2:  Should produce 1571496937 33838, cksum of testimg.red, ten times
-
-echo "Test 2"
+echo "Test 2:  Should produce 1571496937 33838 ten times"
 
 test_pam=${tmpdir}/testimg.pgm
-pamchannel -infile=testimg.ppm -tupletype="GRAYSCALE" 0 > ${test_pam}
+pamchannel -infile=testimg.ppm -tupletype="GRAYSCALE" 0 > ${test_pam} 
 
 for mode in "-mono" "-mono -norle" \
             "-cmap" "-cmap -norle" "-cmap16" "-cmap16 -norle" \
@@ -33,19 +29,14 @@ for mode in "-mono" "-mono -norle" \
 
 rm ${test_pam}
 
-
-#Test 3: Should print 1926073387 101484, cksum of testimg.ppm, four times
-
-echo "Test 3"
+echo "Test 3.  Should print 1926073387 101484 four times"
 
 for mode in "-rgb" "-rgb -norle" "" "-norle"
   do
   pamtotga ${mode} testimg.ppm | tgatoppm | cksum
   done
 
-#Test 4: Should print 0 six times
-
-echo "Test 4"
+echo "Test 4.  Should print 0 0 0 : 0 six times"
 
 test256_ppm=${tmpdir}/test256.ppm
 pnmquant 256 testimg.ppm > ${test256_ppm} || echo "pnmquant failed"
@@ -57,10 +48,7 @@ for mode in "-rgb" "-rgb -norle" "-cmap" "-cmap -norle" "" "-norle"
   echo ${PIPESTATUS[@]} ":" $?
 done
 
-
-#Test 5: Should print 0 eight times
-
-echo "Test 5"
+echo "Test 4.  Should print 0 0 0 : 0 twice, then 0 0 0 0 : 0 six times"
 
 test256_31_ppm=${tmpdir}/test256-31.ppm
 pamdepth 31 ${test256_ppm} > ${test256_31_ppm} || echo "pamdepth failed"
diff --git a/test/tiff-flate-lzw-roundtrip.ok b/test/tiff-flate-lzw-roundtrip.ok
index 4d5597cc..b3b0e1e7 100644
--- a/test/tiff-flate-lzw-roundtrip.ok
+++ b/test/tiff-flate-lzw-roundtrip.ok
@@ -1,7 +1,9 @@
+Test 1.  Should print 1079668603 10237 six times
 1079668603 10237
 1079668603 10237
 1079668603 10237
 1079668603 10237
 1079668603 10237
 1079668603 10237
-2425386270 41
+Test 2.  Should print 281226646 481
+281226646 481
diff --git a/test/tiff-flate-lzw-roundtrip.test b/test/tiff-flate-lzw-roundtrip.test
index 59d4c483..2b0a4536 100755
--- a/test/tiff-flate-lzw-roundtrip.test
+++ b/test/tiff-flate-lzw-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamtotiff tifftopnm
 # Also requires: ppmpat
 
@@ -8,11 +8,11 @@
 ## features.
 
 tmpdir=${tmpdir:-/tmp}
-
 tartan_ppm=${tmpdir}/testimg40.ppm
 
 # Make a test image with reduced colors which compresses better
-# cksum is 1079668603 10237
+
+echo "Test 1.  Should print 1079668603 10237 six times"
 
 ppmpat -tartan --color=rgb:32/0d/b7,rgb:31/58/a3,rgb:e9/5e/d4 71 48 | \
   tee ${tartan_ppm} | cksum
@@ -28,7 +28,9 @@ pamtotiff -adobeflate ${tartan_ppm} | tifftopnm | cksum
 pamtotiff -lzw ${tartan_ppm} | tifftopnm | cksum
 pamtotiff -lzw -predictor=1 ${tartan_ppm} | tifftopnm | cksum
 
-# PBM image: test flate compression
-pamtotiff -flate testgrid.pbm | tifftopnm | cksum
-
 rm ${tartan_ppm}
+
+echo "Test 2.  Should print 281226646 481"
+
+# PBM image: test flate compression
+pamtotiff -flate maze.pbm | tifftopnm | cksum
diff --git a/test/tiff-roundtrip.ok b/test/tiff-roundtrip.ok
index 14258de2..dec662ed 100644
--- a/test/tiff-roundtrip.ok
+++ b/test/tiff-roundtrip.ok
@@ -1,36 +1,36 @@
-PPM-rose
+Test 1:PPM-rose  Should print 1926073387 101484 five times
 1926073387 101484
 1926073387 101484
 1926073387 101484
 1926073387 101484
 1926073387 101484
-PPM-6
+Test 2:PPM-6  Should print 1646869394 29498 four times
 1646869394 29498
 1646869394 29498
 1646869394 29498
 1646869394 29498
-PPM-2
+Test 3:PPM-2  Should print 3743909631 14836 four times
 3743909631 14836
 3743909631 14836
 3743909631 14836
 3743909631 14836
-PPM-gray
+Test 4:PPM-gray  Should print 603974118 4954 six times
 603974118 4954
 603974118 4954
 603974118 4954
 603974118 4954
 603974118 4954
 603974118 4954
-PPM-bilevel-black-white
+Test 5:PPM-bilevel-black-white  Should print 1001018459 4954 four times
 1001018459 4954
 1001018459 4954
 1001018459 4954
 1001018459 4954
-PBM
-2425386270 41
-2425386270 41
-2425386270 41
-Extract from multi-image TIFF
+Test 6:PBM  Should print 281226646 481 three times
+281226646 481
+281226646 481
+281226646 481
+Test 7:Extract from multi-image TIFF
 1926073387 101484
 1646869394 29498
 3743909631 14836
diff --git a/test/tiff-roundtrip.test b/test/tiff-roundtrip.test
index 55aba278..c33ee904 100755
--- a/test/tiff-roundtrip.test
+++ b/test/tiff-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamtotiff tifftopnm
 # Also requires: ppmpat pampick ppmtopgm
 
@@ -13,9 +13,8 @@ argylegray_ppm=${tmpdir}/argyle2.ppm
 multiimage_tiff=${tmpdir}/multiimage.ppm
 
 # PPM image
-# Should print 1926073387 101484 five times
 
-echo PPM-rose
+echo "Test 1:PPM-rose  Should print 1926073387 101484 five times"
 pamtotiff testimg.ppm | tifftopnm -headerdump | cksum
 pamtotiff -truecolor testimg.ppm -output ${multiimage_tiff} && \
   tifftopnm ${multiimage_tiff} -byrow | cksum
@@ -25,9 +24,8 @@ pamtotiff -truecolor -lsb2msb  testimg.ppm | \
   tifftopnm -respectfillorder | cksum
 
 # PPM image with six colors
-# Should print 1646869394 29498 four times
 
-echo PPM-6
+echo "Test 2:PPM-6  Should print 1646869394 29498 four times"
 ppmpat -tartan -color=rgb:0/8/8,rgb:8/f/8,rgb:f/f/0 108 91 | \
   tee ${tartan_ppm} | cksum
 pamtotiff -truecolor ${tartan_ppm} | tifftopnm | cksum
@@ -37,12 +35,12 @@ pamtotiff ${tartan_ppm} -append -output ${multiimage_tiff} && \
 
 
 # PPM image with two colors
-# Should print 3743909631 14836 four times
 
-echo PPM-2
+echo "Test 3:PPM-2  Should print 3743909631 14836 four times"
 ppmpat -argyle2 -color=rgb:0/0/0,rgb:f/8/f,rgb:0/0/0 61 81 | \
   tee ${argylecolor_ppm} | cksum
-pamtotiff -indexbits=2 ${argylecolor_ppm} -append -output ${multiimage_tiff} && \
+pamtotiff -indexbits=2 ${argylecolor_ppm} -append \
+  -output ${multiimage_tiff} && \
   tifftopnm ${multiimage_tiff} | pampick 2 | cksum
 pamtotiff -indexbits=1 ${argylecolor_ppm} | tifftopnm | cksum
 pamtotiff -indexbits=1 -g4 ${argylecolor_ppm} | tifftopnm | cksum
@@ -51,9 +49,8 @@ pamtotiff -indexbits=1 -g4 ${argylecolor_ppm} | tifftopnm | cksum
 # pamtotiff detects the absence of colors and produces a grayscale
 # tiff image unless -color is specified
 # Pipeline output is PGM unless -color is specified
-# Should print 603974118 4954 six times
 
-echo PPM-gray
+echo "Test 4:PPM-gray  Should print 603974118 4954 six times"
 ppmpat -gingham3 -color=rgb:0/0/0,rgb:ff/ff/ff,rgb:0/0/0 61 81 | \
   tee ${gingham_ppm} | ppmtopgm | cksum
 pamtotiff -color ${gingham_ppm} | tifftopnm | cksum
@@ -67,9 +64,8 @@ pamtotiff -mb ${gingham_ppm} -append -output ${multiimage_tiff} && \
 # pamtotiff detects the absence of colors and produces a grayscale
 # tiff image unless -color is specified
 # Pipeline output is PGM unless -color is specified
-# Should print 1001018459 4954 four times
 
-echo PPM-bilevel-black-white
+echo "Test 5:PPM-bilevel-black-white  Should print 1001018459 4954 four times"
 ppmpat -argyle2 -color=rgb:0/0/0,rgb:ff/ff/ff,rgb:0/0/0 61 81 | \
   tee ${argylegray_ppm} | ppmtopgm | cksum
 pamtotiff -color -fill ${argylegray_ppm} | tifftopnm | cksum
@@ -78,17 +74,17 @@ pamtotiff -mb ${argylegray_ppm} -append -output ${multiimage_tiff} && \
   tifftopnm ${multiimage_tiff} | pampick 4 | cksum
 
 # PBM image
-# Should print 2425386270 41 three times
 
-echo PBM
-pamtotiff testgrid.pbm | tifftopnm | cksum
-pamtotiff -g3 -fill testgrid.pbm | tifftopnm | cksum
-pamtotiff -g4 -mb testgrid.pbm -append -output ${multiimage_tiff} && \
+
+echo "Test 6:PBM  Should print 281226646 481 three times"
+pamtotiff maze.pbm | tifftopnm | cksum
+pamtotiff -g3 -fill maze.pbm | tifftopnm | cksum
+pamtotiff -g4 -mb maze.pbm -append -output ${multiimage_tiff} && \
   tifftopnm ${multiimage_tiff} | pampick 5 | cksum
 
 # Extract individual images from multi-image tiff file
 
-echo "Extract from multi-image TIFF"
+echo "Test 7:Extract from multi-image TIFF"
 tifftopnm ${multiimage_tiff} | pampick 0 | cksum
 tifftopnm ${multiimage_tiff} | pampick 1 | cksum
 tifftopnm ${multiimage_tiff} | pampick 2 | cksum
diff --git a/test/tiffcmyk-roundtrip.test b/test/tiffcmyk-roundtrip.test
index 133c81b7..ebbc5666 100755
--- a/test/tiffcmyk-roundtrip.test
+++ b/test/tiffcmyk-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pnmtotiffcmyk tifftopnm
 # Also requires: pnmpsnr
 
diff --git a/test/utahrle-roundtrip.test b/test/utahrle-roundtrip.test
index 17f1a6c4..4dce0b40 100755
--- a/test/utahrle-roundtrip.test
+++ b/test/utahrle-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pnmtorle rletopnm
 # Also requires: pamchannel pamtopnm
 
diff --git a/test/wbmp-roundtrip.ok b/test/wbmp-roundtrip.ok
index 845be5fb..5168378d 100644
--- a/test/wbmp-roundtrip.ok
+++ b/test/wbmp-roundtrip.ok
@@ -1 +1 @@
-2425386270 41
+281226646 481
diff --git a/test/wbmp-roundtrip.test b/test/wbmp-roundtrip.test
index b651c3d0..cf747487 100755
--- a/test/wbmp-roundtrip.test
+++ b/test/wbmp-roundtrip.test
@@ -1,7 +1,7 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pbmtowbmp wbmptopbm
 # Also requires:
 
 
-# Should print 2425386270 41, cksum of testgrid.pbm
-pbmtowbmp testgrid.pbm | wbmptopbm | cksum
+# Should print 281226646 481, cksum of maze.pbm
+pbmtowbmp maze.pbm | wbmptopbm | cksum
diff --git a/test/winicon-roundtrip.ok b/test/winicon-roundtrip.ok
index 8334ff4e..73e5030c 100644
--- a/test/winicon-roundtrip.ok
+++ b/test/winicon-roundtrip.ok
@@ -1,2 +1,12 @@
-71846281 6925
-326197919 137
+Test 1. Should print 4241318573 6973 four times
+4241318573 6973
+4241318573 6973
+4241318573 6973
+4241318573 6973
+Test 1. Should print 1009647580 1093 six times
+1009647580 1093
+1009647580 1093
+1009647580 1093
+1009647580 1093
+1009647580 1093
+1009647580 1093
diff --git a/test/winicon-roundtrip.test b/test/winicon-roundtrip.test
index b37a33e1..31fb89aa 100755
--- a/test/winicon-roundtrip.test
+++ b/test/winicon-roundtrip.test
@@ -1,13 +1,39 @@
-#! /bin/bash
-# This script tests: pamtowinicon winicontopam
-# Also requires: pamcut pnmtile pamtopnm ppmtopgm pgmtopbm
+#! /bin/sh
+# This script tests: pamtowinicon ppmtowinicon winicontopam
+# Also requires: pamchannel pamcut pamdepth pamtopam
+# Also requires: pngtopam pnmtopng
 
+tmpdir=${tmpdir:-/tmp}
+test_pam=${tmpdir}/testimg.pam
 
-pamcut --left=30 --width=48 --height=48 testimg.ppm | \
-pamtowinicon | winicontopam | \
-  pamtopnm | cksum
+echo "Test 1. Should print 4241318573 6973 four times"
 
-pnmtile 32 32 testgrid.pbm | \
-pamtowinicon | winicontopam | \
-  pamtopnm | ppmtopgm | \
-  pgmtopbm  -th -val=0.5 | cksum
+pamcut --left=30 --width=48 --height=48 testimg.ppm | pamtopam | \
+  tee ${test_pam} | cksum
+pamtowinicon ${test_pam} | winicontopam | \
+  pamchannel -tupletype="RGB" 0 1 2 | cksum
+pamtowinicon -pngthreshold=300 ${test_pam} | winicontopam | \
+  pamchannel -tupletype="RGB" 0 1 2 | cksum
+pamtowinicon -pngthreshold=1   ${test_pam} | winicontopam | \
+  pamchannel -tupletype="RGB" 0 1 2 | cksum
+
+rm ${test_pam}
+
+echo "Test 1. Should print 1009647580 1093 six times"
+
+pamcut -top=0 -left=0 -width=32 -height=32 maze.pbm | pamtopam | \
+  tee ${test_pam} | cksum
+pamtowinicon ${test_pam} | winicontopam | \
+  pamdepth 1 | pamchannel -tupletype="BLACKANDWHITE" 0 | cksum
+pamtowinicon -pngthreshold=300 ${test_pam} | winicontopam | \
+  pamdepth 1 | pamchannel -tupletype="BLACKANDWHITE" 0 | cksum
+pamtowinicon -pngthreshold=1   ${test_pam} | winicontopam | 
+  pamdepth 1 | pamchannel -tupletype="BLACKANDWHITE" 0 | cksum
+pamtowinicon -pngthreshold=1   ${test_pam} | winicontopam | 
+  pamchannel -tupletype="BLACKANDWHITE" 0 | cksum
+
+rm ${test_pam}
+
+pamcut -top=0 -left=0 -width=32 -height=32 maze.pbm | \
+  ppmtowinicon | winicontopam | \
+  pamdepth 1 | pamchannel -tupletype="BLACKANDWHITE" 0 | cksum
diff --git a/test/winicon-roundtrip2.ok b/test/winicon-roundtrip2.ok
new file mode 100644
index 00000000..54ba54e6
--- /dev/null
+++ b/test/winicon-roundtrip2.ok
@@ -0,0 +1,82 @@
+Should print: former checksum values
+16 24 32 48 64 : 1 plane
+Should print 2588356089 8591 or 3783949470 69390 four times
+2588356089 8591
+2588356089 8591
+2588356089 8591
+2588356089 8591
+16 24 32 48 64 : 2 planes
+Should print 3357739334 16877 or 3331485515 138534 four times
+3357739334 16877
+3357739334 16877
+3357739334 16877
+3357739334 16877
+16 24 32 48 64 : 3 planes
+Should print 3734212737 25073 or 56221695 207606 four times
+3734212737 25073
+3734212737 25073
+3734212737 25073
+3734212737 25073
+16 24 32 48 64 : 4 planes
+Should print 1294260080 33359 or 732184466 276750 four times
+1294260080 33359
+1294260080 33359
+1294260080 33359
+1294260080 33359
+16 24 32 48 64 : 5 planes: output 3
+Should print 3734212737 25073 or 56221695 207606 four times
+3734212737 25073
+3734212737 25073
+3734212737 25073
+3734212737 25073
+16 24 32 48 64 : 5 planes : output 4
+Should print 2704877198 33359 or 1699833476 276750 four times
+2704877198 33359
+2704877198 33359
+2704877198 33359
+2704877198 33359
+16 24 32 48 64 : 5 planes : output 5
+Should print 2567279592 41655 or 4154838752 345902 twice
+2567279592 41655
+2567279592 41655
+Should print: latter checksum values
+16 32 48 256 : 1 plane
+Should print 2588356089 8591 or 3783949470 69390 four times
+3783949470 69390
+3783949470 69390
+3783949470 69390
+3783949470 69390
+16 32 48 256 : 2 planes
+Should print 3357739334 16877 or 3331485515 138534 four times
+3331485515 138534
+3331485515 138534
+3331485515 138534
+3331485515 138534
+16 32 48 256 : 3 planes
+Should print 3734212737 25073 or 56221695 207606 four times
+56221695 207606
+56221695 207606
+56221695 207606
+56221695 207606
+16 32 48 256 : 4 planes
+Should print 1294260080 33359 or 732184466 276750 four times
+732184466 276750
+732184466 276750
+732184466 276750
+732184466 276750
+16 32 48 256 : 5 planes: output 3
+Should print 3734212737 25073 or 56221695 207606 four times
+56221695 207606
+56221695 207606
+56221695 207606
+56221695 207606
+16 32 48 256 : 5 planes : output 4
+Should print 2704877198 33359 or 1699833476 276750 four times
+1699833476 276750
+1699833476 276750
+1699833476 276750
+1699833476 276750
+16 32 48 256 : 5 planes : output 5
+Should print 2567279592 41655 or 4154838752 345902 twice
+4154838752 345902
+4154838752 345902
diff --git a/test/winicon-roundtrip2.test b/test/winicon-roundtrip2.test
new file mode 100755
index 00000000..de40446e
--- /dev/null
+++ b/test/winicon-roundtrip2.test
@@ -0,0 +1,154 @@
+#! /bin/sh
+# This script tests: pamtowinicon winicontopam
+# Also requires: pamchannel pamdepth pamstack pamtopam pbmmake ppmpat
+# Also requires: pngtopam pnmtopng
+
+tmpdir=${tmpdir:-/tmp}
+test_pam=${tmpdir}/testimg.pam
+test1_pam=${tmpdir}/testimg1.pam
+test2_pam=${tmpdir}/testimg2.pam
+
+test4_pam=${tmpdir}/testimg4.pam
+test5_pam=${tmpdir}/testimg5.pam
+black_pam=${tmpdir}/black.pam
+white_pam=${tmpdir}/white.pam
+gray_pam=${tmpdir}/gray.pam
+
+# classic: 16 24 32 48 64
+# full: 16 32 48 256
+
+for sizes in "16 24 32 48 64" "16 32 48 256"
+  do
+  if  echo $sizes | awk '{exit !($NF==64)}' ;
+  then echo "Should print: former checksum values";
+  else echo "Should print: latter checksum values";
+  fi
+
+  for size in ${sizes}
+    do
+    ppmpat -tartan -color=rgb:1f/1f/1f,rgb:7f/ff/00,rgb:00/ff/3f \
+      ${size} ${size}
+    done | pamtopam > ${test_pam}
+
+  for size in ${sizes}
+    do
+    pbmmake -black ${size} ${size} | pamdepth 255
+    done | pamtopam > ${black_pam}
+
+  for size in ${sizes}
+    do
+    pbmmake -white ${size} ${size} | pamdepth 255
+    done | pamtopam > ${white_pam}
+
+  for size in ${sizes}
+    do
+    pbmmake -gray ${size} ${size} | pamdepth 255
+    done | pamtopam > ${gray_pam}
+
+# 1 plane
+
+  echo ${sizes} ": 1 plane"
+  echo "Should print 2588356089 8591 or 3783949470 69390 four times"
+
+  pamchannel -tupletype="GRAYSCALE" 0 < ${test_pam} | \
+    tee ${test1_pam} | cksum
+  pamtowinicon ${test1_pam} | winicontopam -allimages | \
+    pamchannel -tupletype="GRAYSCALE" 0 | cksum
+  pamtowinicon -pngthreshold=300 ${test1_pam} | winicontopam -allimages | \
+    pamchannel -tupletype="GRAYSCALE" 0 | cksum
+  pamtowinicon -pngthreshold=1   ${test1_pam} | winicontopam -allimages | \
+    pamchannel -tupletype="GRAYSCALE" 0 | cksum
+
+  rm ${test1_pam}
+
+# 2 planes
+
+  echo ${sizes} ": 2 planes"
+  echo "Should print 3357739334 16877 or 3331485515 138534 four times"
+
+  pamstack ${gray_pam} ${gray_pam} | \
+  pamchannel -tupletype="GRAYSCALE_ALPHA" 0 1 | tee ${test2_pam} | cksum
+  pamtowinicon ${test2_pam} | winicontopam -allimages | \
+    pamchannel -tupletype="GRAYSCALE_ALPHA" 0 1 | pamdepth 255 | cksum
+  pamtowinicon -pngthreshold=300 ${test2_pam} | winicontopam -allimages | \
+    pamchannel -tupletype="GRAYSCALE_ALPHA" 0 1 | cksum
+  pamtowinicon -pngthreshold=1   ${test2_pam} | winicontopam -allimages | \
+    pamchannel -tupletype="GRAYSCALE_ALPHA" 0 1 | pamdepth 255 | cksum
+
+  rm ${test2_pam}
+
+# 3 planes
+
+  echo ${sizes} ": 3 planes"
+  echo "Should print 3734212737 25073 or 56221695 207606 four times"
+
+  pamchannel -tupletype="RGB" 0 1 2 < ${test_pam} | cksum
+  pamtowinicon ${test_pam} | winicontopam -allimages | \
+    pamchannel -tupletype="RGB" 0 1 2 | cksum
+  pamtowinicon -pngthreshold=300 ${test_pam} | winicontopam -allimages | \
+    pamchannel -tupletype="RGB" 0 1 2 | cksum
+  pamtowinicon -pngthreshold=1   ${test_pam} | winicontopam -allimages | \
+    pamchannel -tupletype="RGB" 0 1 2 | cksum
+  
+# 4 planes
+
+  echo ${sizes} ": 4 planes"
+  echo "Should print 1294260080 33359 or 732184466 276750 four times"
+
+  pamdepth 255 ${black_pam} | pamstack ${test_pam} - | \
+  pamchannel -tupletype="RGB_ALPHA" 0 1 2 3 | tee ${test4_pam} | cksum
+  pamtowinicon ${test4_pam} | winicontopam -allimages | \
+    pamchannel -tupletype="RGB_ALPHA" 0 1 2 3 | cksum
+  pamtowinicon -pngthreshold=300 ${test4_pam} | winicontopam -allimages | \
+    pamchannel -tupletype="RGB_ALPHA" 0 1 2 3 | cksum
+  pamtowinicon -pngthreshold=1   ${test4_pam} | winicontopam -allimages | \
+    pamchannel -tupletype="RGB_ALPHA" 0 1 2 3 | cksum
+
+  rm ${test4_pam}
+
+# 5 planes
+
+  echo ${sizes} ": 5 planes: output 3"
+  echo "Should print 3734212737 25073 or 56221695 207606 four times"
+
+  pamstack ${test_pam} ${gray_pam} ${white_pam} | \
+  pamchannel -tupletype="RGB" 0 1 2 | \
+    tee ${test5_pam} | cksum
+  pamtowinicon ${test5_pam} | winicontopam -allimages -andmasks | \
+    pamchannel -tupletype="RGB" 0 1 2 | cksum
+  pamtowinicon -pngthreshold=300 ${test5_pam} | \
+    winicontopam -allimages -andmasks | \
+    pamchannel -tupletype="RGB" 0 1 2 | cksum
+  pamtowinicon -pngthreshold=1   ${test5_pam} | \
+    winicontopam -allimages -andmasks | \
+    pamchannel -tupletype="RGB" 0 1 2 | cksum
+    
+  echo ${sizes} ": 5 planes : output 4"
+  echo "Should print 2704877198 33359 or 1699833476 276750 four times"
+
+  pamstack ${test_pam} ${gray_pam} ${white_pam} | \
+  pamchannel -tupletype="RGB_ALPHA" 0 1 2 3 | \
+    tee ${test5_pam} | cksum
+  pamtowinicon ${test5_pam} | winicontopam -allimages -andmasks | \
+    pamchannel -tupletype="RGB_ALPHA" 0 1 2 3 | cksum
+  pamtowinicon -pngthreshold=300 ${test5_pam} | \
+    winicontopam -allimages -andmasks  | \
+    pamchannel -tupletype="RGB_ALPHA" 0 1 2 3 | cksum
+  pamtowinicon -pngthreshold=1   ${test5_pam} | \
+    winicontopam -allimages -andmasks | \
+    pamchannel -tupletype="RGB_ALPHA" 0 1 2 3 | cksum
+    
+  echo ${sizes} ": 5 planes : output 5"
+  echo "Should print 2567279592 41655 or 4154838752 345902 twice"
+
+  pamstack ${test_pam} ${gray_pam} ${white_pam} | \
+  pamchannel -tupletype="RGB_ALPHA_ANDMASK" 0 1 2 3 4 | \
+    tee ${test5_pam} | cksum
+  pamtowinicon -pngthreshold=300 ${test5_pam} | \
+    winicontopam -allimages -andmasks  | \
+    pamchannel -tupletype="RGB_ALPHA_ANDMASK" 0 1 2 3 4 | cksum
+    
+  rm ${test5_pam}
+
+  rm ${test_pam} ${gray_pam} ${white_pam} ${black_pam}
+done
diff --git a/test/xbm-roundtrip.ok b/test/xbm-roundtrip.ok
index a676a1f2..82c6b5d8 100644
--- a/test/xbm-roundtrip.ok
+++ b/test/xbm-roundtrip.ok
@@ -1,2 +1,3 @@
-2425386270 41
-2425386270 41
+Test.  Should print 281226646 481 twice
+281226646 481
+281226646 481
diff --git a/test/xbm-roundtrip.test b/test/xbm-roundtrip.test
index e84d6fc3..a8754150 100755
--- a/test/xbm-roundtrip.test
+++ b/test/xbm-roundtrip.test
@@ -1,7 +1,8 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pbmtoxbm xbmtopbm
 # Also requires:
 
+echo "Test.  Should print 281226646 481 twice"
 
-pbmtoxbm testgrid.pbm | xbmtopbm | cksum
-pbmtoxbm -x10 testgrid.pbm | xbmtopbm | cksum
+pbmtoxbm maze.pbm | xbmtopbm | cksum
+pbmtoxbm -x10 < maze.pbm | xbmtopbm | cksum
diff --git a/test/xpm-roundtrip.ok b/test/xpm-roundtrip.ok
index 845be5fb..5168378d 100644
--- a/test/xpm-roundtrip.ok
+++ b/test/xpm-roundtrip.ok
@@ -1 +1 @@
-2425386270 41
+281226646 481
diff --git a/test/xpm-roundtrip.test b/test/xpm-roundtrip.test
index fd0253b1..6e3e415b 100755
--- a/test/xpm-roundtrip.test
+++ b/test/xpm-roundtrip.test
@@ -1,9 +1,9 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmtoxpm xpmtoppm
 # Also requires: pgmtopbm ppmtopgm
 
 
 #ppmtoxpm -hexonly testimg.ppm | \
 # xpmtoppm  | cksum
-ppmtoxpm testgrid.pbm | xpmtoppm | \
+ppmtoxpm maze.pbm | xpmtoppm | \
   ppmtopgm | pgmtopbm -th -value=0.5 | cksum
diff --git a/test/xv-roundtrip.test b/test/xv-roundtrip.test
index d73933a1..70b298df 100755
--- a/test/xv-roundtrip.test
+++ b/test/xv-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pamtoxvmini xvminitoppm
 # Also requires: pamdepth
 
diff --git a/test/xwd-roundtrip.ok b/test/xwd-roundtrip.ok
index 25d3d871..864d737a 100644
--- a/test/xwd-roundtrip.ok
+++ b/test/xwd-roundtrip.ok
@@ -1,3 +1,6 @@
+Test 1.  Should produce 1571496937 33838, cksum of testimg.red
 1571496937 33838
+Test 2.  Should produce 1926073387 101484
 1926073387 101484
-2425386270 41
+Test 3.  Should produce 281226646 481
+281226646 481
diff --git a/test/xwd-roundtrip.test b/test/xwd-roundtrip.test
index cd0d38ad..2d00971d 100755
--- a/test/xwd-roundtrip.test
+++ b/test/xwd-roundtrip.test
@@ -1,16 +1,15 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: pnmtoxwd xwdtopnm
 # Also requires: pamchannel pamtopnm pamdepth
 
-
-# Test 1.  Should produce 1571496937 33838, cksum of testimg.red
+echo "Test 1.  Should produce 1571496937 33838, cksum of testimg.red"
 pamchannel -infile=testimg.ppm -tupletype="GRAYSCALE" 0 | pamtopnm | \
   pnmtoxwd | xwdtopnm | pamdepth 255 | cksum
 
-# Test 2.  Should produce 1926073387 101484
-pnmtoxwd --quiet  testimg.ppm | \
+echo "Test 2.  Should produce 1926073387 101484"
+pnmtoxwd --quiet testimg.ppm | \
   xwdtopnm --quiet | pamdepth 255 | cksum
 
-# Test 3.  Should produce 2425386270 41
-pnmtoxwd --quiet  testgrid.pbm | \
+echo "Test 3.  Should produce 281226646 481"
+pnmtoxwd --quiet maze.pbm | \
   xwdtopnm | cksum
diff --git a/test/yuv-roundtrip.test b/test/yuv-roundtrip.test
index e339b418..68f459e8 100755
--- a/test/yuv-roundtrip.test
+++ b/test/yuv-roundtrip.test
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 # This script tests: ppmtoyuv yuvtoppm
 # Also requires: pamgradient
 
diff --git a/urt/Makefile b/urt/Makefile
index 0aef5290..8c85dab4 100644
--- a/urt/Makefile
+++ b/urt/Makefile
@@ -10,10 +10,10 @@ default: all
 include $(BUILDDIR)/config.mk
 
 LIBOBJECTS = Runput.o cmd_name.o \
-	rle_addhist.o rle_error.o rle_getcom.o rle_getrow.o rle_getskip.o \
+	rle_addhist.o rle_getcom.o rle_getrow.o rle_getskip.o \
 	rle_global.o rle_hdr.o rle_open_f.o rle_putcom.o rle_putrow.o \
-        rle_row_alc.o \
-        scanargs.o vaxshort.o     
+	rle_row_alc.o \
+	vaxshort.o     
 
 MERGE_OBJECTS =
 
diff --git a/urt/README b/urt/README
index dc68889d..2cfbb3e2 100644
--- a/urt/README
+++ b/urt/README
@@ -18,3 +18,8 @@ in its initializer in the original.  But GNU C Library Version 2
 defines stdout as a variable, so that wouldn't compile.  So I changed
 it to NULL and added a line to rle_hdr_init to set that field to
 'stdout' dynamically.  2000.06.02 BJH.
+
+---
+
+Cleanup by Akira F Urushibata 2022.03.06
+Unused functions removed.
\ No newline at end of file
diff --git a/urt/Runput.c b/urt/Runput.c
index 3bc562ac..1a7f2f7b 100644
--- a/urt/Runput.c
+++ b/urt/Runput.c
@@ -1,14 +1,14 @@
 /*
  * This software is copyrighted as noted below.  It may be freely copied,
- * modified, and redistributed, provided that the copyright notice is 
+ * modified, and redistributed, provided that the copyright notice is
  * preserved on all copies.
- * 
+ *
  * There is no warranty or other guarantee of fitness for this software,
  * it is provided solely "as is".  Bug reports or fixes may be sent
  * to the author, who may or may not act on them as he desires.
  *
  * You may not include this software in a program or other software product
- * without supplying the source, or without informing the end-user that the 
+ * without supplying the source, or without informing the end-user that the
  * source is available for no extra charge.
  *
  * If you modify this software, you should include a notice giving the
@@ -18,146 +18,146 @@
  *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
  *  to have all "void" functions so declared.
  */
-/* 
+/*
  * Runput.c - General purpose Run Length Encoding.
- * 
- * Author:	Spencer W. Thomas
- * 		Computer Science Dept.
- * 		University of Utah
- * Date:	Mon Aug  9 1982
+ *
+ * Author:      Spencer W. Thomas
+ *              Computer Science Dept.
+ *              University of Utah
+ * Date:        Mon Aug  9 1982
  * Copyright (c) 1982,1986 Spencer W. Thomas
- * 
+ *
  * $Id: Runput.c,v 3.0.1.1 1992/01/28 18:17:40 spencer Exp $
- * 
- * Modified by:	Todd W. Fuqua
- * 	Date:	Jul 22 1984
+ *
+ * Modified by: Todd W. Fuqua
+ *      Date:   Jul 22 1984
  * convert to new RLE format to make room for larger frame buffers
  */
 
 /* THIS IS WAY OUT OF DATE.  See rle.5.
  * The output file format is:
- * 
- * Word 0:	A "magic" number.  The top byte of the word contains
- *		the letter 'R' or the letter 'W'.  'W' indicates that
- *		only black and white information was saved.  The bottom
- *		byte is one of the following:
- *	' ':	Means a straight "box" save, -S flag was given.
- *	'B':	Image saved with background color, clear screen to
- *		background before restoring image.
- *	'O':	Image saved in overlay mode.
- * 
- * Words 1-6:	The structure
- * {     short   xpos,			Lower left corner
+ *
+ * Word 0:      A "magic" number.  The top byte of the word contains
+ *              the letter 'R' or the letter 'W'.  'W' indicates that
+ *              only black and white information was saved.  The bottom
+ *              byte is one of the following:
+ *      ' ':    Means a straight "box" save, -S flag was given.
+ *      'B':    Image saved with background color, clear screen to
+ *              background before restoring image.
+ *      'O':    Image saved in overlay mode.
+ *
+ * Words 1-6:   The structure
+ * {     short   xpos,                  Lower left corner
  *             ypos,
- *             xsize,			Size of saved box
+ *             xsize,                   Size of saved box
  *             ysize;
- *     char    rgb[3];			Background color
- *     char    map;			flag for map presence
+ *     char    rgb[3];                  Background color
+ *     char    map;                     flag for map presence
  * }
- * 
- * If the map flag is non-zero, then the color map will follow as 
+ *
+ * If the map flag is non-zero, then the color map will follow as
  * 3*256 16 bit words, first the red map, then the green map, and
  * finally the blue map.
- * 
+ *
  * Following the setup information is the Run Length Encoded image.
  * Each instruction consists of a 4-bit opcode, a 12-bit datum and
  * possibly one or more following words (all words are 16 bits).  The
  * instruction opcodes are:
- * 
+ *
  * SkipLines (1):   The bottom 10 bits are an unsigned number to be added to
- *		    current Y position.
- * 
+ *                  current Y position.
+ *
  * SetColor (2):    The datum indicates which color is to be loaded with
- * 		    the data described by the following ByteData and
- * 		    RunData instructions.  0->red, 1->green, 2->blue.  The
- * 		    operation also resets the X position to the initial
- * 		    X (i.e. a carriage return operation is performed).
- * 
+ *                  the data described by the following ByteData and
+ *                  RunData instructions.  0->red, 1->green, 2->blue.  The
+ *                  operation also resets the X position to the initial
+ *                  X (i.e. a carriage return operation is performed).
+ *
  * SkipPixels (3):  The bottom 10 bits are an unsigned number to be
- * 		    added to the current X position.
- * 
+ *                  added to the current X position.
+ *
  * ByteData (5):    The datum is one less than the number of bytes of
- * 		    color data following.  If the number of bytes is
- * 		    odd, a filler byte will be appended to the end of
- * 		    the byte string to make an integral number of 16-bit
- * 		    words.  The bytes are in PDP-11 order.  The X
- * 		    position is incremented to follow the last byte of
- * 		    data.
- * 
- * RunData (6):	    The datum is one less than the run length.  The
- * 		    following word contains (in its lower 8 bits) the
- * 		    color of the run.  The X position is incremented to
- * 		    follow the last byte in the run.
+ *                  color data following.  If the number of bytes is
+ *                  odd, a filler byte will be appended to the end of
+ *                  the byte string to make an integral number of 16-bit
+ *                  words.  The bytes are in PDP-11 order.  The X
+ *                  position is incremented to follow the last byte of
+ *                  data.
+ *
+ * RunData (6):     The datum is one less than the run length.  The
+ *                  following word contains (in its lower 8 bits) the
+ *                  color of the run.  The X position is incremented to
+ *                  follow the last byte in the run.
  */
 
 #include    <string.h>
-#include	<stdio.h>
+#include        <stdio.h>
 
-#include	"rle_put.h"
-#include	"rle.h"
-#include	"rle_code.h"
+#include        "rle_put.h"
+#include        "rle.h"
+#include        "rle_code.h"
 #include    "vaxshort.h"
 #include    "Runput.h"
 
-#define UPPER 255			/* anything bigger ain't a byte */
+#define UPPER 255                       /* anything bigger ain't a byte */
 
 /*
  * Macros to make writing instructions with correct byte order easier.
  */
 /* Write a two-byte value in little_endian order. */
-#define	put16(a)    (putc((a)&0xff,rle_fd),putc((char)(((a)>>8)&0xff),rle_fd))
+#define put16(a)    (putc((a)&0xff,rle_fd),putc((char)(((a)>>8)&0xff),rle_fd))
 
 /* short instructions */
-#define mk_short_1(oper,a1)		/* one argument short */ \
+#define mk_short_1(oper,a1)             /* one argument short */ \
     putc(oper,rle_fd), putc((char)a1,rle_fd)
 
-#define mk_short_2(oper,a1,a2)		/* two argument short */ \
+#define mk_short_2(oper,a1,a2)          /* two argument short */ \
     putc(oper,rle_fd), putc((char)a1,rle_fd), put16(a2)
 
 /* long instructions */
-#define mk_long_1(oper,a1)		/* one argument long */ \
+#define mk_long_1(oper,a1)              /* one argument long */ \
     putc((char)(LONG|oper),rle_fd), putc('\0', rle_fd), put16(a1)
 
-#define mk_long_2(oper,a1,a2)		/* two argument long */ \
+#define mk_long_2(oper,a1,a2)           /* two argument long */ \
     putc((char)(LONG|oper),rle_fd), putc('\0', rle_fd), \
     put16(a1), put16(a2)
 
 /* choose between long and short format instructions */
 /* NOTE: these macros can only be used where a STATEMENT is legal */
 
-#define mk_inst_1(oper,a1)		/* one argument inst */ \
+#define mk_inst_1(oper,a1)              /* one argument inst */ \
     if (a1>UPPER) (mk_long_1(oper,a1)); else (mk_short_1(oper,a1))
 
-#define mk_inst_2(oper,a1,a2)		/* two argument inst */ \
+#define mk_inst_2(oper,a1,a2)           /* two argument inst */ \
     if (a1>UPPER) (mk_long_2(oper,a1,a2)); else (mk_short_2(oper,a1,a2))
 
-/* 
+/*
  * Opcode definitions
  */
-#define	    RSkipLines(n)   	    mk_inst_1(RSkipLinesOp,(n))
+#define     RSkipLines(n)           mk_inst_1(RSkipLinesOp,(n))
 
-#define	    RSetColor(c)	    mk_short_1(RSetColorOp,(c))
-				    /* has side effect of performing */
-				    /* "carriage return" action */
+#define     RSetColor(c)            mk_short_1(RSetColorOp,(c))
+                                    /* has side effect of performing */
+                                    /* "carriage return" action */
 
-#define	    RSkipPixels(n)	    mk_inst_1(RSkipPixelsOp,(n))
+#define     RSkipPixels(n)          mk_inst_1(RSkipPixelsOp,(n))
 
-#define	    RNewLine		    RSkipLines(1)
+#define     RNewLine                RSkipLines(1)
 
-#define	    RByteData(n)	    mk_inst_1(RByteDataOp,n)
-					/* followed by ((n+1)/2)*2 bytes */
-					/* of data.  If n is odd, last */
-					/* byte will be ignored */
-					/* "cursor" is left at pixel */
-					/* following last pixel written */
+#define     RByteData(n)            mk_inst_1(RByteDataOp,n)
+                                        /* followed by ((n+1)/2)*2 bytes */
+                                        /* of data.  If n is odd, last */
+                                        /* byte will be ignored */
+                                        /* "cursor" is left at pixel */
+                                        /* following last pixel written */
 
-#define	    RRunData(n,c)	    mk_inst_2(RRunDataOp,(n),(c))
-					/* next word contains color data */
-					/* "cursor" is left at pixel after */
-					/* end of run */
+#define     RRunData(n,c)           mk_inst_2(RRunDataOp,(n),(c))
+                                        /* next word contains color data */
+                                        /* "cursor" is left at pixel after */
+                                        /* end of run */
 
-#define     REOF		    mk_inst_1(REOFOp,0)
-					/* Really opcode only */
+#define     REOF                    mk_inst_1(REOFOp,0)
+                                        /* Really opcode only */
 
 /*****************************************************************
  * TAG( RunSetup )
@@ -167,33 +167,33 @@ void
 RunSetup(rle_hdr * the_hdr)
 {
     struct XtndRsetup setup;
-    register FILE * rle_fd = the_hdr->rle_file;
+    FILE * rle_fd = the_hdr->rle_file;
 
     put16( RLE_MAGIC );
 
     if ( the_hdr->background == 2 )
-	setup.h_flags = H_CLEARFIRST;
+        setup.h_flags = H_CLEARFIRST;
     else if ( the_hdr->background == 0 )
-	setup.h_flags = H_NO_BACKGROUND;
+        setup.h_flags = H_NO_BACKGROUND;
     else
-	setup.h_flags = 0;
+        setup.h_flags = 0;
     if ( the_hdr->alpha )
-	setup.h_flags |= H_ALPHA;
+        setup.h_flags |= H_ALPHA;
     if ( the_hdr->comments != NULL && *the_hdr->comments != NULL )
-	setup.h_flags |= H_COMMENT;
+        setup.h_flags |= H_COMMENT;
 
     setup.h_ncolors = the_hdr->ncolors;
-    setup.h_pixelbits = 8;		/* Grinnell dependent */
+    setup.h_pixelbits = 8;              /* Grinnell dependent */
     if ( the_hdr->ncmap > 0 && the_hdr->cmap == NULL )
     {
-	fprintf( stderr,
+        fprintf( stderr,
        "%s: Color map of size %d*%d specified, but not supplied, writing %s\n",
-		 the_hdr->cmd, the_hdr->ncmap, (1 << the_hdr->cmaplen),
-		 the_hdr->file_name );
-	the_hdr->ncmap = 0;
+                 the_hdr->cmd, the_hdr->ncmap, (1 << the_hdr->cmaplen),
+                 the_hdr->file_name );
+        the_hdr->ncmap = 0;
     }
-    setup.h_cmaplen = the_hdr->cmaplen;	/* log2 of color map size */
-    setup.h_ncmap = the_hdr->ncmap;	/* no of color channels */
+    setup.h_cmaplen = the_hdr->cmaplen; /* log2 of color map size */
+    setup.h_ncmap = the_hdr->ncmap;     /* no of color channels */
     vax_pshort(setup.hc_xpos,the_hdr->xmin);
     vax_pshort(setup.hc_ypos,the_hdr->ymin);
     vax_pshort(setup.hc_xlen,the_hdr->xmax - the_hdr->xmin + 1);
@@ -201,61 +201,61 @@ RunSetup(rle_hdr * the_hdr)
     fwrite((char *)&setup, SETUPSIZE, 1, rle_fd);
     if ( the_hdr->background != 0 )
     {
-	register int i;
-	register rle_pixel *background =
-	    (rle_pixel *)malloc( (unsigned)(the_hdr->ncolors + 1) );
-	register int *bg_color;
-	/* 
-	 * If even number of bg color bytes, put out one more to get to 
-	 * 16 bit boundary.
-	 */
-	bg_color = the_hdr->bg_color;
-	for ( i = 0; i < the_hdr->ncolors; i++ )
-	    background[i] =  *bg_color++;
-	/* Extra byte, if written, should be 0. */
-	background[i] = 0;
-	fwrite((char *)background, (the_hdr->ncolors / 2) * 2 + 1, 1, rle_fd);
-	free( background );
+        int i;
+        rle_pixel *background =
+            (rle_pixel *)malloc( (unsigned)(the_hdr->ncolors + 1) );
+        int *bg_color;
+        /*
+         * If even number of bg color bytes, put out one more to get to
+         * 16 bit boundary.
+         */
+        bg_color = the_hdr->bg_color;
+        for ( i = 0; i < the_hdr->ncolors; i++ )
+            background[i] =  *bg_color++;
+        /* Extra byte, if written, should be 0. */
+        background[i] = 0;
+        fwrite((char *)background, (the_hdr->ncolors / 2) * 2 + 1, 1, rle_fd);
+        free( background );
     }
     else
-	putc( '\0', rle_fd );
+        putc( '\0', rle_fd );
     if (the_hdr->ncmap > 0)
     {
-	/* Big-endian machines are harder */
-	register int i, nmap = (1 << the_hdr->cmaplen) *
-			       the_hdr->ncmap;
-	register char *h_cmap = (char *)malloc( nmap * 2 );
-	if ( h_cmap == NULL )
-	{
-	    fprintf( stderr,
-	     "%s: Malloc failed for color map of size %d, writing %s\n",
-		     the_hdr->cmd, nmap, the_hdr->file_name );
-	    exit( 1 );
-	}
-	for ( i = 0; i < nmap; i++ )
-	    vax_pshort( &h_cmap[i*2], the_hdr->cmap[i] );
-
-	fwrite( h_cmap, nmap, 2, rle_fd );
-	free( h_cmap );
+        /* Big-endian machines are harder */
+        int i, nmap = (1 << the_hdr->cmaplen) *
+                               the_hdr->ncmap;
+        char *h_cmap = (char *)malloc( nmap * 2 );
+        if ( h_cmap == NULL )
+        {
+            fprintf( stderr,
+             "%s: Malloc failed for color map of size %d, writing %s\n",
+                     the_hdr->cmd, nmap, the_hdr->file_name );
+            exit( 1 );
+        }
+        for ( i = 0; i < nmap; i++ )
+            vax_pshort( &h_cmap[i*2], the_hdr->cmap[i] );
+
+        fwrite( h_cmap, nmap, 2, rle_fd );
+        free( h_cmap );
     }
 
     /* Now write out comments if given */
     if ( setup.h_flags & H_COMMENT )
     {
-	int comlen;
-	register CONST_DECL char ** com_p;
+        int comlen;
+        CONST_DECL char ** com_p;
 
-	/* Get the total length of comments */
-	comlen = 0;
-	for ( com_p = the_hdr->comments; *com_p != NULL; com_p++ )
-	    comlen += 1 + strlen( *com_p );
+        /* Get the total length of comments */
+        comlen = 0;
+        for ( com_p = the_hdr->comments; *com_p != NULL; com_p++ )
+            comlen += 1 + strlen( *com_p );
 
-	put16( comlen );
-	for ( com_p = the_hdr->comments; *com_p != NULL; com_p++ )
-	    fwrite( *com_p, 1, strlen( *com_p ) + 1, rle_fd );
+        put16( comlen );
+        for ( com_p = the_hdr->comments; *com_p != NULL; com_p++ )
+            fwrite( *com_p, 1, strlen( *com_p ) + 1, rle_fd );
 
-	if ( comlen & 1 )	/* if odd length, round up */
-	    putc( '\0', rle_fd );
+        if ( comlen & 1 )       /* if odd length, round up */
+            putc( '\0', rle_fd );
     }
 }
 
@@ -266,7 +266,7 @@ RunSetup(rle_hdr * the_hdr)
 void
 RunSkipBlankLines(int nblank, rle_hdr * the_hdr)
 {
-    register FILE * rle_fd = the_hdr->rle_file;
+    FILE * rle_fd = the_hdr->rle_file;
     RSkipLines(nblank);
 }
 
@@ -278,7 +278,7 @@ RunSkipBlankLines(int nblank, rle_hdr * the_hdr)
 void
 RunSetColor(int c, rle_hdr * the_hdr)
 {
-    register FILE * rle_fd = the_hdr->rle_file;
+    FILE * rle_fd = the_hdr->rle_file;
     RSetColor(c);
 }
 
@@ -291,10 +291,10 @@ RunSetColor(int c, rle_hdr * the_hdr)
 void
 RunSkipPixels(int nskip, int last, int wasrun, rle_hdr * the_hdr)
 {
-    register FILE * rle_fd = the_hdr->rle_file;
+    FILE * rle_fd = the_hdr->rle_file;
     if (! last && nskip > 0)
     {
-	RSkipPixels(nskip);
+        RSkipPixels(nskip);
     }
 }
 
@@ -306,10 +306,10 @@ RunSkipPixels(int nskip, int last, int wasrun, rle_hdr * the_hdr)
 void
 RunNewScanLine(int flag, rle_hdr * the_hdr)
 {
-    register FILE * rle_fd = the_hdr->rle_file;
+    FILE * rle_fd = the_hdr->rle_file;
     if (flag)
     {
-	RNewLine;
+        RNewLine;
     }
 }
 
@@ -320,14 +320,14 @@ RunNewScanLine(int flag, rle_hdr * the_hdr)
 void
 Runputdata(rle_pixel * buf, int n, rle_hdr * the_hdr)
 {
-    register FILE * rle_fd = the_hdr->rle_file;
+    FILE * rle_fd = the_hdr->rle_file;
     if (n == 0)
-	return;
+        return;
 
     RByteData(n-1);
     fwrite((char *)buf, n, 1, rle_fd);
     if ( n & 1 )
-	putc( 0, rle_fd );
+        putc( 0, rle_fd );
 }
 
 /*****************************************************************
@@ -339,7 +339,7 @@ Runputdata(rle_pixel * buf, int n, rle_hdr * the_hdr)
 void
 Runputrun(int color, int n, int last, rle_hdr * the_hdr)
 {
-    register FILE * rle_fd = the_hdr->rle_file;
+    FILE * rle_fd = the_hdr->rle_file;
     RRunData(n-1,color);
 }
 
@@ -351,6 +351,6 @@ Runputrun(int color, int n, int last, rle_hdr * the_hdr)
 void
 RunputEof(rle_hdr * the_hdr)
 {
-    register FILE * rle_fd = the_hdr->rle_file;
+    FILE * rle_fd = the_hdr->rle_file;
     REOF;
 }
diff --git a/urt/Runput.h b/urt/Runput.h
index 776e3ec5..1d22a971 100644
--- a/urt/Runput.h
+++ b/urt/Runput.h
@@ -1,4 +1,4 @@
-void 
+void
 RunSetup(rle_hdr * the_hdr);
 
 void
diff --git a/urt/cmd_name.c b/urt/cmd_name.c
index 31fe5f42..4b3f169b 100644
--- a/urt/cmd_name.c
+++ b/urt/cmd_name.c
@@ -1,27 +1,27 @@
 /*
  * This software is copyrighted as noted below.  It may be freely copied,
- * modified, and redistributed, provided that the copyright notice is 
+ * modified, and redistributed, provided that the copyright notice is
  * preserved on all copies.
- * 
+ *
  * There is no warranty or other guarantee of fitness for this software,
  * it is provided solely "as is".  Bug reports or fixes may be sent
  * to the author, who may or may not act on them as he desires.
  *
  * You may not include this software in a program or other software product
- * without supplying the source, or without informing the end-user that the 
+ * without supplying the source, or without informing the end-user that the
  * source is available for no extra charge.
  *
  * If you modify this software, you should include a notice giving the
  * name of the person performing the modification, the date of modification,
  * and the reason for such modification.
  */
-/* 
+/*
  * cmd_name.c - Extract command name from argv[0].
- * 
- * Author:	Spencer W. Thomas
- * 		EECS Dept.
- * 		University of Michigan
- * Date:	Wed Jun 27 1990
+ *
+ * Author:      Spencer W. Thomas
+ *              EECS Dept.
+ *              University of Michigan
+ * Date:        Wed Jun 27 1990
  * Copyright (c) 1990, University of Michigan
  */
 
@@ -35,23 +35,23 @@ char *
 cmd_name( argv )
 char **argv;
 {
-    register char *cp, *a;
+    char *cp, *a;
 
     /* Be paranoid. */
     if ( !argv || !(a = *argv) )
-	return no_name;
+        return no_name;
 
     /* Find end of file name. */
     for ( cp = a; *cp; cp++ )
-	;
+        ;
 
     /* Find last / or beginning of command name. */
     for ( cp--; *cp != '/' && cp > a; cp-- )
-	;
-    
+        ;
+
     /* If it's a /, skip it. */
     if ( *cp == '/' )
-	cp++;
+        cp++;
 
     return cp;
 }
diff --git a/urt/rle.h b/urt/rle.h
index 0766d22a..1e7ddd0c 100644
--- a/urt/rle.h
+++ b/urt/rle.h
@@ -1,29 +1,29 @@
 /*
  * This software is copyrighted as noted below.  It may be freely copied,
- * modified, and redistributed, provided that the copyright notice is 
+ * modified, and redistributed, provided that the copyright notice is
  * preserved on all copies.
- * 
+ *
  * There is no warranty or other guarantee of fitness for this software,
  * it is provided solely "as is".  Bug reports or fixes may be sent
  * to the author, who may or may not act on them as he desires.
  *
  * You may not include this software in a program or other software product
- * without supplying the source, or without informing the end-user that the 
+ * without supplying the source, or without informing the end-user that the
  * source is available for no extra charge.
  *
  * If you modify this software, you should include a notice giving the
  * name of the person performing the modification, the date of modification,
  * and the reason for such modification.
  */
-/* 
+/*
  * rle.h - Global declarations for Utah Raster Toolkit RLE programs.
- * 
+ *
  * Author:  Todd W. Fuqua
  *      Computer Science Dept.
  *      University of Utah
  * Date:    Sun Jul 29 1984
  * Copyright (c) 1984 Todd W. Fuqua
- * 
+ *
  * $Id: rle.h,v 3.0.1.5 1992/04/30 14:05:56 spencer Exp $
  */
 
@@ -50,33 +50,25 @@ typedef unsigned short rle_map;
 /*
  * Defines for traditional channel numbers.
  */
-#define RLE_RED     0   /* Red channel traditionally here. */
-#define RLE_GREEN   1   /* Green channel traditionally here. */
-#define RLE_BLUE    2   /* Blue channel traditionally here. */
-#define RLE_ALPHA      -1   /* Alpha channel here. */
+#define RLE_RED    0   /* Red channel traditionally here. */
+#define RLE_GREEN  1   /* Green channel traditionally here. */
+#define RLE_BLUE   2   /* Blue channel traditionally here. */
+#define RLE_ALPHA -1   /* Alpha channel here. */
 
 /*
  * Return values from rle_get_setup.
  */
-#define RLE_SUCCESS  0
-#define RLE_NOT_RLE -1
-#define RLE_NO_SPACE    -2
-#define RLE_EMPTY   -3
-#define RLE_EOF     -4
+#define RLE_SUCCESS   0
+#define RLE_NOT_RLE  -1
+#define RLE_NO_SPACE -2
+#define RLE_EMPTY    -3
+#define RLE_EOF      -4
 
 /*
  * "Magic" value for is_init field.  Pi * 2^29.
  */
 #define RLE_INIT_MAGIC  0x6487ED51L
 
-/*****************************************************************
- * TAG( RLE_CHECK_ALLOC )
- *
- * Test for allocation failure, scream and die if so.
- */
-#define RLE_CHECK_ALLOC( pgm, ptr, name )               \
-    ( !(ptr) ?  rle_alloc_error( pgm, name ) : 0 )
-
 /*
  * TAG( rle_hdr )
  *
@@ -103,15 +95,15 @@ typedef
         rle_map * cmap;       /* Pointer to color map array. */
         const char ** comments; /* Pointer to array of pointers to comments. */
         FILE *    rle_file;   /* Input or output file. */
-        /* 
+        /*
          * Bit map of channels to read/save.  Indexed by (channel mod 256).
          * Alpha channel sets bit 255.
-         * 
+         *
          * Indexing (0 <= c <= 255):
          *      bits[c/8] & (1 << (c%8))
          */
 #define RLE_SET_BIT(glob,bit) \
-        ((glob).bits[((bit)&0xff)/8] |= (1<<((bit)&0x7)))
+            ((glob).bits[((bit)&0xff)/8] |= (1<<((bit)&0x7)))
 #define RLE_CLR_BIT(glob,bit) \
             ((glob).bits[((bit)&0xff)/8] &= ~(1<<((bit)&0x7)))
 #define RLE_BIT(glob,bit) \
@@ -119,12 +111,12 @@ typedef
             char    bits[256/8];
             /* Set to magic pattern if following fields are initialized. */
             /* This gives a 2^(-32) chance of missing. */
-            long int is_init;   
+            long int is_init;
             /* Command, file name and image number for error messages. */
             const char *cmd;
             const char *file_name;
             int img_num;
-            /* 
+            /*
              * Local storage for rle_getrow & rle_putrow.
              * rle_getrow has
              *      scan_y  int     current Y scanline.
@@ -153,7 +145,7 @@ rle_hdr             /* End of typedef. */
 #endif
 ;
 
-/* 
+/*
  * TAG( rle_dflt_hdr )
  *
  * Global variable with possibly useful default values.
@@ -163,15 +155,6 @@ extern rle_hdr rle_dflt_hdr;
 
 /* Declare RLE library routines. */
 
-/* From rle_error.c. */
-/*****************************************************************
- * TAG( rle_alloc_error )
- * 
- * Print memory allocation error message and exit.
- */
-extern int rle_alloc_error( const char *pgm,
-                            const char *name );
-
 /*****************************************************************
  * TAG( rle_get_error )
  *
@@ -181,15 +164,8 @@ extern int rle_alloc_error( const char *pgm,
 extern int rle_get_error( int code,
                           const char *pgmname,
                           const char *fname );
-              
-/* From rle_getrow.c */
 
-/*****************************************************************
- * TAG( rle_debug )
- * 
- * Turn RLE debugging on or off.
- */
-extern void rle_debug( int on_off );
+/* From rle_getrow.c */
 
 int
 rle_get_setup(rle_hdr * const the_hdr);
@@ -199,7 +175,7 @@ rle_get_setup(rle_hdr * const the_hdr);
  *
  * Call rle_get_setup.  If it returns an error code, call
  * rle_get_error to print the error message, then exit with the error
- * code. 
+ * code.
  */
 extern void rle_get_setup_ok( rle_hdr *the_hdr,
                               const char *prog_name,
@@ -210,7 +186,7 @@ extern void rle_get_setup_ok( rle_hdr *the_hdr,
  *
  * Read a scanline worth of data from an RLE file.
  */
-extern int rle_getrow( rle_hdr * the_hdr, 
+extern int rle_getrow( rle_hdr * the_hdr,
                        rle_pixel * scanline[] );
 
 /* From rle_getskip.c */
@@ -235,7 +211,7 @@ extern void rle_names( rle_hdr *the_hdr,
 
 /*****************************************************************
  * TAG( rle_hdr_cp )
- * 
+ *
  * Make a "safe" copy of a rle_hdr structure.
  */
 extern rle_hdr * rle_hdr_cp( rle_hdr *from_hdr,
@@ -243,29 +219,19 @@ extern rle_hdr * rle_hdr_cp( rle_hdr *from_hdr,
 
 /*****************************************************************
  * TAG( rle_hdr_init )
- * 
+ *
  * Initialize a rle_hdr structure.
  */
 extern rle_hdr * rle_hdr_init( rle_hdr *the_hdr );
 
 /*****************************************************************
  * TAG( rle_hdr_clear )
- * 
+ *
  */
 extern void rle_hdr_clear( rle_hdr *the_hdr );
 
 /* From rle_putrow.c. */
 
-/*****************************************************************
- * TAG( rgb_to_bw )
- *
- * Converts RGB data to gray data via the NTSC Y transform.
- */
-extern void rgb_to_bw( rle_pixel *red_row,
-                       rle_pixel *green_row,
-                       rle_pixel *blue_row,
-                       rle_pixel *bw_row,
-                       int rowlen );
 
 /*****************************************************************
  * TAG( rle_puteof )
@@ -302,13 +268,6 @@ extern void rle_put_setup( rle_hdr * the_hdr );
  */
 extern void rle_skiprow( rle_hdr *the_hdr, int nrow );
 
-/* From rle_cp.c */
-/*****************************************************************
- * TAG( rle_cp )
- * Copy image data from input to output with minimal interpretation.
- */
-extern void rle_cp( rle_hdr *in_hdr, rle_hdr *out_hdr );
-
 /* From rle_row_alc.c. */
 /*****************************************************************
  * TAG( rle_row_alloc )
@@ -325,14 +284,6 @@ extern int rle_row_alloc( rle_hdr * the_hdr,
      */
 extern void rle_row_free( rle_hdr *the_hdr, rle_pixel **scanp );
 
-/* From buildmap.c. */
-/* 
- * buildmap - build a more usable colormap from data in the_hdr struct.
-     */
-extern rle_pixel **buildmap( rle_hdr *the_hdr,
-                             int minmap,
-                             double orig_gamma,
-                             double new_gamma );
 
 /* From rle_getcom.c. */
 /*****************************************************************
@@ -346,55 +297,11 @@ rle_getcom(const char * const name,
 
 /* From rle_putcom.c. */
 
-/* Delete a specific comment from the image comments. */
-const char *
-rle_delcom(const char * const name,
-           rle_hdr *    const the_hdr);
-
 /* Put (or replace) a comment into the image comments. */
 const char *
 rle_putcom(const char * const value,
            rle_hdr *    const the_hdr);
 
-/* From dither.c. */
-/*****************************************************************
- * TAG( bwdithermap )
- * Create a color map for ordered dithering in grays.
- */
-extern void bwdithermap( int levels, double gamma, int bwmap[],
-                         int divN[256], int modN[256], int magic[16][16] );
-/*****************************************************************
- * TAG( ditherbw )
- * Dither a gray-scale value.
- */
-extern int ditherbw( int x, int y, int val, 
-                     int divN[256], int modN[256], int magic[16][16] );
-/*****************************************************************
- * TAG( dithergb )
- * Dither a color value.
- */
-extern int dithergb( int x, int y, int r, int g, int b,
-                     int divN[256], int modN[256], int magic[16][16] );
-/*****************************************************************
- * TAG( dithermap )
- * Create a color map for ordered dithering in color.
- */
-extern void dithermap( int levels, double gamma, int rgbmap[][3],
-                       int divN[256], int modN[256], int magic[16][16] );
-/*****************************************************************
- * TAG( make_square )
- * Make a 16x16 magic square for ordered dithering.
- */
-extern void make_square( double N, int divN[256], int modN[256],
-                         int magic[16][16] );
-
-/* From float_to_exp.c. */
-/*****************************************************************
- * TAG( float_to_exp )
- * Convert a list of floating point numbers to "exp" format.
- */
-extern void float_to_exp( int count, float * floats, rle_pixel * pixels );
-
 /* From rle_open_f.c. */
 /*****************************************************************
  * TAG( rle_open_f )
@@ -402,7 +309,7 @@ extern void float_to_exp( int count, float * floats, rle_pixel * pixels );
  * Open an input/output file with default.
  */
 FILE *
-rle_open_f(const char * prog_name, const char * file_name, 
+rle_open_f(const char * prog_name, const char * file_name,
            const char * mode);
 
 /*****************************************************************
@@ -412,27 +319,9 @@ rle_open_f(const char * prog_name, const char * file_name,
  */
 FILE *
 rle_open_f_noexit(const char * const prog_name,
-                  const char * const file_name, 
+                  const char * const file_name,
                   const char * const mode);
 
-/*****************************************************************
- * TAG( rle_close_f )
- * 
- * Close a file opened by rle_open_f.  If the file is stdin or stdout,
- * it will not be closed.
- */
-extern void 
-rle_close_f( FILE *fd );
-
-/* From colorquant.c. */
-/*****************************************************************
- * TAG( colorquant )
- * Compute a colormap for quantizing an image to a limited set of colors.
- */
-extern int colorquant( rle_pixel *red, rle_pixel *green, rle_pixel *blue,
-                       unsigned long pixels, rle_pixel *colormap[3],
-                       int colors, int bits,
-                       rle_pixel *rgbmap, int fast, int otherimages );
 
 /* From rle_addhist.c. */
 
@@ -449,38 +338,5 @@ rle_addhist(char *          argv[],
  */
 extern char *cmd_name( char **argv );
 
-/* From scanargs.c. */
-/*****************************************************************
- * TAG( scanargs )
- * Scan command argument list and parse arguments.
- */
-extern int scanargs( int argc,
-                     char **argv,
-                     const char *format,
-                     ... );
-
-/* From hilbert.c */
-/*****************************************************************
- * TAG( hilbert_i2c )
- * Convert an index into a Hilbert curve to a set of coordinates.
- */
-extern void hilbert_c2i( int n, int m, int a[], long int *r );
-
-/*****************************************************************
- * TAG( hilbert_c2i )
- * Convert coordinates of a point on a Hilbert curve to its index.
- */
-extern void hilbert_i2c( int n, int m, long int r, int a[] );
-
-/* From inv_cmap.c */
-/*****************************************************************
- * TAG( inv_cmap )
- * Compute an inverse colormap efficiently.
- */
-extern void inv_cmap( int colors,
-                      unsigned char *colormap[3],
-                      int bits,
-                      unsigned long *dist_buf,
-                      unsigned char *rgbmap );
 
 #endif /* RLE_H */
diff --git a/urt/rle_addhist.c b/urt/rle_addhist.c
index b1651754..45c3dbfd 100644
--- a/urt/rle_addhist.c
+++ b/urt/rle_addhist.c
@@ -1,25 +1,25 @@
 /*
  * This software is copyrighted as noted below.  It may be freely copied,
- * modified, and redistributed, provided that the copyright notice is 
+ * modified, and redistributed, provided that the copyright notice is
  * preserved on all copies.
- * 
+ *
  * There is no warranty or other guarantee of fitness for this software,
  * it is provided solely "as is".  Bug reports or fixes may be sent
  * to the author, who may or may not act on them as he desires.
  *
  * You may not include this software in a program or other software product
- * without supplying the source, or without informing the end-user that the 
+ * without supplying the source, or without informing the end-user that the
  * source is available for no extra charge.
  *
  * If you modify this software, you should include a notice giving the
  * name of the person performing the modification, the date of modification,
  * and the reason for such modification.
  */
-/* 
+/*
  * rle_addhist.c - Add to the HISTORY comment in header
- * 
+ *
  * Author:  Andrew Marriott.
- *      School of Computer Science 
+ *      School of Computer Science
  *      Curtin University of Technology
  * Date:    Mon Sept 10 1988
  * Copyright (c) 1988, Curtin University of Technology
@@ -35,7 +35,7 @@
 
 /*****************************************************************
  * TAG( rle_addhist )
- * 
+ *
  * Put a history comment into the header struct.
  * Inputs:
  *  argv:       Command line history to add to comments.
@@ -68,7 +68,7 @@ rle_addhist(char *          argv[],
 
     if (getenv("NO_ADD_RLE_HISTORY"))
         return;
-    
+
     length = 0;
     for (i = 0; argv[i]; ++i)
         length += strlen(argv[i]) +1;   /* length of each arg plus space. */
@@ -83,7 +83,7 @@ rle_addhist(char *          argv[],
         old = rle_getcom(histoire, in_hdr);     /* get old comment. */
     else
         old = NULL;
-    
+
     if (old && *old)
         length += strlen(old);       /* add length if there. */
 
@@ -104,6 +104,6 @@ rle_addhist(char *          argv[],
     strcat(newc,"on ");
     strcat(newc,timedate);         /* \n supplied by time. */
     strcat(newc,padding);          /* to line up multiple histories.*/
-    
+
     rle_putcom(newc, out_hdr);
 }
diff --git a/urt/rle_code.h b/urt/rle_code.h
index 955e7d42..493cdc02 100644
--- a/urt/rle_code.h
+++ b/urt/rle_code.h
@@ -1,50 +1,50 @@
 /*
  * This software is copyrighted as noted below.  It may be freely copied,
- * modified, and redistributed, provided that the copyright notice is 
+ * modified, and redistributed, provided that the copyright notice is
  * preserved on all copies.
- * 
+ *
  * There is no warranty or other guarantee of fitness for this software,
  * it is provided solely "as is".  Bug reports or fixes may be sent
  * to the author, who may or may not act on them as he desires.
  *
  * You may not include this software in a program or other software product
- * without supplying the source, or without informing the end-user that the 
+ * without supplying the source, or without informing the end-user that the
  * source is available for no extra charge.
  *
  * If you modify this software, you should include a notice giving the
  * name of the person performing the modification, the date of modification,
  * and the reason for such modification.
  */
-/* 
+/*
  * rle_code.h - Definitions for Run Length Encoding.
- * 
- * Author:	Spencer W. Thomas
- * 		Computer Science Dept.
- * 		University of Utah
- * Date:	Mon Aug  9 1982
+ *
+ * Author:      Spencer W. Thomas
+ *              Computer Science Dept.
+ *              University of Utah
+ * Date:        Mon Aug  9 1982
  * Copyright (c) 1982 Spencer W. Thomas
- * 
+ *
  * $Header: /usr/users/spencer/src/urt/include/RCS/rle_code.h,v 3.0 90/08/03 15:19:48 spencer Exp $
  */
 
 #ifndef RLE_MAGIC
 
-/* 
+/*
  * Opcode definitions
  */
 
 #define     LONG                0x40
-#define	    RSkipLinesOp	1
-#define	    RSetColorOp		2
-#define	    RSkipPixelsOp	3
-#define	    RByteDataOp		5
-#define	    RRunDataOp		6
-#define	    REOFOp		7
+#define     RSkipLinesOp        1
+#define     RSetColorOp         2
+#define     RSkipPixelsOp       3
+#define     RByteDataOp         5
+#define     RRunDataOp          6
+#define     REOFOp              7
 
-#define     H_CLEARFIRST        0x1	/* clear framebuffer flag */
-#define	    H_NO_BACKGROUND	0x2	/* if set, no bg color supplied */
-#define	    H_ALPHA		0x4   /* if set, alpha channel (-1) present */
-#define	    H_COMMENT		0x8	/* if set, comments present */
+#define     H_CLEARFIRST        0x1   /* clear framebuffer flag */
+#define     H_NO_BACKGROUND     0x2   /* if set, no bg color supplied */
+#define     H_ALPHA             0x4   /* if set, alpha channel (-1) present */
+#define     H_COMMENT           0x8   /* if set, comments present */
 
 struct XtndRsetup
 {
@@ -54,17 +54,16 @@ struct XtndRsetup
             hc_ylen[2];
     char    h_flags,
             h_ncolors,
-	    h_pixelbits,
-	    h_ncmap,
-	    h_cmaplen;
+            h_pixelbits,
+            h_ncmap,
+            h_cmaplen;
 };
-#define	    SETUPSIZE	((4*2)+5)
+#define     SETUPSIZE   ((4*2)+5)
 
 /* "Old" RLE format magic numbers */
-#define	    RMAGIC	('R' << 8)	/* top half of magic number */
-#define	    WMAGIC	('W' << 8)	/* black&white rle image */
+#define     RMAGIC      ('R' << 8)      /* top half of magic number */
+#define     WMAGIC      ('W' << 8)      /* black&white rle image */
 
-#define	    RLE_MAGIC	((short)0xcc52)	/* RLE file magic number */
+#define     RLE_MAGIC   ((short)0xcc52) /* RLE file magic number */
 
 #endif /* RLE_MAGIC */
-
diff --git a/urt/rle_config.h b/urt/rle_config.h
index 57126a18..5923c00d 100644
--- a/urt/rle_config.h
+++ b/urt/rle_config.h
@@ -49,7 +49,7 @@
 
 /* Typedef for void * so we can use it consistently. */
 #ifdef VOID_STAR
-typedef	void *void_star;
+typedef void *void_star;
 #else
 typedef char *void_star;
 #endif
@@ -59,7 +59,7 @@ typedef char *void_star;
  * before including this file.
  */
 #ifndef NO_DECLARE_MALLOC
-#   include <sys/types.h>	/* For size_t. */
+#   include <sys/types.h>       /* For size_t. */
     extern void_star malloc( size_t );
     extern void_star calloc( size_t, size_t );
     extern void_star realloc( void_star, size_t );
@@ -75,12 +75,12 @@ extern char *getenv( CONST_DECL char *name );
      * TAG( bstring bzero )
      * 'Byte string' functions.
      */
-#   define bzero( _str, _n )		memset( _str, '\0', _n )
-#   define bcopy( _from, _to, _count )	memcpy( _to, _from, _count )
+#   define bzero( _str, _n )            memset( _str, '\0', _n )
+#   define bcopy( _from, _to, _count )  memcpy( _to, _from, _count )
 #endif
 
 #ifdef NEED_SETLINEBUF
-#   define setlinebuf( _s )	setvbuf( (_s), NULL, _IOLBF, 0 )
+#   define setlinebuf( _s )     setvbuf( (_s), NULL, _IOLBF, 0 )
 #endif
 
 #endif
diff --git a/urt/rle_error.c b/urt/rle_error.c
deleted file mode 100644
index 702c6e2d..00000000
--- a/urt/rle_error.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * This software is copyrighted as noted below.  It may be freely copied,
- * modified, and redistributed, provided that the copyright notice is 
- * preserved on all copies.
- * 
- * There is no warranty or other guarantee of fitness for this software,
- * it is provided solely "as is".  Bug reports or fixes may be sent
- * to the author, who may or may not act on them as he desires.
- *
- * You may not include this software in a program or other software product
- * without supplying the source, or without informing the end-user that the 
- * source is available for no extra charge.
- *
- * If you modify this software, you should include a notice giving the
- * name of the person performing the modification, the date of modification,
- * and the reason for such modification.
- */
-/* 
- * rle_error.c - Error message stuff for URT.
- * 
- * Author:	Spencer W. Thomas
- * 		EECS Dept.
- * 		University of Michigan
- * Date:	Mon Mar  2 1992
- * Copyright (c) 1992, University of Michigan
- */
-
-#include <string.h>
-
-#include "rle_config.h"
-#include "rle.h"
-
-/*****************************************************************
- * TAG( rle_alloc_error )
- * 
- * Print memory allocation error message and exit.
- * Inputs:
- * 	pgm:		Name of this program.
- * 	name:		Name of memory trying to be allocated.
- * Outputs:
- * 	Prints message and exits.
- *
- * Returns int because it's used in a conditional expression.
- */
-int
-rle_alloc_error( pgm, name )
-CONST_DECL char *pgm, *name;
-{
-    if ( !name )
-	fprintf( stderr, "%s: memory allocation failed.\n", pgm );
-    else
-	fprintf( stderr, "%s: memory allocation failed (no space for %s).\n",
-		 pgm, name );
-
-    exit( RLE_NO_SPACE );
-
-    /* Will some compilers bitch about this because they know exit
-     * doesn't return??
-     */
-    return 0;
-}
-
-/*****************************************************************
- * TAG( rle_get_error )
- * 
- * Print an error message for the return code from rle_get_setup
- * Inputs:
- * 	code:		The return code from rle_get_setup.
- *	pgmname:	Name of this program (argv[0]).
- *	fname:		Name of the input file.
- * Outputs:
- * 	Prints an error message on standard output.
- *	Returns code.
- */
-int
-rle_get_error( code, pgmname, fname )
-int code;
-CONST_DECL char *pgmname;
-CONST_DECL char *fname;
-{
-    if (! fname || strcmp( fname, "-" ) == 0 )
-	fname = "Standard Input";
-
-    switch( code )
-    {
-    case RLE_SUCCESS:		/* success */
-	break;
-
-    case RLE_NOT_RLE:		/* Not an RLE file */
-	fprintf( stderr, "%s: %s is not an RLE file\n",
-		 pgmname, fname );
-	break;
-
-    case RLE_NO_SPACE:			/* malloc failed */
-	fprintf( stderr,
-		 "%s: Malloc failed reading header of file %s\n",
-		 pgmname, fname );
-	break;
-
-    case RLE_EMPTY:
-	fprintf( stderr, "%s: %s is an empty file\n",
-		 pgmname, fname );
-	break;
-
-    case RLE_EOF:
-	fprintf( stderr,
-		 "%s: RLE header of %s is incomplete (premature EOF)\n",
-		 pgmname, fname );
-	break;
-
-    default:
-	fprintf( stderr, "%s: Error encountered reading header of %s\n",
-		 pgmname, fname );
-	break;
-    }
-    return code;
-}
-
-
diff --git a/urt/rle_getcom.c b/urt/rle_getcom.c
index 4226eaaf..a0a1e5ae 100644
--- a/urt/rle_getcom.c
+++ b/urt/rle_getcom.c
@@ -1,27 +1,27 @@
 /*
  * This software is copyrighted as noted below.  It may be freely copied,
- * modified, and redistributed, provided that the copyright notice is 
+ * modified, and redistributed, provided that the copyright notice is
  * preserved on all copies.
- * 
+ *
  * There is no warranty or other guarantee of fitness for this software,
  * it is provided solely "as is".  Bug reports or fixes may be sent
  * to the author, who may or may not act on them as he desires.
  *
  * You may not include this software in a program or other software product
- * without supplying the source, or without informing the end-user that the 
+ * without supplying the source, or without informing the end-user that the
  * source is available for no extra charge.
  *
  * If you modify this software, you should include a notice giving the
  * name of the person performing the modification, the date of modification,
  * and the reason for such modification.
  */
-/* 
+/*
  * rle_getcom.c - Get specific comments from the_hdr structure.
- * 
- * Author:	Spencer W. Thomas
- * 		Computer Science Dept.
- * 		University of Utah
- * Date:	Sun Jan 25 1987
+ *
+ * Author:      Spencer W. Thomas
+ *              Computer Science Dept.
+ *              University of Utah
+ * Date:        Sun Jan 25 1987
  * Copyright (c) 1987, University of Utah
  */
 
@@ -31,21 +31,21 @@
 
 /*****************************************************************
  * TAG( match )
- * 
+ *
  * Match a name against a test string for "name=value" or "name".
  * If it matches name=value, return pointer to value part, if just
  * name, return pointer to NUL at end of string.  If no match, return NULL.
  *
  * Inputs:
- * 	n:	Name to match.  May also be "name=value" to make it easier
- *		to replace comments.
- *	v:	Test string.
+ *      n:      Name to match.  May also be "name=value" to make it easier
+ *              to replace comments.
+ *      v:      Test string.
  * Outputs:
- * 	Returns pointer as above.
+ *      Returns pointer as above.
  * Assumptions:
- *	[None]
+ *      [None]
  * Algorithm:
- *	[None]
+ *      [None]
  */
 static const char *
 match(const char * const nArg,
@@ -69,17 +69,17 @@ match(const char * const nArg,
 
 /*****************************************************************
  * TAG( rle_getcom )
- * 
+ *
  * Return a pointer to the value part of a name=value pair in the comments.
  * Inputs:
- * 	name:		Name part of the comment to search for.
- *	the_hdr:	rle_dflt_hdr structure.
+ *      name:           Name part of the comment to search for.
+ *      the_hdr:        rle_dflt_hdr structure.
  * Outputs:
- * 	Returns pointer to value part of comment or NULL if no match.
+ *      Returns pointer to value part of comment or NULL if no match.
  * Assumptions:
- *	[None]
+ *      [None]
  * Algorithm:
- *	[None]
+ *      [None]
  */
 const char *
 rle_getcom(const char * const name,
diff --git a/urt/rle_getrow.c b/urt/rle_getrow.c
index 679811cc..a24870ac 100644
--- a/urt/rle_getrow.c
+++ b/urt/rle_getrow.c
@@ -1,14 +1,14 @@
 /*
  * This software is copyrighted as noted below.  It may be freely copied,
- * modified, and redistributed, provided that the copyright notice is 
+ * modified, and redistributed, provided that the copyright notice is
  * preserved on all copies.
- * 
+ *
  * There is no warranty or other guarantee of fitness for this software,
  * it is provided solely "as is".  Bug reports or fixes may be sent
  * to the author, who may or may not act on them as he desires.
  *
  * You may not include this software in a program or other software product
- * without supplying the source, or without informing the end-user that the 
+ * without supplying the source, or without informing the end-user that the
  * source is available for no extra charge.
  *
  * If you modify this software, you should include a notice giving the
@@ -18,15 +18,15 @@
  *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
  *  to have all "void" functions so declared.
  */
-/* 
+/*
  * rle_getrow.c - Read an RLE file in.
- * 
+ *
  * Author:  Spencer W. Thomas
  *      Computer Science Dept.
  *      University of Utah
  * Date:    Wed Apr 10 1985
  * Copyright (c) 1985 Spencer W. Thomas
- * 
+ *
  * $Id: rle_getrow.c,v 3.0.1.5 1992/03/04 19:33:08 spencer Exp spencer $
  */
 
@@ -43,7 +43,7 @@
 /* Read a two-byte "short" that started in VAX (LITTLE_ENDIAN) order */
 #define VAXSHORT( var, fp )\
     { var = fgetc(fp)&0xFF; var |= (fgetc(fp)) << 8; }
-  
+
 /* Instruction format -- first byte is opcode, second is datum. */
 
 #define OPCODE(inst) (inst[0] & ~LONG)
@@ -77,7 +77,7 @@ rle_get_setup(rle_hdr * const the_hdr) {
     FILE * infile = the_hdr->rle_file;
     int i;
     char * comment_buf;
-    
+
     /* Clear old stuff out of the header. */
     rle_hdr_clear(the_hdr);
     if (the_hdr->is_init != RLE_INIT_MAGIC)
@@ -102,9 +102,13 @@ rle_get_setup(rle_hdr * const the_hdr) {
         rle_pixel * bg_color;
 
         MALLOCARRAY(the_hdr->bg_color, setup.h_ncolors);
+        if (!the_hdr->bg_color)
+            pm_error("Failed to allocation array for %u background colors",
+                     setup.h_ncolors);
         MALLOCARRAY(bg_color, 1 + (setup.h_ncolors / 2) * 2);
-        RLE_CHECK_ALLOC(the_hdr->cmd, the_hdr->bg_color && bg_color,
-                        "background color" );
+        if (!bg_color)
+            pm_error("Failed to allocation array for %u background colors",
+                     1+(setup.h_ncolors / 2) * 2);
         fread((char *)bg_color, 1, 1 + (setup.h_ncolors / 2) * 2, infile);
         for (i = 0; i < setup.h_ncolors; ++i)
             the_hdr->bg_color[i] = bg_color[i];
@@ -163,7 +167,7 @@ rle_get_setup(rle_hdr * const the_hdr) {
         evenlen = (comlen + 1) & ~1;    /* make it even */
         if (evenlen) {
             MALLOCARRAY(comment_buf, evenlen);
-    
+
             if (comment_buf == NULL) {
                 pm_error("Malloc failed for comment buffer of size %d "
                          "in rle_get_setup, reading '%s'",
@@ -214,78 +218,13 @@ rle_get_setup(rle_hdr * const the_hdr) {
 
 
 
-void
-rle_get_setup_ok(rle_hdr *    const the_hdr,
-                 const char * const prog_name,
-                 const char * const file_name) {
-/*-----------------------------------------------------------------------------
-  Read the initialization information from an RLE file.
-
-  Inputs:
-   the_hdr:    Contains pointer to the input file.
-   prog_name:  Program name to be printed in the error message.
-       file_name:  File name to be printed in the error message.
-                   If NULL, the string "stdin" is generated.
-
-  Outputs:
-   the_hdr:    Initialized with information from the input file.
-       If reading the header fails, it prints an error message
-       and exits with the appropriate status code.
-  Algorithm:
-   rle_get_setup does all the work.
----------------------------------------------------------------------------- */
-    int code;
-
-    /* Backwards compatibility: if is_init is not properly set, 
-     * initialize the header.
-     */
-    if (the_hdr->is_init != RLE_INIT_MAGIC) {
-        FILE * const f = the_hdr->rle_file;
-        rle_hdr_init( the_hdr );
-        the_hdr->rle_file = f;
-        rle_names(the_hdr, prog_name, file_name, 0);
-    }
-
-    code = rle_get_error(rle_get_setup(the_hdr),
-                         the_hdr->cmd, the_hdr->file_name);
-    if (code)
-        exit(code);
-}
-
-
-
-void
-rle_debug( on_off )
-    int on_off;
-{
-/*-----------------------------------------------------------------------------
-  Turn RLE debugging on or off.
-  Inputs:
-   on_off:     if 0, stop debugging, else start.
-  Outputs:
-   Sets internal debug flag.
-  Assumptions:
-   [None]
-  Algorithm:
-   [None]
----------------------------------------------------------------------------- */
-    debug_f = on_off;
-
-    /* Set line buffering on stderr.  Character buffering is the default, and
-     * it is SLOOWWW for large amounts of output.
-     */
-    setvbuf(stderr, NULL, _IOLBF, 0);
-}
-
-
-
 int
 rle_getrow(rle_hdr *    const the_hdr,
            rle_pixel ** const scanline) {
 /*-----------------------------------------------------------------------------
   Get a scanline from the input file.
   Inputs:
-   the_hdr:    Header structure containing information about 
+   the_hdr:    Header structure containing information about
            the input file.
   Outputs:
    scanline:   an array of pointers to the individual color
@@ -300,10 +239,10 @@ rle_getrow(rle_hdr *    const the_hdr,
    specified (the_hdr->background is true), just set the
    scanlines to the background color.  If clear-to-background is
    not set, just increment the scanline number and return.
-  
+
    Otherwise, read input until a vertical skip is encountered,
    decoding the instructions into scanline data.
- 
+
    If ymax is reached (or, somehow, passed), continue reading and
    discarding input until end of image.
 ---------------------------------------------------------------------------- */
diff --git a/urt/rle_getskip.c b/urt/rle_getskip.c
index 1366e162..3d36fba4 100644
--- a/urt/rle_getskip.c
+++ b/urt/rle_getskip.c
@@ -1,27 +1,27 @@
 /*
  * This software is copyrighted as noted below.  It may be freely copied,
- * modified, and redistributed, provided that the copyright notice is 
+ * modified, and redistributed, provided that the copyright notice is
  * preserved on all copies.
- * 
+ *
  * There is no warranty or other guarantee of fitness for this software,
  * it is provided solely "as is".  Bug reports or fixes may be sent
  * to the author, who may or may not act on them as he desires.
  *
  * You may not include this software in a program or other software product
- * without supplying the source, or without informing the end-user that the 
+ * without supplying the source, or without informing the end-user that the
  * source is available for no extra charge.
  *
  * If you modify this software, you should include a notice giving the
  * name of the person performing the modification, the date of modification,
  * and the reason for such modification.
  */
-/* 
+/*
  * rle_getskip.c - Skip scanlines on input.
- * 
- * Author:	Spencer W. Thomas
- * 		EECS Dept.
- * 		University of Michigan
- * Date:	Wed Jun 27 1990
+ *
+ * Author:      Spencer W. Thomas
+ *              EECS Dept.
+ *              University of Michigan
+ * Date:        Wed Jun 27 1990
  * Copyright (c) 1990, University of Michigan
  */
 
@@ -32,133 +32,133 @@
 
 /* Read a two-byte "short" that started in VAX (LITTLE_ENDIAN) order */
 #define VAXSHORT( var, fp )\
-	{ var = fgetc(fp)&0xFF; var |= (fgetc(fp)) << 8; }
-  
+        { var = fgetc(fp)&0xFF; var |= (fgetc(fp)) << 8; }
+
 /* Instruction format -- first byte is opcode, second is datum. */
 
 #define OPCODE(inst) (inst[0] & ~LONG)
 #define LONGP(inst) (inst[0] & LONG)
-#define DATUM(inst) (inst[1] & 0xff)	/* Make sure it's unsigned. */
+#define DATUM(inst) (inst[1] & 0xff)    /* Make sure it's unsigned. */
 
 /*****************************************************************
  * TAG( rle_getskip )
- * 
+ *
  * Skip the next scanline with data on it.
  * Most useful for skipping to end-of-image.
  * Inputs:
- * 	the_hdr:	Describes input image.
+ *      the_hdr:        Describes input image.
  * Outputs:
- * 	Returns the number of the next scanline.  At EOF returns 32768.
+ *      Returns the number of the next scanline.  At EOF returns 32768.
  * Assumptions:
- * 	rle_get_setup has been called.
+ *      rle_get_setup has been called.
  * Algorithm:
- * 	Read input to the beginning of the next scanline, or to EOF or
- * 	end of image.
+ *      Read input to the beginning of the next scanline, or to EOF or
+ *      end of image.
  */
 unsigned int
 rle_getskip( the_hdr )
 rle_hdr *the_hdr;
 {
     unsigned char inst[2];
-    register FILE *infile = the_hdr->rle_file;
+    FILE *infile = the_hdr->rle_file;
     int nc;
 
     /* Add in vertical skip from last scanline */
-    if ( the_hdr->priv.get.vert_skip > 0) 
-	the_hdr->priv.get.scan_y += the_hdr->priv.get.vert_skip;
+    if ( the_hdr->priv.get.vert_skip > 0)
+        the_hdr->priv.get.scan_y += the_hdr->priv.get.vert_skip;
     the_hdr->priv.get.vert_skip = 0;
 
     if ( the_hdr->priv.get.is_eof )
-	return 32768;		/* too big for 16 bits, signal EOF */
-    
+        return 32768;           /* too big for 16 bits, signal EOF */
+
     /* Otherwise, read and interpret instructions until a skipLines
      * instruction is encountered.
      */
     for (;;)
     {
         inst[0] = getc( infile );
-	inst[1] = getc( infile );
-	if ( feof(infile) )
-	{
-	    the_hdr->priv.get.is_eof = 1;
-	    break;		/* <--- one of the exits */
-	}
-
-	switch( OPCODE(inst) )
-	{
-	case RSkipLinesOp:
-	    if ( LONGP(inst) )
-	    {
-		VAXSHORT( the_hdr->priv.get.vert_skip, infile );
-	    }
-	    else
-		the_hdr->priv.get.vert_skip = DATUM(inst);
-	    break;			/* need to break for() here, too */
-
-	case RSetColorOp:
-	    /* No-op here. */
-	    break;
-
-	case RSkipPixelsOp:
-	    if ( LONGP(inst) )
-	    {
-		(void)getc( infile );
-		(void)getc( infile );
-	    }
-	    break;
-
-	case RByteDataOp:
-	    if ( LONGP(inst) )
-	    {
-	        VAXSHORT( nc, infile );
-	    }
-	    else
-		nc = DATUM(inst);
-	    nc++;
-	    if ( the_hdr->priv.get.is_seek )
-		fseek( infile, ((nc + 1) / 2) * 2, 1 );
-	    else
-	    {
-		register int ii;
-		for ( ii = ((nc + 1) / 2) * 2; ii > 0; ii-- )
-		    (void) getc( infile );	/* discard it */
-	    }
-
-	    break;
-
-	case RRunDataOp:
-	    if ( LONGP(inst) )
-	    {
-		(void)getc( infile );
-		(void)getc( infile );
-	    }
-	    (void)getc( infile );
-	    (void)getc( infile );
-	    break;
-
-	case REOFOp:
-	    the_hdr->priv.get.is_eof = 1;
-	    break;
-
-	default:
-	    fprintf( stderr,
-		     "%s: rle_getskip: Unrecognized opcode: %d, reading %s\n",
-		     the_hdr->cmd, OPCODE(inst), the_hdr->file_name );
-	    exit(1);
-	}
-	if ( OPCODE(inst) == REOFOp )
-	    break;			/* <--- the other loop exit */
-	if ( OPCODE(inst) == RSkipLinesOp )
-	    break;
+        inst[1] = getc( infile );
+        if ( feof(infile) )
+        {
+            the_hdr->priv.get.is_eof = 1;
+            break;              /* <--- one of the exits */
+        }
+
+        switch( OPCODE(inst) )
+        {
+        case RSkipLinesOp:
+            if ( LONGP(inst) )
+            {
+                VAXSHORT( the_hdr->priv.get.vert_skip, infile );
+            }
+            else
+                the_hdr->priv.get.vert_skip = DATUM(inst);
+            break;                      /* need to break for() here, too */
+
+        case RSetColorOp:
+            /* No-op here. */
+            break;
+
+        case RSkipPixelsOp:
+            if ( LONGP(inst) )
+            {
+                (void)getc( infile );
+                (void)getc( infile );
+            }
+            break;
+
+        case RByteDataOp:
+            if ( LONGP(inst) )
+            {
+                VAXSHORT( nc, infile );
+            }
+            else
+                nc = DATUM(inst);
+            nc++;
+            if ( the_hdr->priv.get.is_seek )
+                fseek( infile, ((nc + 1) / 2) * 2, 1 );
+            else
+            {
+                int ii;
+                for ( ii = ((nc + 1) / 2) * 2; ii > 0; ii-- )
+                    (void) getc( infile );      /* discard it */
+            }
+
+            break;
+
+        case RRunDataOp:
+            if ( LONGP(inst) )
+            {
+                (void)getc( infile );
+                (void)getc( infile );
+            }
+            (void)getc( infile );
+            (void)getc( infile );
+            break;
+
+        case REOFOp:
+            the_hdr->priv.get.is_eof = 1;
+            break;
+
+        default:
+            fprintf( stderr,
+                     "%s: rle_getskip: Unrecognized opcode: %d, reading %s\n",
+                     the_hdr->cmd, OPCODE(inst), the_hdr->file_name );
+            exit(1);
+        }
+        if ( OPCODE(inst) == REOFOp )
+            break;                      /* <--- the other loop exit */
+        if ( OPCODE(inst) == RSkipLinesOp )
+            break;
     }
 
     /* Return the number of the NEXT scanline. */
     the_hdr->priv.get.scan_y +=
-	the_hdr->priv.get.vert_skip;
+        the_hdr->priv.get.vert_skip;
     the_hdr->priv.get.vert_skip = 0;
 
     if ( the_hdr->priv.get.is_eof )
-	return 32768;		/* too big for 16 bits, signal EOF */
+        return 32768;           /* too big for 16 bits, signal EOF */
     else
-	return the_hdr->priv.get.scan_y;
+        return the_hdr->priv.get.scan_y;
 }
diff --git a/urt/rle_global.c b/urt/rle_global.c
index 6014a229..f7228ea9 100644
--- a/urt/rle_global.c
+++ b/urt/rle_global.c
@@ -1,14 +1,14 @@
 /*
  * This software is copyrighted as noted below.  It may be freely copied,
- * modified, and redistributed, provided that the copyright notice is 
+ * modified, and redistributed, provided that the copyright notice is
  * preserved on all copies.
- * 
+ *
  * There is no warranty or other guarantee of fitness for this software,
  * it is provided solely "as is".  Bug reports or fixes may be sent
  * to the author, who may or may not act on them as he desires.
  *
  * You may not include this software in a program or other software product
- * without supplying the source, or without informing the end-user that the 
+ * without supplying the source, or without informing the end-user that the
  * source is available for no extra charge.
  *
  * If you modify this software, you should include a notice giving the
@@ -18,15 +18,15 @@
  *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
  *  to have all "void" functions so declared.
  */
-/* 
+/*
  * rle_global.c - Global variable initialization for rle routines.
- * 
- * Author:	Spencer W. Thomas
- * 		Computer Science Dept.
- * 		University of Utah
- * Date:	Thu Apr 25 1985
+ *
+ * Author:      Spencer W. Thomas
+ *              Computer Science Dept.
+ *              University of Utah
+ * Date:        Thu Apr 25 1985
  * Copyright (c) 1985,1986 Spencer W. Thomas
- * 
+ *
  * $Id: rle_global.c,v 3.0.1.1 1992/01/28 18:23:03 spencer Exp $
  */
 
@@ -39,40 +39,40 @@
 
 struct rle_dispatch_tab rle_DTable[] = {
     {
-	" OB",
-	RunSetup,
-	RunSkipBlankLines,
-	RunSetColor,
-	RunSkipPixels,
-	RunNewScanLine,
-	Runputdata,
-	Runputrun,
-	DefaultBlockHook,
-	RunputEof
+        " OB",
+        RunSetup,
+        RunSkipBlankLines,
+        RunSetColor,
+        RunSkipPixels,
+        RunNewScanLine,
+        Runputdata,
+        Runputrun,
+        DefaultBlockHook,
+        RunputEof
     },
 };
 
 static int bg_color[3] = { 0, 0, 0 };
 
 rle_hdr rle_dflt_hdr = {
-    RUN_DISPATCH,		/* dispatch value */
-    3,				/* 3 colors */
-    bg_color,			/* background color */
-    0,				/* (alpha) if 1, save alpha channel */
-    2,				/* (background) 0->just save pixels, */
-				/* 1->overlay, 2->clear to bg first */
-    0, 511,			/* (xmin, xmax) X bounds to save */
-    0, 511,			/* (ymin, ymax) Y bounds to save */
-    0,				/* ncmap (if != 0, save color map) */
-    8,				/* cmaplen (log2 of length of color map) */
-    NULL,			/* pointer to color map */
-    NULL,			/* pointer to comment strings */
-    NULL,			/* output file -- must be set dynamically */
-    { 7 },			/* RGB channels only */
-    0L,				/* Can't free name and file fields. */
-    "Urt",			/* Default "program name". */
-    "no file",			/* No file name given. */
-    0				/* First image. */
+    RUN_DISPATCH,               /* dispatch value */
+    3,                          /* 3 colors */
+    bg_color,                   /* background color */
+    0,                          /* (alpha) if 1, save alpha channel */
+    2,                          /* (background) 0->just save pixels, */
+                                /* 1->overlay, 2->clear to bg first */
+    0, 511,                     /* (xmin, xmax) X bounds to save */
+    0, 511,                     /* (ymin, ymax) Y bounds to save */
+    0,                          /* ncmap (if != 0, save color map) */
+    8,                          /* cmaplen (log2 of length of color map) */
+    NULL,                       /* pointer to color map */
+    NULL,                       /* pointer to comment strings */
+    NULL,                       /* output file -- must be set dynamically */
+    { 7 },                      /* RGB channels only */
+    0L,                         /* Can't free name and file fields. */
+    "Urt",                      /* Default "program name". */
+    "no file",                  /* No file name given. */
+    0                           /* First image. */
     /* Can't initialize the union */
 };
 
@@ -82,6 +82,6 @@ void
 NullputEof(the_hdr)
 rle_hdr * the_hdr;
 {
-				/* do nothing */
+                                /* do nothing */
 }
 #endif
diff --git a/urt/rle_hdr.c b/urt/rle_hdr.c
index 1611324c..8ceaa9eb 100644
--- a/urt/rle_hdr.c
+++ b/urt/rle_hdr.c
@@ -1,298 +1,286 @@
 /*
  * This software is copyrighted as noted below.  It may be freely copied,
- * modified, and redistributed, provided that the copyright notice is 
+ * modified, and redistributed, provided that the copyright notice is
  * preserved on all copies.
- * 
+ *
  * There is no warranty or other guarantee of fitness for this software,
  * it is provided solely "as is".  Bug reports or fixes may be sent
  * to the author, who may or may not act on them as he desires.
  *
  * You may not include this software in a program or other software product
- * without supplying the source, or without informing the end-user that the 
+ * without supplying the source, or without informing the end-user that the
  * source is available for no extra charge.
  *
  * If you modify this software, you should include a notice giving the
  * name of the person performing the modification, the date of modification,
  * and the reason for such modification.
  */
-/* 
+/*
  * rle_hdr.c - Functions to manipulate rle_hdr structures.
- * 
- * Author:	Spencer W. Thomas
- * 		EECS Dept.
- * 		University of Michigan
- * Date:	Mon May 20 1991
+ *
+ * Author:  Spencer W. Thomas
+ *      EECS Dept.
+ *      University of Michigan
+ * Date:    Mon May 20 1991
  * Copyright (c) 1991, University of Michigan
  */
 
 #include <string.h>
 
+#include "nstring.h"
+#include "mallocvar.h"
+
 #include "rle_config.h"
 #include "rle.h"
 
-/*****************************************************************
- * TAG( rle_names )
- *
+
+
+void
+rle_names(rle_hdr *    const hdrP,
+          const char * const pgmname,
+          const char * const fname,
+          int          const imgNum) {
+/*----------------------------------------------------------------------------
  * Load program and file names into header.
  * Inputs:
- * 	the_hdr:	Header to modify.
- * 	pgmname:	The program name.
- * 	fname:		The file name.
- * 	img_num:	Number of the image within the file.
+ *  hdrP:      Header to modify.
+ *  pgmname:   The program name.
+ *  fname:     The file name.
+ *  imgNum:    Number of the image within the file.
  * Outputs:
- * 	the_hdr:	Modified header.
- * Algorithm:
- * 	If values previously filled in (by testing is_init field),
- * 	free them.  Make copies of file name and program name,
- * 	modifying file name for standard i/o.  Set is_init field.
- */
-void
-rle_names( the_hdr, pgmname, fname, img_num )
-rle_hdr *the_hdr;
-CONST_DECL char *pgmname;
-CONST_DECL char *fname;
-int img_num;
-{
-#if 0
-    /* Can't do this because people do hdr1 = hdr2, which copies
-       the pointers. */
-
-    /* If filled in, free previous values. */
-    if ( the_hdr->is_init == RLE_INIT_MAGIC &&
-	 the_hdr->cmd != NULL && the_hdr->file_name != NULL )
-    {
-	if ( pgmname != the_hdr->cmd )
-	    free( the_hdr->cmd );
-	if ( fname != the_hdr->file_name )
-	    free( the_hdr->file_name );
-    }
-#endif
+ *  *hdrP:     Modified header.
+-----------------------------------------------------------------------------*/
+
+    /* Algorithm:
+       If values previously filled in (by testing is_init field),
+       free them.  Make copies of file name and program name,
+       modifying file name for standard i/o.  Set is_init field.
+    */
+    const char * newFname;
+    const char * newPgmname;
 
     /* Mark as filled in. */
-    the_hdr->is_init = RLE_INIT_MAGIC;
+    hdrP->is_init = RLE_INIT_MAGIC;
 
     /* Default file name for stdin/stdout. */
-    if ( fname == NULL || strcmp( fname, "-" ) == 0 || *fname == '\0' )
-	fname = "Standard I/O";
-    if ( pgmname == NULL )
-	pgmname = rle_dflt_hdr.cmd;
+    if (!fname || streq(fname, "-") || strlen(fname) == 0)
+        newFname = "Standard I/O";
+    else
+        newFname = fname;
+
+    if (pgmname)
+        newPgmname = pgmname;
+    else
+        newPgmname = rle_dflt_hdr.cmd;
 
     /* Fill in with copies of the strings. */
-    if ( the_hdr->cmd != pgmname )
-    {
-	char *tmp = (char *)malloc( strlen( pgmname ) + 1 );
-	RLE_CHECK_ALLOC( pgmname, tmp, 0 );
-	strcpy( tmp, pgmname );
-	the_hdr->cmd = tmp;
-    }
+    if (hdrP->cmd != newPgmname)
+        hdrP->cmd = pm_strdup(newPgmname);
 
-    if ( the_hdr->file_name != fname )
-    {
-	char *tmp = (char *)malloc( strlen( fname ) + 1 );
-	RLE_CHECK_ALLOC( pgmname, tmp, 0 );
-	strcpy( tmp, fname );
-	the_hdr->file_name = tmp;
-    }
+    if (hdrP->file_name != newFname)
+        hdrP->file_name = pm_strdup(newFname);
 
-    the_hdr->img_num = img_num;
+    hdrP->img_num = imgNum;
 }
 
 
+
 /* Used by rle_hdr_cp and rle_hdr_init to avoid recursion loops. */
-static int no_recurse = 0;
+static int noRecurse = 0;
 
-/*****************************************************************
- * TAG( rle_hdr_cp )
- * 
+
+
+rle_hdr *
+rle_hdr_cp(rle_hdr * const fromHdrP,
+           rle_hdr * const toHdrArgP) {
+/*----------------------------------------------------------------------------
  * Make a "safe" copy of a rle_hdr structure.
  * Inputs:
- * 	from_hdr:	Header to be copied.
+ *  *fromHdrP:   Header to be copied.
  * Outputs:
- * 	to_hdr:		Copy of from_hdr, with all memory referred to
- * 			by pointers copied.  Also returned as function
- * 			value.  If NULL, a static header is used.
+ *  *toHdrPd:    Copy of from_hdr, with all memory referred to
+ *               by pointers copied.  Also returned as function
+ *               value.  If NULL, a static header is used.
  * Assumptions:
- * 	It is safe to call rle_hdr_init on to_hdr.
- * Algorithm:
- * 	Initialize to_hdr, copy from_hdr to it, then copy the memory
- * 	referred to by all non-null pointers.
- */
-rle_hdr *
-rle_hdr_cp( from_hdr, to_hdr )
-rle_hdr *from_hdr, *to_hdr;
-{
-    static rle_hdr dflt_hdr;
-    CONST_DECL char *cmd, *file;
-    int num;
+ *  It is safe to call rle_hdr_init on *toHdrP.
+-----------------------------------------------------------------------------*/
+    /* Algorithm:
+       Initialize *toHdrP, copy *fromHdrP to it, then copy the memory
+       referred to by all non-null pointers.
+    */
+    static rle_hdr dfltHdr;
+    rle_hdr * toHdrP;
+    const char * cmd;
+    const char * file;
+    unsigned int num;
 
     /* Save command, file name, and image number if already initialized. */
-    if ( to_hdr &&  to_hdr->is_init == RLE_INIT_MAGIC )
-    {
-	cmd = to_hdr->cmd;
-	file = to_hdr->file_name;
-	num = to_hdr->img_num;
-    }
-    else
-    {
-	cmd = file = NULL;
-	num = 0;
+    if (toHdrArgP &&  toHdrArgP->is_init == RLE_INIT_MAGIC) {
+        cmd  = toHdrArgP->cmd;
+        file = toHdrArgP->file_name;
+        num  = toHdrArgP->img_num;
+    } else {
+        cmd = file = NULL;
+        num = 0;
     }
 
-    if ( !no_recurse )
-    {
-	no_recurse++;
-	rle_hdr_init( to_hdr );
-	no_recurse--;
+    if (!noRecurse) {
+        ++noRecurse;
+        rle_hdr_init(toHdrArgP);
+        --noRecurse;
     }
 
-    if ( to_hdr == NULL )
-	to_hdr = &dflt_hdr;
+    toHdrP = toHdrArgP ? toHdrArgP : &dfltHdr;
+
+    *toHdrP = *fromHdrP;
 
-    *to_hdr = *from_hdr;
+    if (toHdrP->bg_color) {
+        unsigned int i;
 
-    if ( to_hdr->bg_color )
-    {
-	int size = to_hdr->ncolors * sizeof(int);
-	to_hdr->bg_color = (int *)malloc( size );
-	RLE_CHECK_ALLOC( to_hdr->cmd, to_hdr->bg_color, "background color" );
-	memcpy( to_hdr->bg_color, from_hdr->bg_color, size );
+        MALLOCARRAY(toHdrP->bg_color, toHdrP->ncolors);
+        if (!toHdrP->bg_color)
+            pm_error("Failed to allocate array for %u background colors",
+                     toHdrP->ncolors);
+        for (i = 0; i < toHdrP->ncolors; ++i)
+            toHdrP->bg_color[i] = fromHdrP->bg_color[i];
     }
 
-    if ( to_hdr->cmap )
-    {
-	int size = to_hdr->ncmap * (1 << to_hdr->cmaplen) * sizeof(rle_map);
-	to_hdr->cmap = (rle_map *)malloc( size );
-	RLE_CHECK_ALLOC( to_hdr->cmd, to_hdr->cmap, "color map" );
-	memcpy( to_hdr->cmap, from_hdr->cmap, size );
+    if (toHdrP->cmap) {
+        size_t const size =
+            toHdrP->ncmap * (1 << toHdrP->cmaplen) * sizeof(rle_map);
+        toHdrP->cmap = malloc(size);
+        if (!toHdrP->cmap)
+            pm_error("Failed to allocate memory for %u color maps "
+                     "of length %u", toHdrP->ncmap, 1 << toHdrP->cmaplen);
+        memcpy(toHdrP->cmap, fromHdrP->cmap, size);
     }
 
     /* Only copy array of pointers, as the original comment memory
      * never gets overwritten.
      */
-    if ( to_hdr->comments )
-    {
-	int size = 0;
-	CONST_DECL char **cp;
-	for ( cp=to_hdr->comments; *cp; cp++ )
-	    size++;		/* Count the comments. */
-	/* Check if there are really any comments. */
-	if ( size )
-	{
-	    size++;		/* Copy the NULL pointer, too. */
-	    size *= sizeof(char *);
-	    to_hdr->comments = (CONST_DECL char **)malloc( size );
-	    RLE_CHECK_ALLOC( to_hdr->cmd, to_hdr->comments, "comments" );
-	    memcpy( to_hdr->comments, from_hdr->comments, size );
-	}
-	else
-	    to_hdr->comments = NULL;	/* Blow off empty comment list. */
+    if (toHdrP->comments) {
+        unsigned int  size;
+        const char ** cp;
+
+        /* Count the comments. */
+        for (cp = toHdrP->comments, size = 0; *cp; ++cp)
+            ++size;
+
+        /* Check if there are really any comments. */
+        if (size > 0) {
+            ++size;     /* Copy the NULL pointer, too. */
+            size *= sizeof(char *);
+            toHdrP->comments = malloc(size);
+            if (!toHdrP->comments)
+                pm_error("Failed to allocation %u bytes for comments", size);
+            memcpy(toHdrP->comments, fromHdrP->comments, size);
+        } else
+            toHdrP->comments = NULL;    /* Blow off empty comment list. */
     }
 
     /* Restore the names to their original values. */
-    to_hdr->cmd = cmd;
-    to_hdr->file_name = file;
+    toHdrP->cmd       = cmd;
+    toHdrP->file_name = file;
 
     /* Lines above mean nothing much happens if cmd and file are != NULL. */
-    rle_names( to_hdr, to_hdr->cmd, to_hdr->file_name, num );
+    rle_names(toHdrP, toHdrP->cmd, toHdrP->file_name, num);
 
-    return to_hdr;
+    return toHdrP;
 }
 
-/*****************************************************************
- * TAG( rle_hdr_clear )
- * 
+
+
+void
+rle_hdr_clear(rle_hdr * const hdrP) {
+/*----------------------------------------------------------------------------
  * Clear out the allocated memory pieces of a header.
  *
  * This routine is intended to be used internally by the library, to
  * clear a header before putting new data into it.  It clears all the
  * fields that would be set by reading in a new image header.
  * Therefore, it does not clear the program and file names.
- * 
+ *
  * Inputs:
- * 	the_hdr:	To be cleared.
+ *  hdrP:    To be cleared.
  * Outputs:
- * 	the_hdr:	After clearing.
+ *  *hdrP:   After clearing.
  * Assumptions:
- * 	If is_init field is RLE_INIT_MAGIC, the header has been
- * 	properly initialized.  This will fail every 2^(-32) times, on
- * 	average.
- * Algorithm:
- * 	Free memory and set to zero all pointers, except program and
- * 	file name.
- */
-void
-rle_hdr_clear( the_hdr )
-rle_hdr *the_hdr;
-{
+ *  If is_init field is RLE_INIT_MAGIC, the header has been
+ *  properly initialized.  This will fail every 2^(-32) times, on
+ *  average.
+-----------------------------------------------------------------------------*/
+    /* Algorithm:
+       Free memory and set to zero all pointers, except program and
+       file name.
+    */
+
     /* Try to free memory.  Assume if is_init is properly set that this
      * header has been previously initialized, therefore it is safe to
      * free memory.
      */
-    if ( the_hdr && the_hdr->is_init == RLE_INIT_MAGIC )
-    {
-	if ( the_hdr->bg_color )
-	    free( the_hdr->bg_color );
-	the_hdr->bg_color = 0;
-	if ( the_hdr->cmap )
-	    free( the_hdr->cmap );
-	the_hdr->cmap = 0;
-	/* Unfortunately, we don't know how to free the comment memory. */
-	if ( the_hdr->comments )
-	    free( the_hdr->comments );
-	the_hdr->comments = 0;
+    if (hdrP && hdrP->is_init == RLE_INIT_MAGIC) {
+        if (hdrP->bg_color )
+            free(hdrP->bg_color);
+        hdrP->bg_color = NULL;
+        if (hdrP->cmap )
+            free(hdrP->cmap);
+        hdrP->cmap = NULL;
+        /* Unfortunately, we don't know how to free the comment memory. */
+        if (hdrP->comments)
+            free(hdrP->comments);
+        hdrP->comments = NULL;
     }
 }
 
 
 
-/*****************************************************************
- * TAG( rle_hdr_init )
- * 
+rle_hdr *
+rle_hdr_init(rle_hdr * const hdrP) {
+/*----------------------------------------------------------------------------
  * Initialize a rle_hdr structure.
  * Inputs:
- * 	the_hdr:	Header to be initialized.
+ *  hdrP:    Header to be initialized.
  * Outputs:
- * 	the_hdr:	Initialized header.
+ *  *hdrP:   Initialized header.
  * Assumptions:
- * 	If the_hdr->is_init is RLE_INIT_MAGIC, the header has been
- * 	previously initialized.
- * 	If the_hdr is a copy of another rle_hdr structure, the copy
- * 	was made with rle_hdr_cp.
- * Algorithm:
- *  Fill in fields of rle_dflt_hdr that could not be set by the loader
- *	If the_hdr is rle_dflt_hdr, do nothing else
- *  Else:
- *	  If the_hdr is NULL, return a copy of rle_dflt_hdr in static storage
- * 	  If the_hdr->is_init is RLE_INIT_MAGIC, free all memory
- * 	     pointed to by non-null pointers.
- *    If this is a recursive call to rle_hdr_init, clear *the_hdr and
- *      return the_hdr.
- *    Else make a copy of rle_dflt_hdr and return its address.  Make the
- *      copy in static storage if the_hdr is NULL, and in the_hdr otherwise.
- */
-rle_hdr *
-rle_hdr_init( the_hdr )
-rle_hdr *the_hdr;
-{
-    rle_hdr *ret_hdr;
+ *  If hdrP->is_init is RLE_INIT_MAGIC, the header has been
+ *  previously initialized.
+ *  If the_hdr is a copy of another rle_hdr structure, the copy
+ *  was made with rle_hdr_cp.
+-----------------------------------------------------------------------------*/
+    /* Algorithm:
+       Fill in fields of rle_dflt_hdr that could not be set by the loader
+       If the_hdr is rle_dflt_hdr, do nothing else
+       Else:
+         If hdrP is NULL, return a copy of rle_dflt_hdr in static storage
+         If hdrP->is_init is RLE_INIT_MAGIC, free all memory
+            pointed to by non-null pointers.
+         If this is a recursive call to rle_hdr_init, clear *hdrP and
+           return hdrP.
+         Else make a copy of rle_dflt_hdr and return its address.  Make the
+           copy in static storage if hdrP is NULL, and in *hdrP otherwise.
+    */
+    rle_hdr * retval;
 
     rle_dflt_hdr.rle_file = stdout;
-    /* The rest of rle_dflt_hdr is set by the loader's data initialization */
 
-    if ( the_hdr == &rle_dflt_hdr )
-	return the_hdr;
+    /* The rest of rle_dflt_hdr is set by the loader's data initialization */
 
-    rle_hdr_clear( the_hdr );
+    if (hdrP == &rle_dflt_hdr)
+        retval = hdrP;
+    else {
+        rle_hdr_clear(hdrP);
 
-    /* Only call rle_hdr_cp if not called from there. */
-    if ( !no_recurse )
-    {
-	no_recurse++;
-	ret_hdr = rle_hdr_cp( &rle_dflt_hdr, the_hdr );
-	no_recurse--;
+        /* Call rle_hdr_cp only if not called from there. */
+        if (!noRecurse) {
+            ++noRecurse;
+            retval = rle_hdr_cp(&rle_dflt_hdr, hdrP);
+            --noRecurse;
+        } else
+            retval = hdrP;
     }
-    else
-	ret_hdr = the_hdr;
-
-    return ret_hdr;
+    return retval;
 }
+
+
+
diff --git a/urt/rle_open_f.c b/urt/rle_open_f.c
index ae8548b9..65362a53 100644
--- a/urt/rle_open_f.c
+++ b/urt/rle_open_f.c
@@ -1,7 +1,7 @@
-/* 
+/*
  * rle_open_f.c - Open a file with defaults.
- * 
- * Author :     Jerry Winters 
+ *
+ * Author :     Jerry Winters
  *      EECS Dept.
  *      University of Michigan
  * Date:    11/14/89
@@ -37,8 +37,8 @@
 
 
 static FILE *
-my_popen(const char * const cmd, 
-         const char * const mode, 
+my_popen(const char * const cmd,
+         const char * const mode,
          int  *       const pid) {
 
     FILE *retfile;
@@ -55,7 +55,7 @@ my_popen(const char * const cmd,
 
     if (pm_pipe(pipefd) < 0 )
         return NULL;
-    
+
     /* Flush known files. */
     fflush(stdout);
     fflush(stderr);
@@ -86,7 +86,7 @@ my_popen(const char * const cmd,
         if ( execl("/bin/sh", "sh", "-c", cmd, NULL) < 0 )
             exit(127);
         /* NOTREACHED */
-    }   
+    }
 
     /* Close file descriptors, and gen up a FILE ptr */
     if ( *mode == 'r' )
@@ -173,10 +173,10 @@ dealWithSubprocess(const char *  const file_name,
 
     /*  Real file, not stdin or stdout.  If name ends in ".Z",
      *  pipe from/to un/compress (depending on r/w mode).
-     *  
+     *
      *  If it starts with "|", popen that command.
      */
-        
+
     cp = file_name + strlen(file_name) - 2;
     /* Pipe case. */
     if (file_name[0] == '|') {
@@ -198,14 +198,14 @@ dealWithSubprocess(const char *  const file_name,
         const char * command;
 
         *noSubprocessP = FALSE;
-        
+
         if (*mode == 'w')
             pm_asprintf(&command, "compress > %s", file_name);
         else if (*mode == 'a')
             pm_asprintf(&command, "compress >> %s", file_name);
         else
             pm_asprintf(&command, "compress -d < %s", file_name);
-        
+
         *fpP = my_popen(command, mode, &thepid);
 
         if (*fpP == NULL)
@@ -227,8 +227,8 @@ dealWithSubprocess(const char *  const file_name,
 
 
 
-/* 
- *  Purpose : Open a file for input or ouput as controlled by the mode
+/*
+ *  Purpose : Open a file for input or output as controlled by the mode
  *  parameter.  If no file name is specified (ie. file_name is null) then
  *  a pointer to stdin or stdout will be returned.  The calling routine may
  *  call this routine with a file name of "-".  For this case rle_open_f
@@ -246,11 +246,11 @@ dealWithSubprocess(const char *  const file_name,
  *
  *   output:
  *     a file pointer
- * 
+ *
  */
 FILE *
-rle_open_f_noexit(const char * const prog_name, 
-                  const char * const file_name, 
+rle_open_f_noexit(const char * const prog_name,
+                  const char * const file_name,
                   const char * const mode ) {
 
     FILE * retval;
@@ -265,12 +265,12 @@ rle_open_f_noexit(const char * const prog_name,
         fp = stdout;     /* Set the default value */
     else
         fp = stdin;
-    
+
     if (file_name != NULL && !streq(file_name, "-")) {
         bool noSubprocess;
         dealWithSubprocess(file_name, mode, &catching_children, pids,
                            &fp, &noSubprocess, &err_str);
-        
+
         if (!err_str) {
             if (noSubprocess) {
                 /* Ordinary, boring file case. */
@@ -286,7 +286,7 @@ rle_open_f_noexit(const char * const prog_name,
                 mode_string[0] = mode[0];
                 mode_string[1] = 'b';
                 strcpy( mode_string + 2, mode + 1 );
-        
+
                 fp = fopen(file_name, mode_string);
                 if (fp == NULL )
                     err_str = "%s: can't open %s for %s: ";
@@ -322,28 +322,3 @@ rle_open_f(const char * prog_name, const char * file_name, const char * mode)
     return fp;
 }
 
-
-/*****************************************************************
- * TAG( rle_close_f )
- * 
- * Close a file opened by rle_open_f.  If the file is stdin or stdout,
- * it will not be closed.
- * Inputs:
- *  fd: File to close.
- * Outputs:
- *  None.
- * Assumptions:
- *  fd is open.
- * Algorithm:
- *  If fd is NULL, just return.
- *  If fd is stdin or stdout, don't close it.  Otherwise, call fclose.
- */
-void
-rle_close_f( fd )
-    FILE *fd;
-{
-    if ( fd == NULL || fd == stdin || fd == stdout )
-        return;
-    else
-        fclose( fd );
-}
diff --git a/urt/rle_put.h b/urt/rle_put.h
index 1f8cc85b..bfabd617 100644
--- a/urt/rle_put.h
+++ b/urt/rle_put.h
@@ -1,29 +1,29 @@
 /*
  * This software is copyrighted as noted below.  It may be freely copied,
- * modified, and redistributed, provided that the copyright notice is 
+ * modified, and redistributed, provided that the copyright notice is
  * preserved on all copies.
- * 
+ *
  * There is no warranty or other guarantee of fitness for this software,
  * it is provided solely "as is".  Bug reports or fixes may be sent
  * to the author, who may or may not act on them as he desires.
  *
  * You may not include this software in a program or other software product
- * without supplying the source, or without informing the end-user that the 
+ * without supplying the source, or without informing the end-user that the
  * source is available for no extra charge.
  *
  * If you modify this software, you should include a notice giving the
  * name of the person performing the modification, the date of modification,
  * and the reason for such modification.
  */
-/* 
+/*
  * rle_put.h - Definitions and a few global variables for rle_putrow/putraw.
- * 
- * Author:	Spencer W. Thomas
- * 		Computer Science Dept.
- * 		University of Utah
- * Date:	Mon Aug  9 1982
+ *
+ * Author:      Spencer W. Thomas
+ *              Computer Science Dept.
+ *              University of Utah
+ * Date:        Mon Aug  9 1982
  * Copyright (c) 1982 Spencer W. Thomas
- * 
+ *
  * $Id: rle_put.h,v 3.0.1.2 1992/02/27 21:14:35 spencer Exp $
  */
 
@@ -35,7 +35,7 @@
  */
 #ifdef __cplusplus        /* Cfront 2.0  or g++ */
 #ifndef c_plusplus
-#define c_plusplus        
+#define c_plusplus
 #endif
 extern "C" {
 #endif
@@ -67,38 +67,38 @@ struct rle_dispatch_tab {
 
 extern struct rle_dispatch_tab rle_DTable[];
 
-/* 
+/*
  * These definitions presume the existence of a variable called
  * "fileptr", declared "long * fileptr".  *fileptr should be
  * initialized to 0 before calling Setup().
  * A pointer "the_hdr" declared "rle_hdr * the_hdr" is also
  * presumed to exist.
  */
-#define	    rle_magic		(rle_DTable[(int)the_hdr->dispatch].magic)
-#define	    Setup()		(*rle_DTable[(int)the_hdr->dispatch].setup)(the_hdr)
-#define	    SkipBlankLines(n)	(*rle_DTable[(int)the_hdr->dispatch].skipBlankLines)(n, the_hdr)
-#define	    SetColor(c)		(*rle_DTable[(int)the_hdr->dispatch].setColor)(c, the_hdr)
-#define	    SkipPixels(n, l, r)	(*rle_DTable[(int)the_hdr->dispatch].skipPixels)(n,l,r, the_hdr)
-#define	    NewScanLine(flag)	(*rle_DTable[(int)the_hdr->dispatch].newScanLine)(flag, the_hdr)
-#define	    putdata(buf, len)	(*rle_DTable[(int)the_hdr->dispatch].putdat)(buf, len, the_hdr)
-#define	    putrun(val, len, f)	(*rle_DTable[(int)the_hdr->dispatch].putrn)(val,len,f, the_hdr)
-#define	    BlockHook()		(*rle_DTable[(int)the_hdr->dispatch].blockHook)(the_hdr)
-#define	    PutEof()		(*rle_DTable[(int)the_hdr->dispatch].putEof)(the_hdr)
+#define     rle_magic           (rle_DTable[(int)the_hdr->dispatch].magic)
+#define     Setup()             (*rle_DTable[(int)the_hdr->dispatch].setup)(the_hdr)
+#define     SkipBlankLines(n)   (*rle_DTable[(int)the_hdr->dispatch].skipBlankLines)(n, the_hdr)
+#define     SetColor(c)         (*rle_DTable[(int)the_hdr->dispatch].setColor)(c, the_hdr)
+#define     SkipPixels(n, l, r) (*rle_DTable[(int)the_hdr->dispatch].skipPixels)(n,l,r, the_hdr)
+#define     NewScanLine(flag)   (*rle_DTable[(int)the_hdr->dispatch].newScanLine)(flag, the_hdr)
+#define     putdata(buf, len)   (*rle_DTable[(int)the_hdr->dispatch].putdat)(buf, len, the_hdr)
+#define     putrun(val, len, f) (*rle_DTable[(int)the_hdr->dispatch].putrn)(val,len,f, the_hdr)
+#define     BlockHook()         (*rle_DTable[(int)the_hdr->dispatch].blockHook)(the_hdr)
+#define     PutEof()            (*rle_DTable[(int)the_hdr->dispatch].putEof)(the_hdr)
 
 void
 DefaultBlockHook(rle_hdr * the_hdr);
-/* 
+/*
  * States for run detection
  */
-#define	DATA	0
-#define	RUN1	1
-#define RUN2	2
-#define	RUN3	3
-#define RUN4	4
-#define RUN5	5
-#define RUN6	6
-#define RUN7	7
-#define	INRUN	-1
+#define DATA    0
+#define RUN1    1
+#define RUN2    2
+#define RUN3    3
+#define RUN4    4
+#define RUN5    5
+#define RUN6    6
+#define RUN7    7
+#define INRUN  -1
 
 #ifdef __cplusplus
 }
diff --git a/urt/rle_putcom.c b/urt/rle_putcom.c
index ab2eb208..0bebd8d7 100644
--- a/urt/rle_putcom.c
+++ b/urt/rle_putcom.c
@@ -1,23 +1,23 @@
 /*
  * This software is copyrighted as noted below.  It may be freely copied,
- * modified, and redistributed, provided that the copyright notice is 
+ * modified, and redistributed, provided that the copyright notice is
  * preserved on all copies.
- * 
+ *
  * There is no warranty or other guarantee of fitness for this software,
  * it is provided solely "as is".  Bug reports or fixes may be sent
  * to the author, who may or may not act on them as he desires.
  *
  * You may not include this software in a program or other software product
- * without supplying the source, or without informing the end-user that the 
+ * without supplying the source, or without informing the end-user that the
  * source is available for no extra charge.
  *
  * If you modify this software, you should include a notice giving the
  * name of the person performing the modification, the date of modification,
  * and the reason for such modification.
  */
-/* 
+/*
  * rle_putcom.c - Add a picture comment to the header struct.
- * 
+ *
  * Author:  Spencer W. Thomas
  *      Computer Science Dept.
  *      University of Utah
@@ -33,7 +33,7 @@
 
 /*****************************************************************
  * TAG( match )
- * 
+ *
  * Match a name against a test string for "name=value" or "name".
  * If it matches name=value, return pointer to value part, if just
  * name, return pointer to NUL at end of string.  If no match, return NULL.
@@ -72,7 +72,7 @@ match(const char * const nArg,
 
 /*****************************************************************
  * TAG( rle_putcom )
- * 
+ *
  * Put a comment into the header struct.
  * Inputs:
  *  value:      Value to add to comments.
@@ -124,46 +124,3 @@ rle_putcom(const char * const value,
 
     return NULL;
 }
-
-
-
-/*****************************************************************
- * TAG( rle_delcom )
- * 
- * Delete a comment from header struct.
- * Inputs:
- *  name:       Name of comment to delete.
- *  the_hdr:    Header to delete comment from.
- * Outputs:
- *  the_hdr:    Modified header struct.
- *  Returns original comment value.
- * Assumptions:
- *  [None]
- * Algorithm:
- *  [None]
- */
-const char *
-rle_delcom(const char * const name,
-           rle_hdr *    const the_hdr) {
-
-    const char * v = NULL;
-
-    if (the_hdr->comments == NULL)
-        v = NULL;
-    else {
-        const char ** cp;
-
-        for (cp = the_hdr->comments; *cp != NULL; ++cp)
-            if (match(name, *cp) != NULL) {
-                v = *cp;
-                for ( ; *cp != NULL; ++cp)
-                    *cp = cp[1];
-                break;
-            }
-        /* Not found */
-        if (*the_hdr->comments == NULL)
-            the_hdr->comments = NULL;
-    }
-
-    return v;
-}
diff --git a/urt/rle_putrow.c b/urt/rle_putrow.c
index 399633e4..5f808c92 100644
--- a/urt/rle_putrow.c
+++ b/urt/rle_putrow.c
@@ -1,14 +1,14 @@
 /*
  * This software is copyrighted as noted below.  It may be freely copied,
- * modified, and redistributed, provided that the copyright notice is 
+ * modified, and redistributed, provided that the copyright notice is
  * preserved on all copies.
- * 
+ *
  * There is no warranty or other guarantee of fitness for this software,
  * it is provided solely "as is".  Bug reports or fixes may be sent
  * to the author, who may or may not act on them as he desires.
  *
  * You may not include this software in a program or other software product
- * without supplying the source, or without informing the end-user that the 
+ * without supplying the source, or without informing the end-user that the
  * source is available for no extra charge.
  *
  * If you modify this software, you should include a notice giving the
@@ -18,60 +18,57 @@
  *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
  *  to have all "void" functions so declared.
  */
-/* 
+/*
  * rle_putrow.c - Save a row of the fb to a file.
- * 
- * Author:	Spencer W. Thomas
- * 		Computer Science Dept.
- * 		University of Utah
- * Date:	1 April 1981
+ *
+ * Author:      Spencer W. Thomas
+ *              Computer Science Dept.
+ *              University of Utah
+ * Date:        1 April 1981
  * Copyright (c) 1981,1986 Spencer W. Thomas
  *
  * $Id: rle_putrow.c,v 3.0.1.2 1992/01/28 18:29:22 spencer Exp $
  */
- 
+
 #include <stdio.h>
 
 #include "rle_put.h"
 #include "rle.h"
 
 
-#define FASTRUNS		/* Faster run finding */
-#ifdef vax
-#define LOCC			/* Use vax instructions for more speed */
-#endif
+#define FASTRUNS                /* Faster run finding */
 
-#define	FALSE	0
-#define	TRUE	1
+#define FALSE   0
+#define TRUE    1
 
 /* Save some typing. */
 #define PBRUN the_hdr->priv.put.brun
 
 /*****************************************************************
  * TAG( findruns )
- * 
+ *
  * Find runs not a given color in the row.
  * Inputs:
- * 	row:		Row of pixel values
- *	rowlen:		Number of pixels in the row.
- *	color:		Color to compare against.
- *	nrun:		Number of runs already found (in different colors).
- *	brun:		Runs found in other color channels already.
+ *      row:            Row of pixel values
+ *      rowlen:         Number of pixels in the row.
+ *      color:          Color to compare against.
+ *      nrun:           Number of runs already found (in different colors).
+ *      brun:           Runs found in other color channels already.
  * Outputs:
- * 	brun:		Modified to reflect merging of runs in this color.
- *	Returns number of runs in brun.
+ *      brun:           Modified to reflect merging of runs in this color.
+ *      Returns number of runs in brun.
  * Assumptions:
  *
  * Algorithm:
- * 	Search for occurrences of pixels not of the given color outside
- *	the runs already found.  When some are found, add a new run or
- *	extend an existing one.  Adjacent runs with fewer than two
- *	pixels intervening are merged.
+ *      Search for occurrences of pixels not of the given color outside
+ *      the runs already found.  When some are found, add a new run or
+ *      extend an existing one.  Adjacent runs with fewer than two
+ *      pixels intervening are merged.
  */
 static int
-findruns(rle_pixel * const row, 
-         int         const rowlen, 
-         int         const color, 
+findruns(rle_pixel * const row,
+         int         const rowlen,
+         int         const color,
          int         const nrunAlready,
          short    (* const brun)[2]) {
 
@@ -99,9 +96,9 @@ findruns(rle_pixel * const row,
         /* Assert: 0 <= i <= rowlen
          * brun[i] is the run following the "blank" space being
          * searched.  If i == rowlen, search after brun[i-1].
-	 */
+         */
 
-	/* get lower and upper bounds of search */
+        /* get lower and upper bounds of search */
 
         if ( i == 0 )
             lower = 0;
@@ -118,15 +115,13 @@ findruns(rle_pixel * const row,
                  i, lower, upper );
 #endif
         /* Search for beginning of run != color */
-#if  defined(LOCC)&defined(vax)
-        s = upper - skpc( (char *)row + lower, upper - lower + 1, color ) + 1;
-#else
+
         for ( s = lower; s <= upper; s++ )
             if ( row[s] != color )
                 break;
-#endif
 
-        if ( s <= upper )	/* found a new run? */
+
+        if ( s <= upper )       /* found a new run? */
         {
             if ( s > lower + 1 || i == 0 ) /* disjoint from preceding run? */
             {
@@ -144,19 +139,16 @@ findruns(rle_pixel * const row,
             }
             else
             {
-                i--;		/* just add to preceding run */
+                i--;            /* just add to preceding run */
 #ifdef DEBUG
                 fprintf( stderr, "Adding to previous run\n" );
 #endif
             }
 
-#if defined(LOCC)&defined(vax)
-            s = upper - locc( (char *)row + s, upper - s + 1, color ) + 1;
-#else
             for ( ; s <= upper; s++ )
                 if ( row[s] == color )
                     break;
-#endif
+
             brun[i][1] = s - 1;
 
 #ifdef DEBUG
@@ -180,7 +172,7 @@ findruns(rle_pixel * const row,
             putc( '\n', stderr );
 #endif
         }
-	
+
         /* Search in next space */
         i++;
     }
@@ -193,319 +185,313 @@ findruns(rle_pixel * const row,
 /*****************************************************************
  * TAG( rle_putrow )
  * Write a scanline to the output file.
- * 
+ *
  * Inputs:
- *	rows:		Pointer to vector of pointers to
- *			rle_pixel arrays containing the pixel information.
- *			If NULL, rowlen scanlines are skipped.
- *	rowlen:		The number of pixels in the scanline, or the
- *			number of scanlines to skip (see above).
+ *      rows:           Pointer to vector of pointers to
+ *                      rle_pixel arrays containing the pixel information.
+ *                      If NULL, rowlen scanlines are skipped.
+ *      rowlen:         The number of pixels in the scanline, or the
+ *                      number of scanlines to skip (see above).
  * Outputs:
- * 	Run length encoded information is written to the_hdr.rle_file.
+ *      Run length encoded information is written to the_hdr.rle_file.
  * Assumptions:
- * 	I'm sure there are lots of assumptions in here.
+ *      I'm sure there are lots of assumptions in here.
  * Algorithm:
- * 	There are two parts:
- * 		1. Find all "sufficiently long" runs of background
- * 		   color.  These will not be saved at all.
- * 		2. For each run of non-background, for each color
- * 		   channel, find runs of identical pixel values
- * 		   between "data" segments (of differing pixel
- * 		   values).
- * 	For part 1, "sufficiently long" is 2 pixels, if the following
- * 	data is less than 256 pixels long, otherwise it is 4 pixels.
- * 	This is enforced by a post-process merge.
+ *      There are two parts:
+ *              1. Find all "sufficiently long" runs of background
+ *                 color.  These will not be saved at all.
+ *              2. For each run of non-background, for each color
+ *                 channel, find runs of identical pixel values
+ *                 between "data" segments (of differing pixel
+ *                 values).
+ *      For part 1, "sufficiently long" is 2 pixels, if the following
+ *      data is less than 256 pixels long, otherwise it is 4 pixels.
+ *      This is enforced by a post-process merge.
  *
- * 	Part 1 can be done in two different ways, depending on whether
- * 	FASTRUNS is defined or not.  With FASTRUNS defined, it finds
- * 	runs of the background pixel value in each channel
- * 	independently, and then merges the results.  With FASTRUNS not
- * 	defined, it scans all channels in parallel.
+ *      Part 1 can be done in two different ways, depending on whether
+ *      FASTRUNS is defined or not.  With FASTRUNS defined, it finds
+ *      runs of the background pixel value in each channel
+ *      independently, and then merges the results.  With FASTRUNS not
+ *      defined, it scans all channels in parallel.
  *
- * 	Part 2 uses a state machine.  For each run of non-background
- * 	data, it searches for sufficiently long sequences of a single
- * 	value (in each channel independently).  Sufficiently long is 4
- * 	pixels if the following data is < 256 pixels, 6 pixels
- * 	otherwise.  This is because the startup cost for the run is 2
- * 	bytes, and the startup cost for a data segment is 2 bytes if
- * 	it is < 256 pixels long, 4 bytes otherwise.  Thus a run
- * 	shorter than 4 or 6 pixels (respectively) would actually make
- * 	the output longer.  An additional pixel is required if the
- * 	preceding data is an odd number of pixels long (because a
- * 	filler byte will be output at the end of it.)
+ *      Part 2 uses a state machine.  For each run of non-background
+ *      data, it searches for sufficiently long sequences of a single
+ *      value (in each channel independently).  Sufficiently long is 4
+ *      pixels if the following data is < 256 pixels, 6 pixels
+ *      otherwise.  This is because the startup cost for the run is 2
+ *      bytes, and the startup cost for a data segment is 2 bytes if
+ *      it is < 256 pixels long, 4 bytes otherwise.  Thus a run
+ *      shorter than 4 or 6 pixels (respectively) would actually make
+ *      the output longer.  An additional pixel is required if the
+ *      preceding data is an odd number of pixels long (because a
+ *      filler byte will be output at the end of it.)
  */
 
 void
 rle_putrow(rows, rowlen, the_hdr)
-register rle_pixel *rows[];
+rle_pixel *rows[];
 int rowlen;
-register rle_hdr * the_hdr;
+rle_hdr * the_hdr;
 {
-    register int i, j;
+    int i, j;
     int nrun;
-    register rle_pixel *row;
+    rle_pixel *row;
     int mask;
     char bits[256];
-    short   state,		/* State of run-finding state machine. */
-	    dstart,		/* Starting point for current data segment. */
-    	    dend,		/* Ending point of current data segment. */
-	    rstart = 0,		/* Starting point of current run. */
-	    runval = 0;		/* Data value for current run. */
+    short   state,              /* State of run-finding state machine. */
+            dstart,             /* Starting point for current data segment. */
+            dend,               /* Ending point of current data segment. */
+            rstart = 0,         /* Starting point of current run. */
+            runval = 0;         /* Data value for current run. */
 
     if (rows == NULL)
     {
-	the_hdr->priv.put.nblank += rowlen;
-	return;
+        the_hdr->priv.put.nblank += rowlen;
+        return;
     }
-    /* 
+    /*
      * If not done already, allocate space to remember runs of
      * non-background color.  A run of bg color must be at least 2
      * bytes long to count, so there can be at most rowlen/3 of them.
      */
     if ( PBRUN == NULL )
     {
-	PBRUN = (short (*)[2])malloc(
-	    (unsigned)((rowlen/3 + 1) * 2 * sizeof(short)) );
-	if ( PBRUN == NULL )
-	{
-	    fprintf( stderr, "%s: Malloc failed in rle_putrow, writing %s\n",
-		     the_hdr->cmd, the_hdr->file_name );
-	    exit(1);
-	}
+        PBRUN = (short (*)[2])malloc(
+            (unsigned)((rowlen/3 + 1) * 2 * sizeof(short)) );
+        if ( PBRUN == NULL )
+        {
+            fprintf( stderr, "%s: Malloc failed in rle_putrow, writing %s\n",
+                     the_hdr->cmd, the_hdr->file_name );
+            exit(1);
+        }
     }
     /* Unpack bitmask in the_hdr struct */
     for ( i=0; i < the_hdr->ncolors; i++ )
-	bits[i] = RLE_BIT( *the_hdr, i );
+        bits[i] = RLE_BIT( *the_hdr, i );
     bits[255] = RLE_BIT( *the_hdr, -1 );
 
-    /* 
+    /*
      * If saving only non-background pixels, find runs of them.  Note
      * that the alpha channel is considered to be background iff it is
      * zero.
      */
-#ifdef	FASTRUNS
+#ifdef  FASTRUNS
     if ( the_hdr->background )
     {
-	/* 
-	 * Find runs in each color individually, merging them as we go.
-	 */
-	nrun = 0;		/* start out with no runs */
-	/* Alpha channel first */
-	if ( the_hdr->alpha )
-	    nrun = findruns( rows[-1], rowlen, 0, nrun, PBRUN );
-	/* Now the color channels */
-	for ( i = 0; i < the_hdr->ncolors; i++ )
-	    if ( bits[i] )
-		nrun = findruns( rows[i], rowlen, the_hdr->bg_color[i],
-				 nrun, PBRUN );
+        /*
+         * Find runs in each color individually, merging them as we go.
+         */
+        nrun = 0;               /* start out with no runs */
+        /* Alpha channel first */
+        if ( the_hdr->alpha )
+            nrun = findruns( rows[-1], rowlen, 0, nrun, PBRUN );
+        /* Now the color channels */
+        for ( i = 0; i < the_hdr->ncolors; i++ )
+            if ( bits[i] )
+                nrun = findruns( rows[i], rowlen, the_hdr->bg_color[i],
+                                 nrun, PBRUN );
     }
     else
     {
-	PBRUN[0][0] = 0;
-	PBRUN[0][1] = rowlen-1;
-	nrun = 1;
+        PBRUN[0][0] = 0;
+        PBRUN[0][1] = rowlen-1;
+        nrun = 1;
     }
-#else				/* FASTRUNS */
-    if (the_hdr->background)	/* find non-background runs */
+#else                           /* FASTRUNS */
+    if (the_hdr->background)    /* find non-background runs */
     {
-	j = 0;
-	for (i=0; i<rowlen; i++)
-	    if (!same_color( i, rows, the_hdr->bg_color,
-			     the_hdr->ncolors, bits ) ||
-		(the_hdr->alpha && rows[-1][i] != 0))
-	    {
-		if (j > 0 && i - PBRUN[j-1][1] <= 2)
-		    j--;
-		else
-		    PBRUN[j][0] = i; /* start of run */
-		for ( i++;
-		      i < rowlen && 
-			( !same_color( i, rows, the_hdr->bg_color,
-					 the_hdr->ncolors, bits ) ||
-			  (the_hdr->alpha && rows[-1][i] != 0) );
-		      i++)
-		    ;			/* find the end of this run */
-		PBRUN[j][1] = i-1;    /* last in run */
-		j++;
-	    }
-	nrun = j;
+        j = 0;
+        for (i=0; i<rowlen; i++)
+            if (!same_color( i, rows, the_hdr->bg_color,
+                             the_hdr->ncolors, bits ) ||
+                (the_hdr->alpha && rows[-1][i] != 0))
+            {
+                if (j > 0 && i - PBRUN[j-1][1] <= 2)
+                    j--;
+                else
+                    PBRUN[j][0] = i; /* start of run */
+                for ( i++;
+                      i < rowlen &&
+                        ( !same_color( i, rows, the_hdr->bg_color,
+                                         the_hdr->ncolors, bits ) ||
+                          (the_hdr->alpha && rows[-1][i] != 0) );
+                      i++)
+                    ;                   /* find the end of this run */
+                PBRUN[j][1] = i-1;    /* last in run */
+                j++;
+            }
+        nrun = j;
     }
     else
     {
-	PBRUN[0][0] = 0;
-	PBRUN[0][1] = rowlen-1;
-	nrun = 1;
+        PBRUN[0][0] = 0;
+        PBRUN[0][1] = rowlen-1;
+        nrun = 1;
     }
-#endif				/* FASTRUNS */
+#endif                          /* FASTRUNS */
     /* One final pass merges runs with fewer than 4 intervening pixels
      * if the second run is longer than 255 pixels.  This is because
      * the startup cost for such a run is 4 bytes.
      */
     if ( nrun > 1 )
     {
-	for ( i = nrun - 1; i > 0; i-- )
-	{
-	    if ( PBRUN[i][1] - PBRUN[i][0] > 255 &&
-		 PBRUN[i-1][1] + 4 > PBRUN[i][0] )
-	    {
-		PBRUN[i-1][1] = PBRUN[i][1];
-		for ( j = i; j < nrun - 1; j++ )
-		{
-		    PBRUN[j][0] = PBRUN[j+1][0];
-		    PBRUN[j][1] = PBRUN[j+1][1];
-		}
-		nrun--;
-	    }
-	}
+        for ( i = nrun - 1; i > 0; i-- )
+        {
+            if ( PBRUN[i][1] - PBRUN[i][0] > 255 &&
+                 PBRUN[i-1][1] + 4 > PBRUN[i][0] )
+            {
+                PBRUN[i-1][1] = PBRUN[i][1];
+                for ( j = i; j < nrun - 1; j++ )
+                {
+                    PBRUN[j][0] = PBRUN[j+1][0];
+                    PBRUN[j][1] = PBRUN[j+1][1];
+                }
+                nrun--;
+            }
+        }
     }
 
     if (nrun > 0)
     {
-	if (the_hdr->priv.put.nblank > 0)
-	{
-	    SkipBlankLines(the_hdr->priv.put.nblank);
-	    the_hdr->priv.put.nblank = 0;
-	}
-	for ( mask = (the_hdr->alpha ? -1 : 0);
-	      mask < the_hdr->ncolors;
-	      mask++)			/* do all colors */
-	{
-	    if ( ! bits[mask & 0xff] )
-	    {
-		continue;
-	    }
-	    row = rows[mask];
-	    SetColor(mask);
-	    if (PBRUN[0][0] > 0)
-	    {
-		SkipPixels(PBRUN[0][0], FALSE, FALSE);
-	    }
-	    for (j=0; j<nrun; j++)
-	    {
-		state = DATA;
-		dstart = PBRUN[j][0];
-		dend = PBRUN[j][1];
-		for (i=dstart; i<=dend; i++)
-		{
-		    switch(state)
-		    {
-		    case DATA:
-			if (i > dstart && runval == row[i])
-			{
-			    /* 2 in a row may be a run. */
-			    /* If odd data length, start with RUN1 */
-			    if ( ((i - dstart) % 2) == 0)
-				state = RUN1;
-			    else
-				state = RUN2;
-			}
-			else
-			{
-			    runval = row[i];	/* maybe a run starts here? */
-			    rstart = i;
-			}
-			break;
-	    
-		    case RUN4:
-			if (runval == row[i])
-			{
-			    /* If the following data might be longer
-			     * than 255 pixels then look for 8 in a
-			     * row, otherwise, 6 in a row is
-			     * sufficient.  Fake this by skipping to
-			     * state RUN5.
-			     */
-			    if ( dend - i > 255 )
-				state  = RUN5;	/* Need some more. */
-			    else
-				state = RUN7;	/* Next one makes a run. */
-			    
-			}
-			else
-			{
-			    state = DATA;	/* Nope, back to data */
-			    runval = row[i];	/* but maybe a new run here? */
-			    rstart = i;
-			}
-			break;
-
-		    case RUN1:
-		    case RUN2:
-		    case RUN3:
-		    case RUN5:
-		    case RUN6:
-			if (runval == row[i])
-			{
-			    /* Move to the next state. */
-			    state++;
-			}
-			else
-			{
-			    state = DATA;	/* Nope, back to data */
-			    runval = row[i];	/* but maybe a new run here? */
-			    rstart = i;
-			}
-			break;
-
-
-		    case RUN7:
-			if (runval == row[i])	/* enough in a row for a run */
-			{
-			    state = INRUN;
-			    putdata(row + dstart, rstart - dstart);
+        if (the_hdr->priv.put.nblank > 0)
+        {
+            SkipBlankLines(the_hdr->priv.put.nblank);
+            the_hdr->priv.put.nblank = 0;
+        }
+        for ( mask = (the_hdr->alpha ? -1 : 0);
+              mask < the_hdr->ncolors;
+              mask++)                   /* do all colors */
+        {
+            if ( ! bits[mask & 0xff] )
+            {
+                continue;
+            }
+            row = rows[mask];
+            SetColor(mask);
+            if (PBRUN[0][0] > 0)
+            {
+                SkipPixels(PBRUN[0][0], FALSE, FALSE);
+            }
+            for (j=0; j<nrun; j++)
+            {
+                state = DATA;
+                dstart = PBRUN[j][0];
+                dend = PBRUN[j][1];
+                for (i=dstart; i<=dend; i++)
+                {
+                    switch(state)
+                    {
+                    case DATA:
+                        if (i > dstart && runval == row[i])
+                        {
+                            /* 2 in a row may be a run. */
+                            /* If odd data length, start with RUN1 */
+                            if ( ((i - dstart) % 2) == 0)
+                                state = RUN1;
+                            else
+                                state = RUN2;
+                        }
+                        else
+                        {
+                            runval = row[i];    /* maybe a run starts here? */
+                            rstart = i;
+                        }
+                        break;
+
+                    case RUN4:
+                        if (runval == row[i])
+                        {
+                            /* If the following data might be longer
+                             * than 255 pixels then look for 8 in a
+                             * row, otherwise, 6 in a row is
+                             * sufficient.  Fake this by skipping to
+                             * state RUN5.
+                             */
+                            if ( dend - i > 255 )
+                                state  = RUN5;  /* Need some more. */
+                            else
+                                state = RUN7;   /* Next one makes a run. */
+
+                        }
+                        else
+                        {
+                            state = DATA;       /* Nope, back to data */
+                            runval = row[i];    /* but maybe a new run here? */
+                            rstart = i;
+                        }
+                        break;
+
+                    case RUN1:
+                    case RUN2:
+                    case RUN3:
+                    case RUN5:
+                    case RUN6:
+                        if (runval == row[i])
+                        {
+                            /* Move to the next state. */
+                            state++;
+                        }
+                        else
+                        {
+                            state = DATA;       /* Nope, back to data */
+                            runval = row[i];    /* but maybe a new run here? */
+                            rstart = i;
+                        }
+                        break;
+
+
+                    case RUN7:
+                        if (runval == row[i])   /* enough in a row for a run */
+                        {
+                            state = INRUN;
+                            putdata(row + dstart, rstart - dstart);
 #ifdef FASTRUNS
-#ifdef LOCC
-			    /* Shortcut to find end of run! */
-			    i = dend - skpc( (char *)row + i, dend + 1 - i,
-					     runval );
-#else
-			    while ( row[++i] == runval && i <= dend)
-				; /* not quite so good, but not bad */
-			    i--;
-#endif /* LOCC */
+                            while ( row[++i] == runval && i <= dend)
+                                ; /* not quite so good, but not bad */
+                            i--;
 #endif /* FASTRUNS */
-			}
-			else
-			{
-			    state = DATA;		/* not a run, */
-			    runval = row[i];	/* but may this starts one */
-			    rstart = i;
-			}
-			break;
-	    
-		    case INRUN:
-			if (runval != row[i])	/* if run out */
-			{
-			    state = DATA;
-			    putrun(runval, i - rstart, FALSE);
-			    runval = row[i];	/* who knows, might be more */
-			    rstart = i;
-			    dstart = i;	/* starting a new 'data' run */
-			}
-			break;
-		    }
-		}
-		if (state == INRUN)
-		    putrun(runval, i - rstart, TRUE);	/* last bit */
-		else
-		    putdata(row + dstart, i - dstart);
-
-		if (j < nrun-1)
-		    SkipPixels(
-			    PBRUN[j+1][0] - dend - 1,
-			    FALSE, state == INRUN);
-		else
-		{
-		    if (rowlen - dend > 0)
-			SkipPixels(
-			    rowlen - dend - 1,
-			    TRUE, state == INRUN);
-		}
-	    }
-
-	    if ( mask != the_hdr->ncolors - 1 )
-		NewScanLine(FALSE);
-	}
+                        }
+                        else
+                        {
+                            state = DATA;               /* not a run, */
+                            runval = row[i];    /* but may this starts one */
+                            rstart = i;
+                        }
+                        break;
+
+                    case INRUN:
+                        if (runval != row[i])   /* if run out */
+                        {
+                            state = DATA;
+                            putrun(runval, i - rstart, FALSE);
+                            runval = row[i];    /* who knows, might be more */
+                            rstart = i;
+                            dstart = i; /* starting a new 'data' run */
+                        }
+                        break;
+                    }
+                }
+                if (state == INRUN)
+                    putrun(runval, i - rstart, TRUE);   /* last bit */
+                else
+                    putdata(row + dstart, i - dstart);
+
+                if (j < nrun-1)
+                    SkipPixels(
+                            PBRUN[j+1][0] - dend - 1,
+                            FALSE, state == INRUN);
+                else
+                {
+                    if (rowlen - dend > 0)
+                        SkipPixels(
+                            rowlen - dend - 1,
+                            TRUE, state == INRUN);
+                }
+            }
+
+            if ( mask != the_hdr->ncolors - 1 )
+                NewScanLine(FALSE);
+        }
     }
 
     /* Increment to next scanline */
@@ -517,55 +503,30 @@ register rle_hdr * the_hdr;
 
 
 /*****************************************************************
- * TAG( rle_skiprow )
- * 
- * Skip rows in RLE file.
- * Inputs:
- * 	the_hdr:    	Header struct for RLE output file.
- *  	nrow:	    	Number of rows to skip.
- * Outputs:
- * 	Increments the nblank field in the the_hdr struct, so that a Skiplines
- *  	code will be output the next time rle_putrow or rle_putraw is called.
- * Assumptions:
- * 	Only effective when called between rle_putrow or rle_putraw calls (or
- *  	some other routine that follows the same conventions.
- * Algorithm:
- *	[None]
- */
-void
-rle_skiprow( the_hdr, nrow )
-rle_hdr *the_hdr;
-int nrow;
-{
-    the_hdr->priv.put.nblank += nrow;
-}
-
-
-/*****************************************************************
  * TAG( rle_put_init )
- * 
- * Initialize the header structure for writing scanlines. 
+ *
+ * Initialize the header structure for writing scanlines.
  * Inputs:
- *	[None]
+ *      [None]
  * Outputs:
- * 	the_hdr:	Private portions initialized for output.
+ *      the_hdr:        Private portions initialized for output.
  * Assumptions:
- *	[None]
+ *      [None]
  * Algorithm:
- *	[None]
+ *      [None]
  */
 void
 rle_put_init( the_hdr )
-register rle_hdr *the_hdr;
+rle_hdr *the_hdr;
 {
     the_hdr->dispatch = RUN_DISPATCH;
 
     if ( the_hdr->is_init != RLE_INIT_MAGIC )
     {
-	the_hdr->cmd = "Urt";
-	the_hdr->file_name = "some file";
+        the_hdr->cmd = "Urt";
+        the_hdr->file_name = "some file";
     }
-    the_hdr->priv.put.nblank = 0;	/* Reinit static vars */
+    the_hdr->priv.put.nblank = 0;       /* Reinit static vars */
     /* Would like to be able to free previously allocated storage,
      * but can't count on a non-NULL value being a valid pointer.
      */
@@ -574,37 +535,37 @@ register rle_hdr *the_hdr;
 
     /* Only save alpha if alpha AND alpha channel bit are set. */
     if ( the_hdr->alpha )
-	the_hdr->alpha = (RLE_BIT( *the_hdr, -1 ) != 0);
+        the_hdr->alpha = (RLE_BIT( *the_hdr, -1 ) != 0);
     else
-	RLE_CLR_BIT( *the_hdr, -1 );
+        RLE_CLR_BIT( *the_hdr, -1 );
 }
 
 /*****************************************************************
  * TAG( rle_put_setup )
- * 
+ *
  * Initialize for writing RLE, and write header to output file.
  * Inputs:
- * 	the_hdr:	Describes output image.
+ *      the_hdr:        Describes output image.
  * Outputs:
- * 	the_hdr:	Initialized.
+ *      the_hdr:        Initialized.
  * Assumptions:
- *	Lots of them.
+ *      Lots of them.
  * Algorithm:
- *	[None]
+ *      [None]
  */
 void
 rle_put_setup( the_hdr )
-register rle_hdr * the_hdr;
+rle_hdr * the_hdr;
 {
     rle_put_init( the_hdr );
-    the_hdr->img_num++;		/* Count output images. */
+    the_hdr->img_num++;         /* Count output images. */
     Setup();
 }
 
 void
 DefaultBlockHook(rle_hdr * the_hdr)
 {
-    					/* Do nothing */
+                                        /* Do nothing */
 }
 
 /*****************************************************************
@@ -613,18 +574,18 @@ DefaultBlockHook(rle_hdr * the_hdr)
  */
 void
 rle_puteof( the_hdr )
-register rle_hdr * the_hdr;
+rle_hdr * the_hdr;
 {
     /* Don't puteof twice. */
     if ( the_hdr->dispatch == NO_DISPATCH )
-	return;
+        return;
     PutEof();
     fflush( the_hdr->rle_file );
     /* Free storage allocated by rle_put_init. */
     if ( PBRUN != NULL )
     {
-	free( PBRUN );
-	PBRUN = NULL;
+        free( PBRUN );
+        PBRUN = NULL;
     }
     /* Signal that puteof has been called. */
     the_hdr->dispatch = NO_DISPATCH;
@@ -633,97 +594,33 @@ register rle_hdr * the_hdr;
 #ifndef FASTRUNS
 /*****************************************************************
  * TAG( same_color )
- * 
+ *
  * Determine if the color at the given index position in the scan rows
  * is the same as the background color.
  * Inputs:
- * 	index:	    Index to the pixel position in each row.
- *	rows:	    array of pointers to the scanlines
- *	bg_color:   the background color
- *	ncolors:    number of color elements/pixel
+ *      index:      Index to the pixel position in each row.
+ *      rows:       array of pointers to the scanlines
+ *      bg_color:   the background color
+ *      ncolors:    number of color elements/pixel
  * Outputs:
- * 	TRUE if the color at row[*][i] is the same as bg_color[*].
+ *      TRUE if the color at row[*][i] is the same as bg_color[*].
  * Assumptions:
- *	[None]
+ *      [None]
  * Algorithm:
- *	[None]
+ *      [None]
  */
 static int
 same_color( index, rows, bg_color, ncolors, bits )
-register rle_pixel *rows[];
-register int bg_color[];
+rle_pixel *rows[];
+int bg_color[];
 char *bits;
 {
-    register int i;
+    int i;
 
     for ( i = 0; i < ncolors; i++, bits++ )
-	if ( *bits &&
-	     rows[i][index] != bg_color[i] )
-	    return 0;
-    return 1;				/* all the same */
+        if ( *bits &&
+             rows[i][index] != bg_color[i] )
+            return 0;
+    return 1;                           /* all the same */
 }
 #endif /* !FASTRUNS */
-
-/*****************************************************************
- * TAG( rgb_to_bw )
- * 
- * Perform the NTSC Y transform on RGB data to get B&W data.
- * Inputs:
- * 	red_row, green_row, blue_row:	Given RGB pixel data.
- *	rowlen:	    Number of pixels in the rows.
- * Outputs:
- * 	bw_row:	    Output B&W data.  May coincide with one of the
- *		    inputs.
- * Assumptions:
- *	[None]
- * Algorithm:
- * 	BW = .30*R + .59*G + .11*B
- */
-void
-rgb_to_bw( red_row, green_row, blue_row, bw_row, rowlen )
-rle_pixel *red_row;
-rle_pixel *green_row;
-rle_pixel *blue_row;
-rle_pixel *bw_row;
-int rowlen;
-{
-    register int x, bw;
-
-    for (x=0; x<rowlen; x++)
-    {
-	/* 68000 won't store float > 127 into byte? */
-	/* HP compiler blows it */
-	bw = 0.5 + .30*red_row[x] + .59*green_row[x] + .11*blue_row[x];
-	bw_row[x] = bw;
-    }
-}
-
-#ifdef LOCC
-/*ARGSUSED*/
-locc( p, l, c )
-register char *p;
-register int l;
-register int c;
-{
-    asm( "locc	r9,r10,(r11)" );
-#ifdef lint
-    c = (int) p;		/* why doesn't ARGSUSED work? */
-    l = c;
-    return l;			/* Needs return value, at least */
-#endif
-}
-
-/*ARGSUSED*/
-skpc( p, l, c )
-register char *p;
-register int l;
-register int c;
-{
-    asm( "skpc r9,r10,(r11)" );
-#ifdef lint
-    c = (int) p;		/* why doesn't ARGSUSED work? */
-    l = c;
-    return l;			/* Needs return value, at least */
-#endif
-}
-#endif
diff --git a/urt/rle_row_alc.c b/urt/rle_row_alc.c
index 982e1c5e..d7631744 100644
--- a/urt/rle_row_alc.c
+++ b/urt/rle_row_alc.c
@@ -1,14 +1,14 @@
 /*
  * This software is copyrighted as noted below.  It may be freely copied,
- * modified, and redistributed, provided that the copyright notice is 
+ * modified, and redistributed, provided that the copyright notice is
  * preserved on all copies.
- * 
+ *
  * There is no warranty or other guarantee of fitness for this software,
  * it is provided solely "as is".  Bug reports or fixes may be sent
  * to the author, who may or may not act on them as he desires.
  *
  * You may not include this software in a program or other software product
- * without supplying the source, or without informing the end-user that the 
+ * without supplying the source, or without informing the end-user that the
  * source is available for no extra charge.
  *
  * If you modify this software, you should include a notice giving the
@@ -18,13 +18,13 @@
  *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
  *  to have all "void" functions so declared.
  */
-/* 
+/*
  * rle_row_alc.c - Allocate buffers for rle_getrow/rle_putrow.
- * 
- * Author:	Spencer W. Thomas
- * 		Computer Science Dept.
- * 		University of Utah
- * Date:	Fri Nov 14 1986
+ *
+ * Author:      Spencer W. Thomas
+ *              Computer Science Dept.
+ *              University of Utah
+ * Date:        Fri Nov 14 1986
  * Copyright (c) 1986, Spencer W. Thomas
  */
 
@@ -35,24 +35,24 @@
 
 /*****************************************************************
  * TAG( rle_row_alloc )
- * 
+ *
  * Allocate buffer space for use by rle_getrow and rle_putrow.
  * Inputs:
- * 	the_hdr:	Header structure for RLE file to be read or
- *			written.
+ *      the_hdr:        Header structure for RLE file to be read or
+ *                      written.
  * Outputs:
- *	scanp:		Pointer to pointer to created scanline buffer.
- *			This pointer is adjusted for the alpha channel,
- *			if present.
- *	Returns 0 for success, -1 if malloc failed.
+ *      scanp:          Pointer to pointer to created scanline buffer.
+ *                      This pointer is adjusted for the alpha channel,
+ *                      if present.
+ *      Returns 0 for success, -1 if malloc failed.
  * Assumptions:
- * 	No input scanline will extend beyond the declared xmax endpoint.
+ *      No input scanline will extend beyond the declared xmax endpoint.
  * Algorithm:
- *	Count number of channels actually used (check bitmap).
- * 	Allocate nchan*rowlength pixels, allocate a buffer
- *	to hold ncolors+alpha pointers, and give each channel
- *	rowlength pixels.  Rowlength is xmax + 1, to allow for rle_getrow
- *	usage.
+ *      Count number of channels actually used (check bitmap).
+ *      Allocate nchan*rowlength pixels, allocate a buffer
+ *      to hold ncolors+alpha pointers, and give each channel
+ *      rowlength pixels.  Rowlength is xmax + 1, to allow for rle_getrow
+ *      usage.
  */
 int
 rle_row_alloc( the_hdr, scanp )
@@ -64,33 +64,33 @@ rle_pixel ***scanp;
 
     rowlen = the_hdr->xmax + 1;
     if ( the_hdr->alpha && RLE_BIT( *the_hdr, RLE_ALPHA ) )
-	nchan++;
+        nchan++;
     for ( i = 0; i < the_hdr->ncolors; i++ )
-	if ( RLE_BIT( *the_hdr, i ) )
-	     nchan++;
+        if ( RLE_BIT( *the_hdr, i ) )
+             nchan++;
 
     ncol = the_hdr->ncolors + the_hdr->alpha;
 
     if ( (scanbuf = (rle_pixel **)malloc( ncol * sizeof(rle_pixel *) )) == 0 )
-	return -1;
+        return -1;
     if ( (pixbuf = (rle_pixel *)malloc( nchan * rowlen *
-				       sizeof(rle_pixel) )) == 0 )
+                                       sizeof(rle_pixel) )) == 0 )
     {
-	free( scanbuf );
-	return -1;
+        free( scanbuf );
+        return -1;
     }
 
     if ( the_hdr->alpha )
-	scanbuf++;
+        scanbuf++;
 
     for ( i = -the_hdr->alpha; i < the_hdr->ncolors; i++ )
-	if ( RLE_BIT( *the_hdr, i ) )
-	{
-	    scanbuf[i] = pixbuf;
-	    pixbuf += rowlen;
-	}
-	else
-	    scanbuf[i] = 0;
+        if ( RLE_BIT( *the_hdr, i ) )
+        {
+            scanbuf[i] = pixbuf;
+            pixbuf += rowlen;
+        }
+        else
+            scanbuf[i] = 0;
     *scanp = scanbuf;
 
     return 0;
@@ -99,18 +99,18 @@ rle_pixel ***scanp;
 
 /*****************************************************************
  * TAG( rle_row_free )
- * 
+ *
  * Free storage allocated by rle_row_alloc().
  * Inputs:
- * 	the_hdr:	Header structure as above.
- *	scanp:		Pointer to scanbuf above.
+ *      the_hdr:        Header structure as above.
+ *      scanp:          Pointer to scanbuf above.
  * Outputs:
- * 	Frees storage referenced by scanp and nrawp.
+ *      Frees storage referenced by scanp and nrawp.
  * Assumptions:
- * 	Storage was allocated by rle_row_alloc, or by use of same
- *	algorithm, at least.
+ *      Storage was allocated by rle_row_alloc, or by use of same
+ *      algorithm, at least.
  * Algorithm:
- * 	free scanp[0] and scanp.
+ *      free scanp[0] and scanp.
  */
 void
 rle_row_free( the_hdr, scanp )
@@ -120,12 +120,12 @@ rle_pixel **scanp;
     int i;
 
     if ( the_hdr->alpha )
-	scanp--;
+        scanp--;
     for ( i = 0; i < the_hdr->ncolors + the_hdr->alpha; i++ )
-	if ( scanp[i] != 0 )
-	{
-	    free( (char *)scanp[i] );
-	    break;
-	}
+        if ( scanp[i] != 0 )
+        {
+            free( (char *)scanp[i] );
+            break;
+        }
     free( (char *)scanp );
 }
diff --git a/urt/scanargs.c b/urt/scanargs.c
deleted file mode 100644
index f3af3342..00000000
--- a/urt/scanargs.c
+++ /dev/null
@@ -1,918 +0,0 @@
-/* 
- * $Id: scanargs.c,v 3.0.1.3 1992/02/27 21:18:14 spencer Exp $
- * 		Version 7 compatible
- * 	Argument scanner, scans argv style argument list.
- * 
- * 	Some stuff is a kludge because sscanf screws up
- * 
- * 	Gary Newman - 10/4/1979 - Ampex Corp. 
- * 
- * 	Modified by Spencer W. Thomas, Univ. of Utah, 5/81 to
- * 	add args introduced by 	a flag, add qscanargs call,
- * 	allow empty flags.
- * 
- * 	If you make improvements we'd like to get them too.
- * 	Jay Lepreau	lepreau@utah-20, decvax!harpo!utah-cs!lepreau
- * 	Spencer Thomas	thomas@utah-20, decvax!harpo!utah-cs!thomas 
- * 
- *	(I know the code is ugly, but it just grew, you see ...)
- * 
- * Modified by:	Spencer W. Thomas
- * 	Date:	Feb 25 1983
- * 1. Fixed scanning of optional args.  Now args introduced by a flag
- *    must follow the flag which introduces them and precede any other
- *    flag argument.  It is still possible for a flag introduced
- *    argument to be mistaken for a "bare" argument which occurs
- *    earlier in the format string.  This implies that flags may not
- *    be conditional upon other flags, and a message will be generated
- *    if this is attempted.
- * 
- * 2. Usage message can be formatted by inserting newlines, tabs and
- *    spaces into the format string.  This is especially useful for
- *    long argument lists.
- * 
- * 3. Added n/N types for "numeric" args.  These args are scanned
- *    using the C language conventions - a number starting 0x is
- *    hexadecimal, a number starting with 0 is octal, otherwise it is
- *    decimal.
- *
- *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
- *  to have all "void" functions so declared.
- */
-
-#include <stdio.h>
-#include <ctype.h>
-#include <stdarg.h>
-
-#include "netpbm/pm_c_util.h"
-#include "netpbm/nstring.h"
-#include "rle_config.h"
-#include "rle.h"
-
-/* 
- * An explicit assumption is made in this code that all pointers look
- * alike, except possible char * pointers.
- */
-typedef int *ptr;
-
-#define YES 1
-#define NO 0
-#define ERROR(msg)  {fprintf(stderr, "%s\n", msg); goto error; }
-
-/* 
- * Storage allocation macros
- */
-#define NEW( type, cnt )	(type *) malloc( (cnt) * sizeof( type ) )
-#define RENEW( type, ptr, cnt )	(type *) realloc( ptr, (cnt) * sizeof( type ) )
-
-static CONST_DECL char * prformat( CONST_DECL char *, int );
-static int isnum( CONST_DECL char *, int, int );
-static int	_do_scanargs( int argc, char **argv, CONST_DECL char *format,
-			      va_list argl );
-void		scan_usage( char **, CONST_DECL char * );
-
-/* 
- * Argument list is (argc, argv, format, ... )
- */
-int
-scanargs ( int argc, char **argv, CONST_DECL char *format, ... )
-{
-    va_list argl;
-    int retval;
-    va_start( argl, format );
-    retval = _do_scanargs( argc, argv, format, argl );
-    va_end( argl );
-    return retval;
-}
-    
-/* 
- * This routine is necessary because of a pyramid compiler botch that
- * uses parameter registers in a varargs routine.  The extra
- * subroutine call isolates the args on the register stack so they
- * don't get trashed.
- */
-
-static int
-_do_scanargs( argc, argv, format, argl )
-int     argc;			/* Actual arguments */
-char  **argv;
-CONST_DECL char   *format;
-va_list argl;
-{
-
-    int    check;			/* check counter to be sure all argvs
-					   are processed */
-    register CONST_DECL char  *cp;
-    int    cnt;
-    int	    optarg = 0;			/* where optional args start */
-    int	    nopt = 0;
-    char    tmpflg,			/* temp flag */
-	    typchr;			/* type char from format string */
-    char    c;
-    bool  * arg_used;			/* array of flags */
-    ptr	    aptr = 0;			/* pointer to return loc */
-
-    bool    required;
-    int	    excnt;			/* which flag is set */
-    bool    exflag;			/* when set, one of a set of exclusive
-					   flags is set */
-
-    bool    list_of;			/* set if parsing off a list of args */
-    bool    comma_list;			/* set if AT&T style multiple args */
-    bool    no_usage;			/* If set, don't print usage msg. */
-    bool    help = NO;			/* If set, always print usage. */
-    int	  * cnt_arg = 0;		/* where to stuff list count */
-    int	    list_cnt;			/* how many in list */
-    /* These are used to build return lists */
-    char ** strlist = 0;
-    int   * intlist = 0;
-    long  * longlist = 0;
-    float * fltlist = 0;
-    double *dbllist = 0;
-    char  * argp;			/* Pointer to argument. */
-
-    CONST_DECL char   *ncp;		/* remember cp during flag scanning */
-    static char   cntrl[7] = "%  %1s";	/* control string for scanf's */
-    char    junk[2];			/* junk buffer for scanf's */
-
-    /* Set up for argument counting. */
-    arg_used = NEW( bool, argc );
-    if (arg_used == NULL)
-    {
-	fprintf(stderr, "malloc failed in scanargs, exiting\n");
-	exit(-1);
-    }
-    else
-    {
-	for (cnt=0; cnt<argc; cnt++)
-	    arg_used[cnt] = NO;
-    }
-    check = 0;
-
-    /* Scan for -help in arg list. */
-    for ( cnt=1; cnt<argc; cnt++ )
-	if ( strcmp( argv[cnt], "-help" ) == 0 )
-	{
-	    check += cnt;
-	    arg_used[cnt] = YES;
-	    if ( argc == 2 )
-	    {
-		scan_usage( argv, format );
-		return 0;
-	    }
-	    else
-		help = YES;
-	}
-
-    /* If format string ends in @, don't print a usage message. */
-    no_usage = *(format + strlen( format ) - 1) == '&';
-
-    cp = format;
-    /* 
-     * Skip program name
-     */
-    while ( *cp != ' ' && *cp != '\t' && *cp != '\n' && *cp != '\0' )
-	cp++;
-
-    while (*cp)
-    {
-	required = NO;			/* reset per-arg flags */
-	list_of = NO;
-	comma_list = NO;
-	list_cnt = 0;
-	switch (*(cp++))
-	{
-	    default: 			/* all other chars */
-		break;
-	    case ' ':			/* separators */
-	    case '\t':
-	    case '\n':
-		optarg = 0;		/* end of optional arg string */
-		break;
-
-	    case '(':			/* Surrounds a comment. */
-	    {
-		int depth = 1;		/* Count parenthesis depth. */
-		while ( *cp && depth > 0 )
-		    switch ( *(cp++) )
-		    {
-		    case '(':	depth++;		break;
-		    case ')':	depth--;		break;
-		    }
-		break;
-	    }
-
-	    case '!': 			/* required argument */
-		required = YES;
-	    case '%': 			/* not required argument */
-reswitch:				/* after finding '*' or ',' */
-		switch (typchr = *(cp++))
-		{
-		    case ',':		/* argument is AT&T list of things */
-			comma_list = YES;
-		    case '*':		/* argument is list of things */
-			list_of = YES;
-			list_cnt = 0;	/* none yet */
-			cnt_arg = va_arg( argl, int *);	/* item count * here */
-			goto reswitch;	/* try again */
-
-		    case '$':		/* "rest" of argument list */
-			while ( argc > 1 && !arg_used[argc-1] )
-			    argc--;	/* find last used argument */
-			*va_arg( argl, int * ) = argc;
-			break;
-
-		    case '&':		/* Return unused args. */
-			/* Count how many.  Always include argv[0]. */
-			for ( nopt = cnt = 1; cnt < argc; cnt++ )
-			    if ( !arg_used[cnt] )
-				nopt++;
-			if ( nopt == 1 )
-			    nopt = 0;	/* Special case for no args. */
-			if ( nopt > 0 )
-			{
-			    strlist = NEW( char *, nopt + 1 );
-			    /* Copy program name, for sure. */
-			    strlist[0] = argv[0];
-			    for ( nopt = cnt = 1; cnt < argc; cnt++ )
-				if ( !arg_used[cnt] )
-				{
-				    strlist[nopt++] = argv[cnt];
-				    check += cnt;
-				    arg_used[cnt] = 1;
-				}
-			    strlist[nopt] = NULL;
-			}
-			else
-			    strlist = NULL;	/* No args, return empty. */
-
-			/* Return count and arg list. */
-			*va_arg( argl, int * ) = nopt;
-			*va_arg( argl, char *** ) = strlist;
-			break;
-
-		    case '-': 		/* argument is flag */
-			if (optarg > 0)
-			    ERROR("Format error: flag conditional on flag not allowed");
-
-		    /* go back to label */
-			ncp = cp-1;	/* remember */
-			cp -= 3;
-			for (excnt = exflag = 0
-				; *cp != ' ' && !(*cp=='-' &&(cp[-1]=='!'||cp[-1]=='%'));
-				(--cp, excnt++))
-			{
-			    for (cnt = optarg+1; cnt < argc; cnt++)
-			    {
-			    /* flags all start with - */
-				if (*argv[cnt] == '-' && !arg_used[cnt] &&
-					!ISDIGIT(argv[cnt][1]))
-				    if (*(argv[cnt] + 1) == *cp)
-				    {
-					if (*(argv[cnt] + 2) != 0)
-					    ERROR ("extra flags ignored");
-					if (exflag)
-					    ERROR ("more than one exclusive flag chosen");
-					exflag++;
-					required = NO;
-					check += cnt;
-					arg_used[cnt] = 1;
-					nopt = cnt;
-					*va_arg( argl, int *) |= (1 << excnt);
-					break;
-				    }
-			    }
-			}
-			if (required)
-			    ERROR ("flag argument missing");
-			cp = ncp;
-			/* 
-			 * If none of these flags were found, skip any
-			 * optional arguments (in the varargs list, too).
-			 */
-			if (!exflag)
-			{
-			    (void)va_arg( argl, int * );/* skip the arg, too */
-			    while (*++cp && ! ISSPACE(*cp))
-				if (*cp == '!' || *cp == '%')
-				{
-				    if ( *++cp == '*' || *cp == ',' )
-				    {
-					cp++;
-					(void)va_arg( argl, int * );
-				    }
-				    /* 
-				     * Assume that char * might be a
-				     * different size, but that all
-				     * other pointers are same size.
-				     */
-				    if ( *cp == 's' )
-					(void)va_arg( argl, char * );
-				    else
-					(void)va_arg( argl, ptr );
-				}
-			}
-			else
-			{
-			    optarg = nopt;
-			    cp++;	/* skip over - */
-			}
-
-			break;
-
-		    case 's': 		/* char string */
-		    case 'd': 		/* decimal # */
-		    case 'o': 		/* octal # */
-		    case 'x': 		/* hexadecimal # */
-		    case 'n':		/* "number" in C syntax */
-		    case 'f': 		/* floating # */
-		    case 'D': 		/* long decimal # */
-		    case 'O': 		/* long octal # */
-		    case 'X': 		/* long hexadecimal # */
-		    case 'N':		/* long number in C syntax */
-		    case 'F': 		/* double precision floating # */
-#if defined(sgi) && !defined(mips)
-			/* Fix for broken SGI IRIS 2400/3000 floats */
-			if ( typchr == 'F' ) typchr = 'f';
-#endif /* sgi */
-			for (cnt = optarg+1; cnt < argc; cnt++)
-			{
-			    argp = argv[cnt];
-
-			    if ( isnum( argp, typchr, comma_list ) )
-			    {
-				;	/* it's ok, then */
-			    }
-			    else if ( *argp == '-' && argp[1] != '\0' )
-				if ( optarg > 0 ) /* end optional args? */
-				{
-				    /* Eat the arg, too, if necessary */
-				    if ( list_cnt == 0 ) {
-					if ( typchr == 's' )
-					    (void)va_arg( argl, char * );
-					else
-					    (void)va_arg( argl, ptr );
-                    }
-				    break;
-				}
-				else
-				    continue;
-			    else if ( typchr != 's' )
-				continue;	/* not number, keep looking */
-			    
-			    /* 
-			     * Otherwise usable argument may already
-			     * be used.  (Must check this after
-			     * checking for flag, though.)
-			     */
-			    if (arg_used[cnt]) continue;
-
-			    /* 
-			     * If it's a comma-and-or-space-separated
-			     * list then count how many, and separate
-			     * the list into an array of strings.
-			     */
-			    if ( comma_list )
-			    {
-				register char * s;
-				int pass;
-
-				/*
-				 * Copy the string so we remain nondestructive
-				 */
-				s = NEW( char, strlen(argp)+1 );
-				strcpy( s, argp );
-				argp = s;
-
-				/* 
-				 * On pass 0, just count them.  On
-				 * pass 1, null terminate each string 
-				 */
-				for ( pass = 0; pass <= 1; pass++ )
-				{
-				    for ( s = argp; *s != '\0'; )
-				    {
-					if ( pass )
-					    strlist[list_cnt] = s;
-					while ( (c = *s) != '\0' && c != ' ' &&
-						c != '\t' && c != ',' )
-					    s++;
-					if ( pass )
-					    *s = '\0';
-
-					list_cnt++;	/* count separators */
-					/* 
-					 * Two commas in a row give a null
-					 * string, but two spaces
-					 * don't.  Also skip spaces
-					 * after a comma.
-					 */
-					if ( c != '\0' )
-					    while ( *++s == ' ' || *s == '\t' )
-						;
-				    }
-				    if ( pass == 0 )
-				    {
-					strlist = NEW( char *, list_cnt );
-					list_cnt = 0;
-				    }
-				}
-			    }
-			    else if ( list_of )
-				list_cnt++;   /* getting them one at a time */
-			    /* 
-			     * If it's either type of list, then alloc
-			     * storage space for the returned values
-			     * (except that comma-separated string
-			     * lists already are done).
-			     */
-			    if ( list_of )
-			    {
-				if ( list_cnt == 1 || comma_list )
-				    switch( typchr )
-				    {
-					case 's':
-					    if ( !comma_list )
-						strlist = NEW( char *, 1 );
-					    aptr = (ptr) &strlist[0];
-					    break;
-					case 'n':
-					case 'd':
-					case 'o':
-					case 'x':
-					    intlist = NEW( int, list_cnt );
-					    aptr = (ptr) &intlist[0];
-					    break;
-					case 'N':
-					case 'D':
-					case 'O':
-					case 'X':
-					    longlist = NEW( long, list_cnt );
-					    aptr = (ptr) &longlist[0];
-					    break;
-					case 'f':
-					    fltlist = NEW( float, list_cnt );
-					    aptr = (ptr) &fltlist[0];
-					    break;
-					case 'F':
-					    dbllist = NEW( double, list_cnt );
-					    aptr = (ptr) &dbllist[0];
-					    break;
-				    }
-				else
-				    switch( typchr )
-				    {
-					case 's':
-					    strlist = RENEW( char *, strlist,
-							     list_cnt );
-					    aptr = (ptr) &strlist[list_cnt-1];
-					    break;
-					case 'n':
-					case 'd':
-					case 'o':
-					case 'x':
-					    intlist = RENEW( int, intlist,
-							     list_cnt );
-					    aptr = (ptr) &intlist[list_cnt-1];
-					    break;
-					case 'N':
-					case 'D':
-					case 'O':
-					case 'X':
-					    longlist = RENEW( long, longlist,
-							      list_cnt );
-					    aptr = (ptr) &longlist[list_cnt-1];
-					    break;
-					case 'f':
-					    fltlist = RENEW( float, fltlist,
-							     list_cnt );
-					    aptr = (ptr) &fltlist[list_cnt-1];
-					    break;
-					case 'F':
-					    dbllist = RENEW( double, dbllist,
-							     list_cnt );
-					    aptr = (ptr) &dbllist[list_cnt-1];
-					    break;
-				    }
-			    }
-			    else
-				aptr = va_arg( argl, ptr );
-
-			    if ( typchr == 's' )
-			    {
-				if ( ! comma_list )
-				    *(char **)aptr = argp;
-			    }
-			    else
-			    {
-				nopt = 0;
-				do {
-				    /* 
-				     * Need to update aptr if parsing
-				     * a comma list
-				     */
-				    if ( comma_list && nopt > 0 )
-				    {
-					argp = strlist[nopt];
-					switch( typchr )
-					{
-					    case 'n':
-					    case 'd':
-					    case 'o':
-					    case 'x':
-						aptr = (ptr) &intlist[nopt];
-						break;
-					    case 'N':
-					    case 'D':
-					    case 'O':
-					    case 'X':
-						aptr = (ptr) &longlist[nopt];
-						break;
-					    case 'f':
-						aptr = (ptr) &fltlist[nopt];
-						break;
-					    case 'F':
-						aptr = (ptr) &dbllist[nopt];
-						break;
-					}
-				    }
-				    /* 
-				     * Do conversion for n and N types
-				     */
-				    tmpflg = typchr;
-				    if (typchr == 'n' || typchr == 'N' ) {
-					if (*argp != '0')
-					    tmpflg = 'd';
-					else if (*(argp+1) == 'x' ||
-						 *(argp+1) == 'X')
-					{
-					    tmpflg = 'x';
-					    argp += 2;
-					}
-					else
-					    tmpflg = 'o';
-                    }
-				    if (typchr == 'N')
-					tmpflg = toupper( tmpflg );
-
-
-				    /* put in conversion */
-				    if ( isupper( tmpflg ) )
-				    {
-					cntrl[1] = 'l';
-					cntrl[2] = tolower( tmpflg );
-				    }
-				    else
-				    {
-					cntrl[1] = tmpflg;
-					cntrl[2] = ' ';
-				    }
-				    if (sscanf (argp, cntrl, aptr, junk) != 1)
-					ERROR ("Bad numeric argument");
-				} while ( comma_list && ++nopt < list_cnt );
-			    }
-			    check += cnt;
-			    arg_used[cnt] = 1;
-			    required = NO;
-			    /*
-			     * If not looking for multiple args,
-			     * then done, otherwise, keep looking.
-			     */
-			    if ( !( list_of && !comma_list ) )
-				break;
-			    else
-				continue;
-			}
-			if (required)
-			    switch (typchr)
-			    {
-				case 'x': 
-				case 'X': 
-				    ERROR ("missing hexadecimal argument");
-				case 's': 
-				    ERROR ("missing string argument");
-				case 'o': 
-				case 'O': 
-				    ERROR ("missing octal argument");
-				case 'd': 
-				case 'D': 
-				    ERROR ("missing decimal argument");
-				case 'f': 
-				case 'F': 
-				    ERROR ("missing floating argument");
-				case 'n':
-				case 'N':
-				    ERROR ("missing numeric argument");
-			    }
-			if ( list_cnt > 0 )
-			{
-			    *cnt_arg = list_cnt;
-			    switch ( typchr )
-			    {
-				case 's':
-				    *va_arg( argl, char *** ) = strlist;
-				    break;
-				case 'n':
-				case 'd':
-				case 'o':
-				case 'x':
-				    *va_arg( argl, int ** ) = intlist;
-				    break;
-				case 'N':
-				case 'D':
-				case 'O':
-				case 'X':
-				    *va_arg( argl, long ** ) = longlist;
-				    break;
-				case 'f':
-				    *va_arg( argl, float ** ) = fltlist;
-				    break;
-				case 'F':
-				    *va_arg( argl, double **) = dbllist;
-				    break;
-			    }
-			    if ( typchr != 's' && comma_list )
-				free( (char *) strlist );
-			}
-			else if ( cnt >= argc )
-			{
-			    /* Fell off end looking, so must eat the arg */
-			    if ( typchr == 's' )
-				(void)va_arg( argl, char * );
-			    else
-				(void)va_arg( argl, ptr );
-			}
-			break;
-		    default: 		/* error */
-			fprintf (stderr,
-				 "scanargs: Corrupt or invalid format spec\n");
-			return 0;
-		}
-	}
-    }
-
-    /*  Count up empty flags */
-    for (cnt=1; cnt<argc; cnt++)
-	if (argv[cnt][0] == '-' && argv[cnt][1] == '-' && argv[cnt][2] == 0
-	    && !arg_used[cnt] )
-	    check += cnt;
-
-    /* sum from 1 to N = n*(n+1)/2 used to count up checks */
-    if (check != (((argc - 1) * argc) / 2))
-	ERROR ("extra arguments not processed");
-
-    /* If -help, always print usage. */
-    if ( help )
-	scan_usage( argv, format );
-
-    free(arg_used);
-    return 1;
-
-error: 
-    if ( !no_usage )
-	scan_usage( argv, format );
-    free(arg_used);
-    return 0;
-}
-
-void
-scan_usage( argv, format )
-char ** argv;
-CONST_DECL char * format;
-{
-    register CONST_DECL char * cp;
-
-    fprintf (stderr, "usage : ");
-    if (*(cp = format) != ' ')
-    {
-	if ( *cp == '%' )
-	{
-	    /* 
-	     * This is bogus, but until everyone can agree on a name
-	     * for (rindex/strrchr) ....
-	     */
-	    for ( cp = argv[0]; *cp != '\0'; cp++ )
-		;			/* find the end of the string */
-	    for ( ; cp > argv[0] && *cp != '/'; cp-- )
-		;			/* find the last / */
-	    if ( *cp == '/' )
-		cp++;
-	    fprintf( stderr, "%s", cp );
-
-	    cp = format + 1;		/* reset to where it should be */
-	}
-	while (putc (*cp++, stderr) != ' ');
-    }
-    else
-	fprintf (stderr, "?? ");
-    while (*cp == ' ')
-	cp++;
-    (void)prformat (cp, NO);
-}
-
-static CONST_DECL char *
-prformat (format, recurse)
-CONST_DECL char   *format;
-int 	recurse;
-{
-    register CONST_DECL char  *cp;
-    bool    required, comma_list;
-    int    list_of, depth;
-
-    cp = format;
-    if (recurse)
-	putc (' ', stderr);
-
-    required = NO;
-    list_of = 0;
-    comma_list = NO;
-    while (*cp)
-    {
-	switch (*cp)
-	{
-	    default:
-	    	cp++;
-		break;
-	    case ' ':
-	    case '\n':
-	    case '\t':
-		/* allow annotations */
-		for ( ; format < cp; format++ )
-		    putc( *format, stderr );
-		putc(*cp, stderr);
-		format = ++cp;
-		break;
-
-	    case '(':
-		/* Parentheses surround an arbitrary (parenthesis
-		 * balanced) comment.
-		 */
-		for ( ; format < cp; format++ )
-		    putc( *format, stderr );
-		for ( cp++, depth = 1; *cp && depth > 0; )
-		{
-		    /* Don't print last close paren. */
-		    if ( *cp != ')' || depth > 1 )
-			putc( *cp, stderr );
-		    switch( *(cp++) )
-		    {
-		    case '(':	depth++;		break;
-		    case ')':	depth--;		break;
-		    }
-		}
-		format = cp;
-		break;
-
-	    case '!': 
-		required = YES;
-	    case '%': 
-reswitch:
-		switch (*++cp)
-		{
-		    case ',':
-			comma_list++;
-		    case '*':
-			list_of++;
-			goto reswitch;
-
-		    case '$':		/* "rest" of argument list */
-			if (!required)
-			    putc ('[', stderr);
-			for (; format < cp - 1 - list_of; format++)
-			    putc (*format, stderr);
-			fputs( " ...", stderr );
-			if ( !required )
-			    putc( ']', stderr );
-			break;
-
-		    case '-': 		/* flags */
-			if (!required)
-			    putc ('[', stderr);
-			putc ('-', stderr);
-
-			if (cp - format > 2 + list_of)
-			    putc ('{', stderr);
-			cp = format;
-			while (*cp != '%' && *cp != '!')
-			    putc (*cp++, stderr);
-			if (cp - format > 1 + list_of)
-			    putc ('}', stderr);
-			cp += 2;	/* skip !- or %- */
-			if (*cp && !ISSPACE(*cp))
-			    cp = prformat (cp, YES);
-					/* this is a recursive call */
-
-			cp--;	/* don't ignore next character */
-
-			if (!required)
-			    putc (']', stderr);
-			break;
-		    case 's': 		/* char string */
-		    case 'd': 		/* decimal # */
-		    case 'o': 		/* octal # */
-		    case 'x': 		/* hexadecimal # */
-		    case 'f': 		/* floating # */
-		    case 'D': 		/* long decimal # */
-		    case 'O': 		/* long octal # */
-		    case 'X': 		/* long hexadecimal # */
-		    case 'F': 		/* double precision floating # */
-		    case 'n':		/* numeric arg (C format) */
-		    case 'N':		/* long numeric arg */
-			if (!required)
-			    putc ('[', stderr);
-			for (; format < cp - 1 - list_of; format++)
-			    putc (*format, stderr);
-			if ( list_of != 0 )
-			{
-			    if ( comma_list )
-				putc( ',', stderr );
-			    else
-				putc( ' ', stderr );
-			    fputs( "...", stderr );
-			}
-			if (!required)
-			    putc (']', stderr);
-			break;
-		    default: 
-			break;
-		}
-		required = NO;
-		list_of = NO;
-		comma_list = NO;
-		if (*cp)		/* check for end of string */
-		    format = ++cp;
-		if (*cp && !ISSPACE(*cp))
-		    putc (' ', stderr);
-	}
-	if (recurse && ISSPACE(*cp))
-	    break;
-    }
-    if (!recurse)
-    {
-	for ( ; format < cp; format++ )
-	    putc( *format, stderr );
-	putc ('\n', stderr);
-    }
-    return (cp);
-}
-
-/* 
- * isnum - determine whether a string MIGHT represent a number.
- * typchr indicates the type of argument we are looking for, and
- * determines the legal character set.  If comma_list is YES, then
- * space and comma are also legal characters.
- */
-static int
-isnum( str, typchr, comma_list )
-register CONST_DECL char * str;
-int typchr;
-int comma_list;
-{
-    register CONST_DECL char *allowed, *digits, *cp;
-    int hasdigit = NO;
-
-    switch( typchr )
-    {
-	case 'n':
-	case 'N':
-	    allowed = " \t,+-x0123456789abcdefABCDEF";
-	    break;
-	case 'd':
-	case 'D':
-	    allowed = " \t,+-0123456789";
-	    break;
-	case 'o':
-	case 'O':
-	    allowed = " \t,01234567";
-	    break;
-	case 'x':
-	case 'X':
-	    allowed = " \t,0123456789abcdefABCDEF";
-	    break;
-	case 'f':
-	case 'F':
-	    allowed = " \t,+-eE.0123456789";
-	    break;
-	case 's':			/* only throw out decimal numbers */
-	default:
-	    allowed = " \t,+-.0123456789";
-	    break;
-    }
-    digits = allowed;
-    while ( *digits != '0' )
-	digits++;
-    if ( ! comma_list )
-	allowed += 3;		      /* then don't allow space, tab, comma */
-
-    while ( *str != '\0' )
-    {
-    	for ( cp = allowed; *cp != '\0' && *cp != *str; cp++ )
-    	    ;
-    	if ( *cp == '\0' )
-	    return NO;		     /* if not in allowed chars, not number */
-	if ( cp - digits >= 0 )
-	    hasdigit = YES;
-	str++;
-    }
-    return hasdigit;
-}
diff --git a/urt/vaxshort.c b/urt/vaxshort.c
index 4b57b516..c39e78ec 100644
--- a/urt/vaxshort.c
+++ b/urt/vaxshort.c
@@ -1,5 +1,5 @@
 /*
- *			V A X S H O R T
+ *                      V A X S H O R T
  *
  *  Code to manipulate 16-bit integers in VAX order in a
  *  machine independent manner.
@@ -7,21 +7,21 @@
  *  (VAX is a trademark of Digital Equipment Corporation)
  *
  *  Author -
- *	Michael John Muuss
- *  
+ *      Michael John Muuss
+ *
  *  Source -
- *	SECAD/VLD Computing Consortium, Bldg 394
- *	The U. S. Army Ballistic Research Laboratory
- *	Aberdeen Proving Ground, Maryland  21005-5066
- *  
+ *      SECAD/VLD Computing Consortium, Bldg 394
+ *      The U. S. Army Ballistic Research Laboratory
+ *      Aberdeen Proving Ground, Maryland  21005-5066
+ *
  *  Distribution Status -
- *	Public Domain, Distribution Unlimitied.
+ *      Public Domain, Distribution Unlimited.
  */
 
 #include "vaxshort.h"
 
 /*
- *			V A X _ G S H O R T
+ *                      V A X _ G S H O R T
  *
  *  Obtain a 16-bit signed integer from two adjacent characters,
  *  stored in VAX order, regardless of word alignment.
@@ -29,22 +29,25 @@
 int
 vax_gshort(char *msgp)
 {
-	register unsigned char *p = (unsigned char *) msgp;
-	register int	i;
+        unsigned char *p = (unsigned char *) msgp;
+        int     i;
 
-	if( (i = (p[1] << 8) | p[0]) & 0x8000 )
-		return(i | ~0xFFFF);	/* Sign extend */
-	return(i);
+        if( (i = (p[1] << 8) | p[0]) & 0x8000 )
+                return(i | ~0xFFFF);    /* Sign extend */
+        return(i);
 }
 
 /*
- *			V A X _ P S H O R T
+ *                      V A X _ P S H O R T
  */
 char *
 vax_pshort(char *msgp, unsigned short s)
 {
 
-	msgp[0] = s & 0xFF;
-	msgp[1] = s >> 8;
-	return(msgp+2);
+        msgp[0] = s & 0xFF;
+        msgp[1] = s >> 8;
+        return(msgp+2);
 }
+
+
+
diff --git a/version.mk b/version.mk
index 7aac55ea..d579dc15 100644
--- a/version.mk
+++ b/version.mk
@@ -1,3 +1,3 @@
-NETPBM_MAJOR_RELEASE = 10
-NETPBM_MINOR_RELEASE = 86
-NETPBM_POINT_RELEASE = 38
+NETPBM_MAJOR_RELEASE = 11
+NETPBM_MINOR_RELEASE = 2
+NETPBM_POINT_RELEASE = 0