about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--GNUmakefile7
-rw-r--r--buildtools/Makefile19
-rwxr-xr-xbuildtools/configure.pl75
-rw-r--r--common.mk22
-rw-r--r--config.mk.in13
-rw-r--r--converter/other/cameratopam/Makefile4
-rw-r--r--converter/other/jpeg2000/libjasper/common.mk3
-rw-r--r--converter/other/pnmtopalm/Makefile2
-rw-r--r--converter/other/pnmtops.c55
-rw-r--r--converter/other/pstopnm.c80
-rw-r--r--converter/pbm/brushtopbm.c178
-rw-r--r--converter/pbm/pbmtoepsi.c128
-rw-r--r--doc/HISTORY66
-rw-r--r--editor/pamflip/Makefile6
-rw-r--r--editor/pamflip/pamflip_sse.c42
-rw-r--r--editor/pamfunc.c128
-rw-r--r--editor/pnmshear.c37
-rw-r--r--generator/pamgauss.c15
-rw-r--r--generator/pgmkernel.c282
-rw-r--r--lib/Makefile9
-rw-r--r--lib/libpbm3.c49
-rw-r--r--lib/libsystem.c29
-rw-r--r--lib/util/Makefile11
-rw-r--r--lib/util/nstring.c22
-rw-r--r--lib/util/pm_c_util.h2
-rw-r--r--lib/util/vasprintf.c6
-rw-r--r--other/pamarith.c6
-rw-r--r--pm_config.in.h43
-rwxr-xr-xtest/Execute-Tests25
-rw-r--r--test/Makefile24
-rw-r--r--test/Test-Order2
-rw-r--r--test/pnmshear.ok1
-rw-r--r--test/pnmshear.test19
-rw-r--r--test/ps-alt-roundtrip.ok3
-rwxr-xr-xtest/ps-alt-roundtrip.test46
-rw-r--r--test/ps-roundtrip.ok14
-rwxr-xr-xtest/ps-roundtrip.test76
-rw-r--r--test/testrandom.c (renamed from buildtools/testrandom.c)0
-rw-r--r--urt/Makefile10
-rw-r--r--version.mk4
40 files changed, 1091 insertions, 472 deletions
diff --git a/GNUmakefile b/GNUmakefile
index c6077285..035a8ed5 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -60,7 +60,7 @@ VPATH=.:$(SRCDIR)
 
 include $(BUILDDIR)/config.mk
 
-PROG_SUBDIRS = converter analyzer editor generator other
+PROG_SUBDIRS = converter analyzer editor generator other test
 PRODUCT_SUBDIRS = lib $(PROG_SUBDIRS)
 SUPPORT_SUBDIRS = urt buildtools
 
@@ -161,6 +161,11 @@ ifeq ($(HAVE_INT64),Y)
 else
 	echo "#define HAVE_INT64 0" >>$@
 endif	
+ifeq ($(WANT_SSE),Y)
+	echo "#define WANT_SSE 1" >>$@
+else
+	echo "#define WANT_SSE 0" >>$@
+endif	
 ifeq ($(DONT_HAVE_PROCESS_MGMT),Y)
 	echo "#define HAVE_FORK 0" >>$@
 else
diff --git a/buildtools/Makefile b/buildtools/Makefile
index e90feeca..6a2e33da 100644
--- a/buildtools/Makefile
+++ b/buildtools/Makefile
@@ -8,24 +8,10 @@ include $(BUILDDIR)/config.mk
 
 MERGE_OBJECTS =
 
-# These are programs that are used by the make files:
-BUILDPROGS = libopt typegen endiangen
-
-# Ideally, this directory would not contain anything but build tools, which
-# means they would all be built to run in the build environment, not the
-# target environment.  But we have no other convenient place for test tools,
-# so we put them here and build them for the target environment.
-TESTPROGS = testrandom
-
-PROGS = $(BUILDPROGS) $(TESTPROGS)
+PROGS = libopt typegen endiangen
 
 all: $(PROGS)
 
-PORTBINARIES = $(TESTPROGS)
-BINARIES = $(PORTBINARIES)
-OBJECTS = $(BINARIES:%=%.o)
-SCRIPTS =
-
 OMIT_BUILDTOOL_RULE = 1
 include $(SRCDIR)/common.mk
 
@@ -40,7 +26,8 @@ endif
 libopt.o: libopt.c
 	$(CC_FOR_BUILD) -c -o $@ $(CFLAGS_FOR_BUILD) \
 	  -DSHLIBPREFIXLIST="\"$(SHLIBPREFIXLIST)\"" \
-	  $(STRIP_DLL_VERSION) $(EXPLICIT) $(CFLAGS_PERSONAL) $(CADD) \
+	  $(STRIP_DLL_VERSION) $(EXPLICIT) \
+	  $(CFLAGS_PERSONAL) $(CFLAGS) $(CADD) \
 	  $<
 
 typegen.o endiangen.o:%.o:%.c
diff --git a/buildtools/configure.pl b/buildtools/configure.pl
index 2179454b..b03630d8 100755
--- a/buildtools/configure.pl
+++ b/buildtools/configure.pl
@@ -99,7 +99,7 @@ sub prompt($$) {
 
 
 sub promptYesNo($) {
-    my ($default) = $@;
+    my ($default) = @_;
 
     my $retval;
 
@@ -947,6 +947,7 @@ sub getInttypes($) {
 }
 
 
+
 sub getInt64($$) {
 
     my ($inttypes_h, $haveInt64R) = @_;
@@ -982,6 +983,72 @@ sub getInt64($$) {
 
 
 
+sub determineSseCapability($) {
+
+    my ($haveEmmintrinR) = @_;
+
+    if (defined($testCc)) {
+
+        print("(Doing test compiles to determine if your compiler has SSE " .
+              "intrinsics -- ignore errors)\n");
+
+        my $cflags = testCflags();
+
+        my $works;
+
+        my @cSourceCode = (
+                           "#include <emmintrin.h>\n",
+                           );
+            
+        testCompile($cflags, \@cSourceCode, \my $success);
+            
+        if ($success) {
+            print("It does.\n");
+            $$haveEmmintrinR = $TRUE;
+        } else {
+            print("It does not.  Programs will not exploit fast SSE " .
+                  "instructions.\n");
+            $$haveEmmintrinR = $FALSE;
+        }
+        print("\n");
+    } else {
+        # We conservatively estimate the facility isn't there
+        $$haveEmmintrinR = $FALSE;
+    }
+}
+
+
+
+sub getSse($) {
+
+    my ($wantSseR) = @_;
+
+    determineSseCapability(\my $haveEmmintrin);
+
+    my $gotit;
+
+    print("Use SSE instructions?\n");
+    print("\n");
+
+    my $default = $haveEmmintrin ? "y" : "n";
+
+    $$wantSseR = promptYesNo($default);
+
+    # Another complication in the SSE world is that GNU compiler options
+    # -msse, -msse2, and -march=xxx affect whether the compiler can or will
+    # generate the instructions.  When compiling for older processors, the
+    # default for these options is negative ; for newer processors, it is
+    # affirmative.  -[no]msse2 determines whether macro __SSE2__ macro is
+    # defined.  If it is not, #include <emmintrins.h> fails (<emmintrins.h>
+    # checks __SSE2__.
+
+    # The Netpbm build does not mess with these compiler options.  If the
+    # user wants something other than the default, he can put it in CFLAGS
+    # in config.mk manually or on the make command line on in CFLAGS_PERSONAL.
+}
+
+
+
 # TODO: These should do test compiles to see if the headers are in the
 # default search path, both to create a default to offer and to issue a
 # warning after user has chosen.  Also test links to test the link library.
@@ -1959,6 +2026,8 @@ getInttypes(\my $inttypesHeaderFile);
 
 getInt64($inttypesHeaderFile, \my $haveInt64);
 
+getSse(\my $wantSse);
+
 findProcessManagement(\my $dontHaveProcessMgmt);
 
 #******************************************************************************
@@ -2385,6 +2454,10 @@ if ($haveInt64 ne 'Y') {
     push(@config_mk, "HAVE_INT64 = $haveInt64\n");
 }
 
+if ($wantSse) {
+    push(@config_mk, "WANT_SSE = Y\n");
+}
+
 if ($dontHaveProcessMgmt) {
     push(@config_mk, "DONT_HAVE_PROCESS_MGMT = Y\n");
 }
diff --git a/common.mk b/common.mk
index 4077f2ea..c096bd6e 100644
--- a/common.mk
+++ b/common.mk
@@ -43,13 +43,11 @@
 # MERGEBINARIES: list of the programs that, in a merge build, are invoked
 #   via the merged Netpbm program
 # CC: C compiler command 
-# CPPFLAGS: C preprocessor options
-# CFLAGS: C compiler general options
+# CFLAGS_CONFIG: C compiler options from config.mk.
 # CFLAGS_TARGET: C compiler options for a particular target
 # LD: linker command
 # LINKERISCOMPILER: 'Y' if the linker invoked by LD is actually a compiler
 #   front end, so takes linker options in a different format
-# LDFLAGS: linker options 
 # LIBS or LOADLIBES: names of libraries to be added to all links
 # COMP_INCLUDES: Compiler option string to establish the search path for
 #   component-specific include files when compiling things or computing
@@ -64,6 +62,10 @@
 # is intended to be set on a make command line (e.g. 'make CADD=-g')
 # for options that apply just to a particular build.
 
+# In addition, there is CFLAGS, which is extra C compilation options and is
+# expected to be set via the make command line for a particular build.
+# Likewise, LDFLAGS for link-edit options.
+
 # In addition, there is CFLAGS_PERSONAL, which is extra C
 # compilation options and is expected to be set via environment variable
 # for options that are particular to the person doing the build and not
@@ -235,7 +237,19 @@ config:
 # -UNDEBUG (in any of various ways) to override this.
 #
 CFLAGS_ALL = \
-  -DNDEBUG $(CPPFLAGS) $(CFLAGS) $(CFLAGS_TARGET) $(CFLAGS_PERSONAL) $(CADD)
+  -DNDEBUG $(CPPFLAGS) $(CFLAGS_CONFIG) $(CFLAGS_TARGET) $(CFLAGS_PERSONAL) $(CFLAGS) $(CADD)
+
+ifeq ($(WANT_SSE),Y)
+  # The only two compilers we've seen that have the SSE capabilities that
+  # WANT_SSE requests are GCC and Clang, and they both have these options and
+  # require them in order for <emmintrin.h> to compile.  On some systems
+  # (x86_64, in our experience), these options are default, but on more
+  # traditional systems, they are not.  Note: __SSE2__ macro tells whether
+  # -msse2 is in effect.
+  CFLAGS_SSE = -msse -msse2
+else
+  CFLAGS_SSE =
+endif
 
 $(OBJECTS): %.o: %.c importinc
 #############################################################################
diff --git a/config.mk.in b/config.mk.in
index 3873ba19..bc1d2804 100644
--- a/config.mk.in
+++ b/config.mk.in
@@ -89,6 +89,17 @@ INTTYPES_H = <inttypes.h>
 HAVE_INT64 = Y
 #HAVE_INT64 = N
 
+# WANT_SSE tells whether the build should use SSE instructions, via the the
+# standard SSE intrinsics (operators such as '_mm_movemask_epi8').  SSE
+# instructions are faster than traditional instructions, but aren't available
+# on all CPUs.  Also, the standard intrinsics are not available in all
+# compilers.  Even if you say N here, Netpbm may still be built with some
+# SSE exploitation (e.g. SSE floating point) because the compiler will 
+# do it automatically.  You can add a -nomsse or -nomsse2 option to
+# CFLAGS or CFLAGS_PERSONAL to stop that.
+WANT_SSE = N
+#WANT_SSE = Y
+
 # CC and LD are for building the Netpbm programs, which are not necessarily
 # intended to run on the same system on which Make is running.  But when we 
 # build a build tool such as Libopt, it is meant to run only on the same 
@@ -96,7 +107,7 @@ HAVE_INT64 = Y
 # to use to compile and link build tools.
 CC_FOR_BUILD = $(CC)
 LD_FOR_BUILD = $(LD)
-CFLAGS_FOR_BUILD = $(CFLAGS)
+CFLAGS_FOR_BUILD = $(CFLAGS_CONFIG)
 LDFLAGS_FOR_BUILD = $(LDFLAGS)
 
 # MAKE is set automatically by Make to what was used to invoke Make.
diff --git a/converter/other/cameratopam/Makefile b/converter/other/cameratopam/Makefile
index 20a95aa2..4470d472 100644
--- a/converter/other/cameratopam/Makefile
+++ b/converter/other/cameratopam/Makefile
@@ -9,7 +9,7 @@ EXTERN_INCLUDES =
 ifneq ($(JPEGLIB),NONE)
   ifneq ($(JPEGHDR_DIR)x,x)
     EXTERN_INCLUDES += -I$(JPEGHDR_DIR)
-    CFLAGS += -DHAVE_JPEG
+    HAVE_JPEG_DEFINE = -DHAVE_JPEG
   endif
 endif
 
@@ -22,6 +22,8 @@ all: cameratopam
 OBJECTS = util.o identify.o cameratopam.o camera.o foveon.o decode.o \
 	canon.o ljpeg.o dng.o
 
+camera.o camera.o2: CFLAGS_TARGET = $(HAVE_JPEG_DEFINE)
+
 MERGE_OBJECTS =
 
 BINARIES = cameratopam
diff --git a/converter/other/jpeg2000/libjasper/common.mk b/converter/other/jpeg2000/libjasper/common.mk
index b31b1209..a333f5d6 100644
--- a/converter/other/jpeg2000/libjasper/common.mk
+++ b/converter/other/jpeg2000/libjasper/common.mk
@@ -13,8 +13,7 @@ partlist: $(SUBDIRS:%=%/partlist)
 	cat /dev/null $(SUBDIRS:%=%/partlist) >$@
 	echo $(LIB_OBJECTS:%=$(CURDIR)/%) >>$@
 
-.PHONY: $(SUBDIRS:%=%/partlist)
-$(SUBDIRS:%=%/partlist): %/partlist: $(CURDIR)/%
+$(SUBDIRS:%=%/partlist):
 	$(MAKE) -C $(dir $@) -f $(SRCDIR)/$(SUBDIR)/$(dir $@)Makefile \
 	    SRCDIR=$(SRCDIR) BUILDDIR=$(BUILDDIR) $(notdir $@) 
 
diff --git a/converter/other/pnmtopalm/Makefile b/converter/other/pnmtopalm/Makefile
index 7f99f95a..65790002 100644
--- a/converter/other/pnmtopalm/Makefile
+++ b/converter/other/pnmtopalm/Makefile
@@ -25,7 +25,7 @@ $(BINARIES): %: %.o palmcolormap.o $(NETPBMLIB) $(LIBOPT)
 	  $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
 
 gen_palm_colormap : % : %.c palmcolormap.o
-	$(CC) -I importinc $(CPPFLAGS) $(CFLAGS) -o $@ \
+	$(CC) -I importinc $(CFLAGS_ALL) -o $@ \
 	  $< palmcolormap.o \
 	  $(LIBOPTS) $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(LADD)
 
diff --git a/converter/other/pnmtops.c b/converter/other/pnmtops.c
index 150331a1..316b7626 100644
--- a/converter/other/pnmtops.c
+++ b/converter/other/pnmtops.c
@@ -114,8 +114,10 @@ struct cmdlineInfo {
     unsigned int dict;
     unsigned int vmreclaim;
     unsigned int verbose;
+    unsigned int debug;
 };
 
+static bool debug;
 static bool verbose;
 
 
@@ -248,6 +250,7 @@ parseCommandLine(int argc, const char ** argv,
     OPTENT3(0, "vmreclaim",   OPT_FLAG,  NULL, &cmdlineP->vmreclaim,     0);
     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, 
             &cmdlineP->levelSpec,              0);
     
@@ -395,6 +398,16 @@ writeFileChar(const char * const buffer,
 
 
 
+static void
+writeFileByte(unsigned char const byte,
+              const char *  const name,
+              FILE *        const ofP) {
+
+    writeFile(&byte, 1, name, ofP);
+}
+
+
+
 #define MAX_FILTER_CT 10
     /* The maximum number of filters this code is capable of applying */
 
@@ -621,17 +634,28 @@ flateFilter(FILE *          const ifP,
 
 
 static void
-rlePutBuffer (unsigned int    const repeat,
+rlePutBuffer (bool            const repeatMode,
               unsigned int    const count,
-              unsigned int    const repeatitem,
+              unsigned char   const repeatitem,
               unsigned char * const itembuf,
               FILE *          const fP) {
+/*----------------------------------------------------------------------------
+   Output some RLE data.  There are two forms of output:
 
-    if (repeat) {
-        fputc(257 - count,  fP);
-        fputc(repeatitem, fP);
+     'repeatMode' true: output a repeat sequence, indicating to repeat byte
+     'repeatitem' 'count' times.
+
+     'repeatMode' false: output a non-repeat sequence indicating the
+     'count' characters in itembuf[].
+-----------------------------------------------------------------------------*/
+    assert(count > 0);
+    assert(count <= 128);
+
+    if (repeatMode) {
+        writeFileByte((257 - count) % 256, "rlePutBuffer", fP);
+        writeFileByte(repeatitem, "rlePutBuffer", fP);
     } else {
-        fputc(count - 1, fP);
+        writeFileByte(count - 1, "rlePutBuffer", fP);
         writeFile(itembuf, count, "rlePutBuffer", fP);
     }
 }
@@ -975,6 +999,12 @@ addFilter(const char *    const description,
         pm_message("%s filter spawned: pid %u",
                    description, (unsigned)pid);
     
+    if (debug) {
+        int const outFd    = fileno(oldFeedFileP);
+        int const supplyFd = fileno(newFeedFileP);
+        pm_message("PID %u writes to FD %u, its supplier writes to FD %u",
+                   (unsigned)pid, outFd, supplyFd);
+    }
     fclose(oldFeedFileP);  /* Child keeps this open now */
 
     addToPidList(pidList, pid);
@@ -1937,7 +1967,17 @@ convertRaster(struct pam * const inpamP,
               unsigned int const bitsPerSample,
               bool         const psFilter,
               FILE *       const fP) {
+/*----------------------------------------------------------------------------
+   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.
 
+   'bitsPerSample' is how many bits each sample is to take in the Postscript
+   output.
+-----------------------------------------------------------------------------*/
     if (PAM_FORMAT_TYPE(inpamP->format) == PBM_TYPE && bitsPerSample == 1)  {
         unsigned char * bitrow;
         unsigned int row;
@@ -2097,7 +2137,8 @@ main(int argc, const char * argv[]) {
 
     parseCommandLine(argc, argv, &cmdline);
 
-    verbose = cmdline.verbose;
+    verbose = cmdline.verbose || cmdline.debug;
+    debug   = cmdline.debug;
 
     if (cmdline.flate && !progIsFlateCapable())
         pm_error("This program cannot do flate compression.  "
diff --git a/converter/other/pstopnm.c b/converter/other/pstopnm.c
index f4081464..c0d6a4ee 100644
--- a/converter/other/pstopnm.c
+++ b/converter/other/pstopnm.c
@@ -496,42 +496,72 @@ computeBoxToExtract(struct Box const cmdlineExtractBox,
 static enum Orientation
 computeOrientation(struct CmdlineInfo const cmdline, 
                    struct Box         const extractBox) {
-
-    unsigned int const inputWidth  = extractBox.urx - extractBox.llx;
-    unsigned int const inputHeight = extractBox.ury - extractBox.lly;
+/*----------------------------------------------------------------------------
+   The proper orientation of the image on the page, given the user's
+   parameters 'cmdline' and the image dimensions 'extractBox'.
+-----------------------------------------------------------------------------*/
+    /* We're putting an _image_ on a _page_.  Either one can have portrait or
+       landscape aspect ratio.  In our return value, orientation just means
+       whether the image is rotated on the page: Portrait means it isn't
+       Landscape means it is.  The result can be confusing: Consider an image
+       which is a landscape, wider than it is tall, being printed on a page
+       which is also wider than it is tall.  The orientation we would return
+       for that case is Portrait.
+
+       The decision is simple: if the user didn't request a particular
+       orientation, we return the value that makes the image orientation match
+       the page orientation.  If both possibilities match equally (because the
+       image or the page is square), we return Portrait.
+    */
 
     enum Orientation retval;
 
     if (cmdline.orientation != UNSPECIFIED)
         retval = cmdline.orientation;
     else {
-        if ((!cmdline.xsize || !cmdline.ysize) &
-            (cmdline.xsize || cmdline.ysize)) {
-            /* User specified one output dimension, but not the other,
-               so we can't use output dimensions to make the decision.  So
-               just use the input dimensions.
-            */
-            if (inputHeight > inputWidth) retval = PORTRAIT;
-            else retval = LANDSCAPE;
+        /* Dimensions of image to print, in points */
+        unsigned int const imageWidPt = extractBox.urx - extractBox.llx;
+        unsigned int const imageHgtPt = extractBox.ury - extractBox.lly;
+        
+        /* Dimensions of image to print, in pixels (possibly of assumed
+           resolution)
+        */
+        unsigned int imageWidXel;
+        unsigned int imageHgtXel;
+
+        /* We have to deal with the awkward case that the printed pixels are
+           not square.  We match up the aspect ratio of the image in _pixels_
+           and the aspect ratio of the page in _pixels_.  But only the ratio
+           matters; we don't care what the absolute size of the pixels is.
+           And that's good, because if the user didn't specify xsize/ysize, we
+           don't know the absolute size in pixels.  In that case, fortunately,
+           the pixels are guaranteed to be square so we can just pretend it is
+           one point per pixel and get the right result.
+        */
+
+        if (cmdline.xsize && cmdline.ysize) {
+            imageWidXel = cmdline.xsize;
+            imageHgtXel = cmdline.ysize;
         } else {
-            unsigned int outputWidth, outputHeight;
-            if (cmdline.xsize) {
-                /* He gave xsize and ysize, so that's the output size */
-                outputWidth  = cmdline.xsize;
-                outputHeight = cmdline.ysize;
-            } else {
-                /* Well then we'll just use his (or default) xmax, ymax */
-                outputWidth  = cmdline.xmax;
-                outputHeight = cmdline.ymax;
-            }
+            /* Pixels are square, so it doesn't matter what the resolution
+               is; just call it one pixel per point.
+            */
+            imageWidXel = imageWidPt;
+            imageHgtXel = imageHgtPt;
 
-            if (inputHeight > inputWidth && outputHeight > outputWidth)
+            if (imageHgtXel >= imageWidXel && cmdline.ymax >= cmdline.xmax) {
+                /* Both image and page are higher than wide, so no rotation */
                 retval = PORTRAIT;
-            else if (inputHeight < inputWidth && 
-                     outputHeight < outputWidth)
+            } else if (imageHgtXel < imageWidXel &&
+                       cmdline.ymax < cmdline.xmax) {
+                /* Both image and page are wider than high, so no rotation */
                 retval = PORTRAIT;
-            else 
+            } else {
+                /* Image and pixel have opposite aspect ratios, so rotate
+                   for best fit.
+                */
                 retval = LANDSCAPE;
+            }
         }
     }
     return retval;
diff --git a/converter/pbm/brushtopbm.c b/converter/pbm/brushtopbm.c
index 0cffaa4d..c50fe8a1 100644
--- a/converter/pbm/brushtopbm.c
+++ b/converter/pbm/brushtopbm.c
@@ -1,4 +1,4 @@
-/* brushtopbm.c - read a doodle brush file and write a portable bitmap
+/* brushtopbm.c - read a doodle brush file and write a PBM image
 **
 ** Copyright (C) 1988 by Jef Poskanzer.
 **
@@ -12,96 +12,100 @@
 
 #include "pbm.h"
 
-static void getinit ARGS(( FILE* file, int* colsP, int* rowsP ));
-static bit getbit ARGS(( FILE* file ));
+#define HEADERSIZE 16   /* 16 is just a guess at the header size */
 
-int
-main( argc, argv )
-    int argc;
-    char* argv[];
-    {
-    FILE* ifp;
-    bit* bitrow;
-    register bit* bP;
-    int rows, cols, padright, row, col;
-
-
-    pbm_init( &argc, argv );
-
-    if ( argc > 2 )
-	pm_usage( "[brushfile]" );
-
-    if ( argc == 2 )
-	ifp = pm_openr( argv[1] );
-    else
-	ifp = stdin;
-
-    getinit( ifp, &cols, &rows );
-
-    pbm_writepbminit( stdout, cols, rows, 0 );
-    bitrow = pbm_allocrow( cols );
-
-    /* Compute padding to round cols up to the next multiple of 16. */
-    padright = ( ( cols + 15 ) / 16 ) * 16 - cols;
-
-    for ( row = 0; row < rows; ++row )
-	{
-	/* Get data. */
-        for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
-	    *bP = getbit( ifp );
-	/* Discard line padding. */
-        for ( col = 0; col < padright; ++col )
-	    (void) getbit( ifp );
-	/* Write row. */
-	pbm_writepbmrow( stdout, bitrow, cols, 0 );
-	}
-
-    pm_close( ifp );
-    pm_close( stdout );
-    
-    exit( 0 );
-    }
 
 
-static int item, bitsperitem, bitshift;
+static void
+getinit(FILE *         const ifP,
+        unsigned int * const colsP,
+        unsigned int * const rowsP) {
+
+    unsigned char header[HEADERSIZE];
+    size_t bytesRead;
+
+    bytesRead = fread(header, sizeof(header), 1, ifP);
+    if (bytesRead !=1)
+        pm_error("Error reading header");   
+
+    if (header[0] != 1)
+        pm_error("bad magic number 1");
+    if (header[1] != 0)
+        pm_error("bad magic number 2");
+
+    *colsP =  (header[2] << 8) + header[3];  /* Max 65535 */
+    *rowsP =  (header[4] << 8) + header[5];  /* Max 65535 */
+}
+
+
 
 static void
-getinit( file, colsP, rowsP )
-    FILE* file;
-    int* colsP;
-    int* rowsP;
-    {
-    int i;
-
-    if ( getc( file ) != 1 )
-	pm_error( "bad magic number 1" );
-    if ( getc( file ) != 0 )
-	pm_error( "bad magic number 2" );
-    *colsP = getc( file ) << 8;
-    *colsP += getc( file );
-    *rowsP = getc( file ) << 8;
-    *rowsP += getc( file );
-    bitsperitem = 8;
-
-    /* Junk rest of header. */
-    for ( i = 0; i < 10; ++i )  /* 10 is just a guess at the header size */
-	(void) getc( file );
-    }
+validateEof(FILE * const ifP) {
+
+    int rc;
+    rc = getc(ifP);
+    if (rc != EOF)
+        pm_message("Extraneous data at end of file");
+}
+
+
+/*
+   The routine for converting the raster closely resembles the pbm
+   case of pnminvert.  Input is padded up to 16 bit border.
+   afu December 2013
+ */
+
+
 
-static bit
-getbit( file )
-    FILE* file;
-    {
-    bit b;
-
-    if ( bitsperitem == 8 )
-	{
-	item = getc( file );
-	bitsperitem = 0;
-	bitshift = 7;
-	}
-    ++bitsperitem;
-    b = ( ( item >> bitshift) & 1 ) ? PBM_WHITE : PBM_BLACK;
-    --bitshift;
-    return b;
+int
+main(int argc, const char ** argv)  {
+
+    FILE * ifP;
+    bit * bitrow;
+    unsigned int rows, cols, row;
+
+    pm_proginit(&argc, argv);
+
+    if (argc-1 > 0) {
+        ifP = pm_openr(argv[1]);
+        if (argc-1 > 1)
+            pm_error("Too many arguments (%u).  "
+                     "The only argument is the brush file name.", argc-1);
+    } else
+        ifP = stdin;
+
+    getinit(ifP, &cols, &rows);
+
+    pbm_writepbminit(stdout, cols, rows, 0);
+
+    bitrow = pbm_allocrow_packed(cols + 16);
+
+    for (row = 0; row < rows; ++row) {
+        unsigned int const inRowBytes = ((cols + 15) / 16) * 2;
+        unsigned int i;
+        size_t bytesRead;
+
+        bytesRead = fread (bitrow, 1, inRowBytes, ifP); 
+        if (bytesRead != inRowBytes)
+            pm_error("Error reading a row of data from brushfile");
+
+        for (i = 0; i < inRowBytes; ++i)
+            bitrow[i] = ~bitrow[i];
+
+        /* Clean off remainder of fractional last character */
+        if (cols % 8 > 0) {
+            unsigned int const colChars = pbm_packed_bytes(cols);
+            bitrow[colChars-1] >>= 8 - cols % 8;
+            bitrow[colChars-1] <<= 8 - cols % 8;
+        }
+
+        pbm_writepbmrow_packed(stdout, bitrow, cols, 0);
     }
+
+    validateEof(ifP);
+
+    pm_close(ifP);
+    pm_close(stdout);
+    
+    return 0;
+}
diff --git a/converter/pbm/pbmtoepsi.c b/converter/pbm/pbmtoepsi.c
index 6d2065dc..87985a1f 100644
--- a/converter/pbm/pbmtoepsi.c
+++ b/converter/pbm/pbmtoepsi.c
@@ -16,19 +16,24 @@
 ** implied warranty.
 */
 
+/*
+ *
+ * Official guide from Adobe:
+ *
+ * Encapsulated PostScript File Format Specification
+ * http://partners.adobe.com/public/developer/en/ps/5002.EPSF_Spec.pdf
+ *
+*/
+
 #include "pm_c_util.h"
 #include "pbm.h"
 #include "shhopt.h"
 
-#if !defined(MAXINT)
-#define MAXINT (0x7fffffff)
-#endif
-
 struct cmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    const char *inputFilespec;  /* Filespecs of input files */
+    const char *inputFileName;
 
     unsigned int dpiX;     /* horiz component of DPI option */
     unsigned int dpiY;     /* vert component of DPI option */
@@ -40,8 +45,9 @@ struct cmdlineInfo {
 
 
 static void
-parse_dpi(char * const dpiOpt, 
-          unsigned int * const dpiXP, unsigned int * const dpiYP) {
+parseDpi(char *         const dpiOpt, 
+         unsigned int * const dpiXP,
+         unsigned int * const dpiYP) {
 
     char *dpistr2;
     unsigned int dpiX, dpiY;
@@ -72,7 +78,7 @@ parse_dpi(char * const dpiOpt,
 
 
 static void
-parseCommandLine(int argc, char ** const argv,
+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
@@ -97,48 +103,58 @@ 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 (dpiOptSpec)
-        parse_dpi(dpiOpt, &cmdlineP->dpiX, &cmdlineP->dpiY);
+        parseDpi(dpiOpt, &cmdlineP->dpiX, &cmdlineP->dpiY);
     else
         cmdlineP->dpiX = cmdlineP->dpiY = 72;
     
     if ((argc-1) > 1)
-        pm_error("Too many arguments (%d).  Only argument is input filespec",
+        pm_error("Too many arguments (%d).  Only argument is input file name",
                  argc-1);
     
     if (argc-1 == 0)
-        cmdlineP->inputFilespec = "-";
+        cmdlineP->inputFileName = "-";
     else
-        cmdlineP->inputFilespec = argv[1];
+        cmdlineP->inputFileName = argv[1];
 }
 
 
 
 static void
-findPrincipalImage(bit ** const bits, 
-                   int    const rows,
-                   int    const cols,
-                   int *  const topP,
-                   int *  const bottomP,
-                   int *  const leftP,
-                   int *  const rightP) {
+findPrincipalImage(bit **         const bits, 
+                   unsigned int   const rows,
+                   unsigned int   const cols,
+                   unsigned int * const topP,
+                   unsigned int * const bottomP,
+                   unsigned int * const leftP,
+                   unsigned int * const rightP) {
+/*----------------------------------------------------------------------------
+   Find the foreground image on a white background.
+
+   Find the image in the pixels bits[][], which is 'rows' rows by
+   'cols' columns.
 
-    int top, bottom, left, right;
-    int row;
+   Return the boundaries of the foreground image as *topP, *bottomP, *leftP,
+   and *rightP.
+
+   If the image is all white, consider the entire image foreground.
+-----------------------------------------------------------------------------*/
+    unsigned int top, bottom, left, right;
+    unsigned int row;
 
     /* Initial values */
-    top = MAXINT;
-    bottom = -MAXINT;
-    left = MAXINT;
-    right = -MAXINT;
+    top    = rows;
+    bottom = 0;
+    left   = cols;
+    right  = 0;
  
-    for (row = 0; row < rows; row++) {
-        int col;
-        for (col = 0; col < cols; col++) {
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+        for (col = 0; col < cols; ++col) {
             if (bits[row][col] == PBM_BLACK) {
                 if (row < top) 
                     top = row;
@@ -152,16 +168,19 @@ findPrincipalImage(bit ** const bits,
         }
     }
 
-    if(bottom == -MAXINT) {  /* No black pixels encountered */ 
+    if (top > bottom) {
+        /* No black pixels encountered */ 
         pm_message("Blank page");
-        top = left = 0;
-        bottom = rows-1;  right = cols-1;
-	}
+        top    = 0;
+        left   = 0;
+        bottom = rows - 1;
+        right  = cols - 1;
+    }
 
-    *topP = top;
+    *topP    = top;
     *bottomP = bottom;
-    *leftP = left;
-    *rightP = right;
+    *leftP   = left;
+    *rightP  = right;
 }
 
 
@@ -190,7 +209,8 @@ eightPixels(bit ** const bits,
 /*----------------------------------------------------------------------------
   Compute a byte that represents the 8 pixels starting at Column 'col' of
   row 'row' of the raster 'bits'.  The most significant bit of the result
-  represents the leftmost pixel, with 1 meaning black.
+  represents the leftmost pixel, with 1 meaning black.  (Note that this is
+  the opposite of Postscript.)
 
   The row is 'cols' columns wide, so fill on the right with white if there
   are not eight pixels in the row starting with Column 'col'.
@@ -212,23 +232,23 @@ eightPixels(bit ** const bits,
 
 
 int
-main(int argc, char * argv[]) {
+main(int argc, const char * argv[]) {
 
     struct cmdlineInfo cmdline;
-    FILE *ifP;
-    bit **bits;
+    FILE * ifP;
+    bit ** bits;
     int rows, cols;
-    int top, bottom, left, right;
+    unsigned int top, bottom, left, right;
         /* boundaries of principal part of image -- i.e. excluding white
            borders
         */
 
-    pbm_init( &argc, argv );
+    pm_proginit(&argc, argv);
     
     parseCommandLine(argc, argv, &cmdline);
 
-    ifP = pm_openr(cmdline.inputFilespec);
-    bits = pbm_readpbm( ifP, &cols, &rows );
+    ifP = pm_openr(cmdline.inputFileName);
+    bits = pbm_readpbm(ifP, &cols, &rows);
     pm_close(ifP);
 
     findPrincipalImage(bits, rows, cols, &top, &bottom, &left, &right);
@@ -244,24 +264,26 @@ main(int argc, char * argv[]) {
                right - left + 1, bottom - top + 1, bottom - top + 1);
 
         for (row = top; row <= bottom; row++) {
-            int col;
-	    int outChars = 2;
-	    printf("%% ");
+            unsigned int col;
+            unsigned int outChars;
+            printf("%% ");
+
+            outChars = 2;  /* initial value */
 
             for (col = left; col <= right; col += 8) {
                 if (outChars == 72) {
-		  printf("\n%% ");
-                  outChars = 2;
-		}  
+                    printf("\n%% ");
+                    outChars = 2;
+                }  
 
                 printf("%02x", eightPixels(bits, row, col, cols));
                 outChars += 2;
-	    }
-	    if (outChars > 0)
+            }
+            if (outChars > 0)
                 printf("\n");
         }
         printf("%%%%EndImage\n");
         printf("%%%%EndPreview\n");
     }
-    exit(0);
+    return 0;
 }
diff --git a/doc/HISTORY b/doc/HISTORY
index e08a3e76..2dc6371b 100644
--- a/doc/HISTORY
+++ b/doc/HISTORY
@@ -4,11 +4,21 @@ Netpbm.
 CHANGE HISTORY 
 --------------
 
-13.12.26 BJH  Release 10.65.06
+13.12.26 BJH  Release 10.65.00
 
-              pamgauss: Fix typo in message.
+              pamfunc: add -changemaxval.
+
+              pgmkernel: add -maxval.
+
+              Recognize SIGPWR on systems that have it in messages
+              about signal received.
 
-13.12.15 BJH  Release 10.65.05
+              pstopnm: More rational default for landscape/portrait choice.
+              In particular, if the image or page is square, image will always
+              be in portrait (not rotated).
+
+              brushtopbm: check for read errors, extraneous data after apparent
+              end of image.
 
               pnmtops: Fix spurious blank line in asciihex encoding of the
               image raster.  Probably harmless.  Introduced in 10.56
@@ -17,6 +27,19 @@ CHANGE HISTORY
               pnmtops: Fix crash with 12 bits per sample.  Introduced in 10.53
               (December 2010).  Thanks Prophet of the Way <afu@wta.att.ne.jp>.
 
+              pnmtops: Fix bug: wrong output with -ascii85.  Introduced in
+              10.63 (June 2013).
+
+              pnmtops: Fix bug: wrong output with -rle.  Introduced in
+              10.63 (June 2013).
+
+              pnmtops: Fix bug: program hangs if it inherits lots of open
+              files.  Introduced in 10.56 (September 2011).
+
+              pnmtops: Fix bug: fails with message about waitpid() failing
+              if invoked with SIGCHLD ignored.  Introduced in 10.56
+              (September 2011).
+
               pbmtoepsi: fix handling of all-white image.  Always broken.
               Thanks Prophet of the Way <afu@wta.att.ne.jp>.
 
@@ -30,35 +53,30 @@ CHANGE HISTORY
               > 25:1. Thanks Prophet of the Way <afu@wta.att.ne.jp>.
               Always broken.
 
-13.11.24 BJH  Release 10.64.04
-
-              pnmtops: Fix bug: wrong output with -ascii85.  Introduced in
-              10.63 (June 2013).
-
-              pnmtops: Fix bug: wrong output with -rle.  Introduced in
-              10.63 (June 2013).
-
-              pnmtops: Fix bug: fails with message about waitpid() failing
-              if invoked with SIGCHLD ignored.  Introduced in 10.56
-              (September 2011).
+              pgmkernel: fix some pixels 1 less than they should be.
 
-13.11.12 BJH  Release 10.64.03
-
-              pnmtops: Fix bug: closes Standard Error.  Introduced in
-              10.64.02 (today).
+              pamgauss: Fix typo in message.
 
-13.11.12 BJH  Release 10.64.02
+              Fix wild pointer dereference when memory allocation for a string
+              fails.  Broken since 10.36 (September 2006).
 
-              pnmtops: Fix bug: program hangs if it inherits lots of open
-              files.  Introduced in 10.56 (September 2011).
+              Build for big-endian machines: fix syntax error so it compiles.
+              Introduced in 10.63 (June 2013).
 
               Fix compile failure on system such as OpenBSD that don't have
               SIGWINCH and SIGIO.  Broken since 10.49 (December 2009).
 
-13.10.06 BJH  Release 10.64.01
+              Build: Use SSE2 vector instructions when compiling with Clang,
+              as done already with GCC.
 
-              Build for big-endian machines: fix syntax error so it compiles.
-              Introduced in 10.63 (June 2013).
+              Build: Use <emmintrin.h> interface for SSE intrinsics
+              instead of GCC-specific versions.  Thanks Prophet of the Way
+              <afu@wta.att.ne.jp>.
+
+              Build on system without vasprintf (not GNU libc): fix compiler
+              warning.
+
+              Apple build: use vasprintf.
 
 13.09.28 BJH  Release 10.64.00
 
diff --git a/editor/pamflip/Makefile b/editor/pamflip/Makefile
index 497c5379..83e961a7 100644
--- a/editor/pamflip/Makefile
+++ b/editor/pamflip/Makefile
@@ -5,6 +5,8 @@ endif
 SUBDIR = editor/pamflip
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
+default: all
+
 include $(BUILDDIR)/config.mk
 
 SUBDIRS =
@@ -21,10 +23,12 @@ OBJECTS = $(PAMFLIP_OBJECTS)
 
 MERGE_OBJECTS = $(OBJECTS:%.o=%.o2)
 
+include $(SRCDIR)/common.mk
+
 .PHONY: all
 all: $(BINARIES) $(SUBDIRS:%=%/all)
 
-include $(SRCDIR)/common.mk
+pamflip_sse.o pamflip_sse.o2: CFLAGS_TARGET = $(CFLAGS_SSE)
 
 pamflip: $(PAMFLIP_OBJECTS) $(NETPBMLIB) $(LIBOPT)
 	$(LD) -o $@ $(PAMFLIP_OBJECTS) \
diff --git a/editor/pamflip/pamflip_sse.c b/editor/pamflip/pamflip_sse.c
index 5a256f9d..eccbe965 100644
--- a/editor/pamflip/pamflip_sse.c
+++ b/editor/pamflip/pamflip_sse.c
@@ -28,7 +28,11 @@
 
 #include "pamflip_sse.h"
 
-#if HAVE_GCC_SSE2 && defined(__SSE2__)
+/* Note that WANT_SSE implies the user expects SSE to be available
+   (i.e. <emmintrin.h> exists).
+*/
+
+#if WANT_SSE && defined(__SSE2__)
 
 /*----------------------------------------------------------------------------
    This is a specialized routine for row-for-column PBM transformations.
@@ -68,6 +72,8 @@
    possibility.
 -----------------------------------------------------------------------------*/
 
+#include <emmintrin.h>
+
 typedef char v16qi __attribute__ ((vector_size (16)));
 typedef int  v4di  __attribute__ ((vector_size (16)));
 
@@ -82,10 +88,23 @@ typedef int  v4di  __attribute__ ((vector_size (16)));
    variable must be vector from the beginning.
 
    Changes for your local system are okay, but if you intend to
-   publish the them, please specify the compiler version you used.
+   publish them, please specify the compiler version you used.
+
+   This code has been tested on gcc versions 4.2.0, 4.2.4, 4.3.2,
+   4.4.3, 4.4.4, 4.5.0, 4.5.2, 4.6.0 and 4.6.1 clang versions
+   3.0, 3.2, 3.3.
+
+   We use SSE instructions in "_mm_" form in favor of "__builtin_".
+   In GCC the "__builtin_" form is documented but "_mm_" is not.
+   Former versions of this source file used "__builtin_".  This was
+   changed to make possible compilation with clang.
+
+   _mm_slli_epi32 : __builtin_ia32_pslldi128
+   _mm_cmpeq_epi8 : __builtin_ia32_pcmpeqb128
+   _mm_movemask_epi8 : __builtin_ia32_pmovmskb128
+
+   The conversion requires <emmintrin.h> .
 
-   This code has been tested on gcc versions: 4.2.0, 4.2.4, 4.3.2,
-   4.4.3, 4.4.4 and 4.5.0 .
 */
 
 
@@ -133,9 +152,10 @@ transpose16Bitrows(unsigned int const cols,
             block[12][col8], block[13][col8],
             block[14][col8], block[15][col8] };
 
-        register v16qi const compare =__builtin_ia32_pcmpeqb128(vReg,zero128);
+        register __m128i const compare =
+            _mm_cmpeq_epi8((__m128i)vReg, (__m128i)zero128);
 
-        if (__builtin_ia32_pmovmskb128(compare) != 0xffff) {
+        if (_mm_movemask_epi8(compare) != 0xffff) {
 
             /* There is some black content in this block; write to outplane */
             
@@ -147,10 +167,10 @@ transpose16Bitrows(unsigned int const cols,
             for (i = 0; i < 7; ++i) {
                 /* GCC (>=4.2) automatically unrolls this loop */  
                 outplane[outrow++][outcol16] =
-                    __builtin_ia32_pmovmskb128(vReg);
-                vReg = (v16qi)__builtin_ia32_pslldi128 ((v4di)vReg, 1);
+                    _mm_movemask_epi8((__m128i)vReg);
+                vReg = (v16qi)_mm_slli_epi32((__m128i)vReg, 1);
             }
-            outplane[outrow][outcol16] = __builtin_ia32_pmovmskb128(vReg);
+            outplane[outrow][outcol16] = _mm_movemask_epi8((__m128i)vReg);
         } else {
             /* The block is completely white; skip. */
         }
@@ -391,12 +411,12 @@ pamflip_transformRowsToColumnsPbmSse(const struct pam * const inpamP,
     pbm_freearray(outplane, outpamP->height + 7);
     pbm_freearray(inrow, 16);
 }
-#else  /* SSE functions exist */
+#else  /* WANT_SSE */
 
 void
 pamflip_transformRowsToColumnsPbmSse(const struct pam * const inpamP,
                                      const struct pam * const outpamP,
-                                     struct xformCore const xformCore) { 
+                                     struct xformCore   const xformCore) { 
 
     /* Nobody is supposed to call this */
     assert(false);
diff --git a/editor/pamfunc.c b/editor/pamfunc.c
index 2f6ac682..5945b82d 100644
--- a/editor/pamfunc.c
+++ b/editor/pamfunc.c
@@ -13,8 +13,8 @@
   multiply/divide where possible.  Especially when multiplying by an 
   integer.
 
-  2) For multiply/divide, give option of simply changing the maxval and
-  leaving the raster alone.
+  2) speed up by not transforming the raster in the idempotent cases
+  (e.g. multiply by one).
 
 ******************************************************************************/
 
@@ -23,7 +23,7 @@
 #include "shhopt.h"
 #include "pam.h"
 
-enum function {
+enum Function {
     FN_MULTIPLY,
     FN_DIVIDE,
     FN_ADD,
@@ -42,22 +42,23 @@ enum function {
    a "max" function.
 */
 
-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 */
-    enum function function;
+    const char * inputFileName;
+    enum Function function;
     union {
-        float multiplier;
-        float divisor;
-        int adder;
-        int subtractor;
+        float        multiplier;
+        float        divisor;
+        int          adder;
+        int          subtractor;
         unsigned int max;
         unsigned int min;
         unsigned int mask;
         unsigned int shiftCount;
     } u;
+    unsigned int changemaxval;
     unsigned int verbose;
 };
 
@@ -80,8 +81,8 @@ parseHex(const char * const hexString) {
          
 
 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.
@@ -126,13 +127,16 @@ parseCommandLine(int argc, char ** const argv,
             &shiftleftSpec,  0);
     OPTENT3(0,   "shiftright", OPT_UINT,   &cmdlineP->u.shiftCount,
             &shiftrightSpec, 0);
-    OPTENT3(0,   "verbose",    OPT_FLAG,   NULL, &cmdlineP->verbose,       0);
+    OPTENT3(0,   "verbose",      OPT_FLAG,   NULL, &cmdlineP->verbose,
+            0);
+    OPTENT3(0,   "changemaxval", OPT_FLAG,   NULL, &cmdlineP->changemaxval,
+            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 (multiplierSpec + divisorSpec + adderSpec + subtractorSpec +
@@ -186,16 +190,17 @@ parseCommandLine(int argc, char ** const argv,
                  argc-1);
 
     if (argc-1 < 1)
-        cmdlineP->inputFilespec = "-";
+        cmdlineP->inputFileName = "-";
     else 
-        cmdlineP->inputFilespec = argv[1];
+        cmdlineP->inputFileName = argv[1];
     
+    free(option_def);
 }
 
 
 
 static bool
-isDyadicMaskFunction(enum function const fn) {
+isDyadicMaskFunction(enum Function const fn) {
 
     return (fn == FN_AND || fn == FN_OR || fn == FN_XOR);
 }
@@ -203,7 +208,7 @@ isDyadicMaskFunction(enum function const fn) {
 
 
 static bool
-isMaskFunction(enum function const fn) {
+isMaskFunction(enum Function const fn) {
 
     return (isDyadicMaskFunction(fn) || fn == FN_NOT);
 }
@@ -211,7 +216,7 @@ isMaskFunction(enum function const fn) {
 
 
 static bool
-isShiftFunction(enum function const fn) {
+isShiftFunction(enum Function const fn) {
 
     return (fn == FN_SHIFTLEFT || fn == FN_SHIFTRIGHT);
 }
@@ -219,7 +224,7 @@ isShiftFunction(enum function const fn) {
 
 
 static bool
-isBitstringFunction(enum function const fn) {
+isBitstringFunction(enum Function const fn) {
 
     return isMaskFunction(fn) || isShiftFunction(fn);
 }
@@ -227,7 +232,7 @@ isBitstringFunction(enum function const fn) {
 
 
 static void
-validateFunction(struct cmdlineInfo const cmdline,
+validateFunction(struct CmdlineInfo const cmdline,
                  const struct pam * const pamP) {
 
     if (isBitstringFunction(cmdline.function)) {
@@ -259,7 +264,58 @@ validateFunction(struct cmdlineInfo const cmdline,
 
 
 static void
-applyFunction(struct cmdlineInfo const cmdline,
+planTransform(struct CmdlineInfo const cmdline,
+              sample             const inputMaxval,
+              sample *           const outputMaxvalP,
+              bool *             const mustChangeRasterP) {
+/*----------------------------------------------------------------------------
+   Plan the transform described by 'cmdline', given the maxval of the input
+   image is 'inputMaxval.
+
+   The plan just consists of whether to change the maxval or the raster.
+   Some multiplications and divisions can be achieved just by changing the
+   maxval and leaving the samples in the raster alone.
+-----------------------------------------------------------------------------*/
+    if (cmdline.changemaxval) {
+        /* User allows us to change the maxval, if that makes it easier */
+        if (cmdline.function == FN_MULTIPLY || cmdline.function == FN_DIVIDE) {
+            float const multiplier =
+                cmdline.function == FN_MULTIPLY ? cmdline.u.multiplier :
+                (1/cmdline.u.divisor);
+
+            float const neededMaxval = inputMaxval / multiplier;
+
+            if (neededMaxval + 0.5 < inputMaxval) {
+                /* Lowering the maxval might make some of the sample values
+                   higher than the maxval, so we'd have to modify the raster
+                   to clip them.
+                */
+                *outputMaxvalP     = inputMaxval;
+                *mustChangeRasterP = true;
+            } else if (neededMaxval > PAM_OVERALL_MAXVAL) {
+                *outputMaxvalP     = inputMaxval;
+                *mustChangeRasterP = true;
+            } else {
+                *outputMaxvalP     = ROUNDU(neededMaxval);
+                *mustChangeRasterP = false;
+            }
+        } else {
+            *outputMaxvalP     = inputMaxval;
+            *mustChangeRasterP = true;
+        }
+    } else {
+        *outputMaxvalP     = inputMaxval;
+        *mustChangeRasterP = true;
+    }
+    if (*outputMaxvalP != inputMaxval)
+        pm_message("Changing maxval to %u because of -changemaxval",
+                   (unsigned)*outputMaxvalP);
+}
+
+
+
+static void
+applyFunction(struct CmdlineInfo const cmdline,
               struct pam         const inpam,
               struct pam         const outpam,
               tuple *            const inputRow,
@@ -275,10 +331,10 @@ applyFunction(struct cmdlineInfo const cmdline,
            divide, both cmdline.u.divisor and oneOverDivisor are
            meaningless.  
         */
-    int col;
+    unsigned int col;
 
     for (col = 0; col < inpam.width; ++col) {
-        int plane;
+        unsigned int plane;
         for (plane = 0; plane < inpam.depth; ++plane) {
             sample const inSample = inputRow[col][plane];
             sample outSample;  /* Could be > maxval  */
@@ -330,21 +386,22 @@ applyFunction(struct cmdlineInfo const cmdline,
 
 
 int
-main(int argc, char *argv[]) {
+main(int argc, const char *argv[]) {
 
     FILE * ifP;
     tuple * inputRow;   /* Row from input image */
     tuple * outputRow;  /* Row of output image */
-    int row;
-    struct cmdlineInfo cmdline;
+    unsigned int row;
+    struct CmdlineInfo cmdline;
     struct pam inpam;   /* Input PAM image */
     struct pam outpam;  /* Output PAM image */
+    bool mustChangeRaster;
 
-    pnm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
-    ifP = pm_openr(cmdline.inputFilespec);
+    ifP = pm_openr(cmdline.inputFileName);
 
     pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
 
@@ -355,16 +412,21 @@ main(int argc, char *argv[]) {
     outpam = inpam;    /* Initial value -- most fields should be same */
     outpam.file = stdout;
 
+    planTransform(cmdline, inpam.maxval, &outpam.maxval, &mustChangeRaster);
+
     pnm_writepaminit(&outpam);
 
     outputRow = pnm_allocpamrow(&outpam);
 
-    for (row = 0; row < inpam.height; row++) {
+    for (row = 0; row < inpam.height; ++row) {
         pnm_readpamrow(&inpam, inputRow);
 
-        applyFunction(cmdline, inpam, outpam, inputRow, outputRow);
+        if (mustChangeRaster) {
+            applyFunction(cmdline, inpam, outpam, inputRow, outputRow);
 
-        pnm_writepamrow(&outpam, outputRow);
+            pnm_writepamrow(&outpam, outputRow);
+        } else
+            pnm_writepamrow(&outpam, inputRow);
     }
     pnm_freepamrow(outputRow);
     pnm_freepamrow(inputRow);
@@ -374,3 +436,5 @@ main(int argc, char *argv[]) {
     return 0;
 }
 
+
+
diff --git a/editor/pnmshear.c b/editor/pnmshear.c
index 657f265d..99fa3026 100644
--- a/editor/pnmshear.c
+++ b/editor/pnmshear.c
@@ -1,4 +1,4 @@
-/* pnmshear.c - read a portable anymap and shear it by some angle
+ /* pnmshear.c - read a portable anymap and shear it by some angle
 **
 ** Copyright (C) 1989, 1991 by Jef Poskanzer.
 **
@@ -17,6 +17,7 @@
 #include <string.h>
 
 #include "pm_c_util.h"
+#include "mallocvar.h"
 #include "ppm.h"
 #include "pnm.h"
 #include "shhopt.h"
@@ -24,11 +25,13 @@
 #define SCALE 4096
 #define HALFSCALE 2048
 
-struct cmdline_info {
+
+
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    const char *       input_filespec;  /* Filespec of input file */
+    const char * inputFileName;   /* Name of input file */
     double       angle;           /* requested shear angle, in radians */
     unsigned int noantialias;     /* -noantialias option */
     const char * background;      /* NULL if none */
@@ -37,15 +40,17 @@ struct cmdline_info {
 
 
 static void
-parseCommandLine(int argc, char ** argv,
-                 struct cmdline_info *cmdlineP) {
+parseCommandLine(int argc, const char ** argv,
+                 struct CmdlineInfo *cmdlineP) {
 
     optStruct3 opt;
     unsigned int option_def_index = 0;
-    optEntry *option_def = malloc(100*sizeof(optEntry));
+    optEntry * option_def;
 
     unsigned int backgroundSpec;
 
+    MALLOCARRAY(option_def, 100);
+
     OPTENT3(0, "noantialias",      OPT_FLAG,  NULL, &cmdlineP->noantialias, 0);
     OPTENT3(0, "background",       OPT_STRING, &cmdlineP->background,
             &backgroundSpec, 0);
@@ -54,7 +59,7 @@ parseCommandLine(int argc, char ** argv,
     opt.short_allowed = FALSE;
     opt.allowNegNum = TRUE;
 
-    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
 
     if (!backgroundSpec)
         cmdlineP->background = NULL;
@@ -68,15 +73,16 @@ parseCommandLine(int argc, char ** argv,
             pm_error("Angle argument is not a valid floating point number: "
                      "'%s'", argv[1]);
         if (argc-1 < 2)
-            cmdlineP->input_filespec = "-";
+            cmdlineP->inputFileName = "-";
         else {
-            cmdlineP->input_filespec = argv[2];
+            cmdlineP->inputFileName = argv[2];
             if (argc-1 > 2)
                 pm_error("too many arguments (%d).  "
                          "The only arguments are shear angle and filespec.",
                          argc-1);
         }
     }
+    free(option_def);
 }
 
 
@@ -200,7 +206,7 @@ backgroundColor(const char * const backgroundColorName,
 
 
 int
-main(int argc, char * argv[]) {
+main(int argc, const char * argv[]) {
 
     FILE * ifP;
     xel * xelrow;
@@ -212,13 +218,13 @@ main(int argc, char * argv[]) {
     xelval maxval, newmaxval;
     double shearfac;
 
-    struct cmdline_info cmdline;
+    struct CmdlineInfo cmdline;
 
-    pnm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
-    ifP = pm_openr(cmdline.input_filespec);
+    ifP = pm_openr(cmdline.inputFileName);
 
     pnm_readpnminit(ifP, &cols, &rows, &maxval, &format);
     xelrow = pnm_allocrow(cols);
@@ -256,7 +262,7 @@ main(int argc, char * argv[]) {
             shearCols = (rows - row) * shearfac;
 
         shearRow(xelrow, cols, newxelrow, newcols, 
-                  shearCols, format, bgxel, !cmdline.noantialias);
+                 shearCols, format, bgxel, !cmdline.noantialias);
 
         pnm_writepnmrow(stdout, newxelrow, newcols, newmaxval, newformat, 0);
     }
@@ -266,3 +272,6 @@ main(int argc, char * argv[]) {
 
     return 0;
 }
+
+
+
diff --git a/generator/pamgauss.c b/generator/pamgauss.c
index 13fe8ea1..82c340fa 100644
--- a/generator/pamgauss.c
+++ b/generator/pamgauss.c
@@ -11,7 +11,7 @@
 
 
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -25,8 +25,8 @@ struct cmdlineInfo {
 
 
 static void
-parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo * const cmdlineP) {
+parseCommandLine(int argc, const char ** argv,
+                 struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
   Convert program invocation arguments (argc,argv) into a format the 
   program can use easily, struct cmdlineInfo.  Validate arguments along
@@ -57,7 +57,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 *cmdlineP and others. */
 
     if (!tupletypeSpec)
@@ -101,6 +101,7 @@ parseCommandLine(int argc, char ** argv,
             pm_error("height argument must be a positive number.  You "
                      "specified '%s'", argv[2]);
     }
+    free(option_def);
 }
 
 
@@ -159,15 +160,15 @@ imageNormalizer(struct pam * const pamP,
 
 
 int
-main(int argc, char **argv) {
+main(int argc, const char **argv) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     struct pam pam;
     int row;
     double normalizer;
     tuplen * tuplerown;
     
-    pnm_init(&argc, argv);
+    pm_proginit(&argc, argv);
    
     parseCommandLine(argc, argv, &cmdline);
 
diff --git a/generator/pgmkernel.c b/generator/pgmkernel.c
index b741d596..4f40f003 100644
--- a/generator/pgmkernel.c
+++ b/generator/pgmkernel.c
@@ -1,8 +1,8 @@
-/* pgmkernel.c - generate a portable graymap convolution kernel
+/* pgmkernel.c - generate a PGM convolution kernel
 **
-** Creates a Portable Graymap file containing a convolution filter
-** with max value = 255 and minimum value > 127 that can be used as a 
-** smoothing kernel for pnmconvol.
+** Creates a PGM image containing a convolution filter with max value = 255
+** and minimum value > 127 that can be used as a smoothing kernel for
+** pnmconvol.
 **
 ** Copyright (C) 1992 by Alberto Accomazzi, Smithsonian Astrophysical
 ** Observatory.
@@ -16,76 +16,224 @@
 */
 
 #include <math.h>
-#include "pgm.h"
+#include "pm_c_util.h"
+#include "shhopt.h"
 #include "mallocvar.h"
+#include "pgm.h"
 
-int
-main ( argc, argv )
-    int argc;
-    char *argv[];
-{
-    register    int i, j;
-    int     argn = 1, ixsize, iysize, maxval = 255;
-    double  fxsize = 0.0, fysize = 0.0, w = 6.0, kxcenter, kycenter, 
-        tmax = 0, *fkernel;
-    const char  *usage = "[-weight f] width [height]";
-
-    pgm_init( &argc, argv );
-
-    while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
-    {
-        if ( pm_keymatch( argv[argn], "-weight", 2 )) {
-            if (++argn >= argc)
-                pm_usage( usage );
-            else if (sscanf(argv[argn], "%lf", &w) != 1)
-                pm_usage( usage );
-        }
-        else
-            pm_usage( usage );
-        argn++;
-    }
 
-    if (argn == argc)
-        pm_usage( usage );
-    
-    if (sscanf(argv[argn], "%lf", &fxsize) != 1) 
-        pm_error( "error reading input kernel x size, (%s)\n", argv[argn]);
 
-    ++argn;
-    if (argn == argc - 1) {
-        if (sscanf(argv[argn], "%lf", &fysize) != 1)
-            pm_error( "error reading input kernel y size, (%s)\n", argv[argn]);
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    unsigned int cols;
+    unsigned int rows;
+    float weight;
+    gray maxval;
+};
+
+
+
+static void
+parseCommandLine(int argc, const char ** argv,
+                 struct CmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+  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 
+  argv[] points to.
+-----------------------------------------------------------------------------*/
+    optEntry *option_def;
+        /* Instructions to OptParseOptions2 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int weightSpec, maxvalSpec;
+    unsigned int option_def_index;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0,   "weight",  OPT_FLOAT, &cmdlineP->weight, 
+            &weightSpec,     0);
+    OPTENT3(0,   "maxval",  OPT_UINT, &cmdlineP->maxval, 
+            &maxvalSpec,     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 (!weightSpec)
+        cmdlineP->weight = 6.0;
+
+    if (cmdlineP->weight < 0.0)
+        pm_error("-weight cannot be negative.  You specified %f",
+                 cmdlineP->weight);
+
+    if (!maxvalSpec)
+        cmdlineP->maxval = PGM_MAXMAXVAL;
+
+    if (cmdlineP->maxval > PGM_OVERALLMAXVAL)
+        pm_error("-maxval is too large: %u.  Maximum is %u",
+                 cmdlineP->maxval, PGM_OVERALLMAXVAL);
+
+    if (cmdlineP->maxval == 0)
+        pm_error("-maxval cannot be zero");
+
+    if (argc-1 < 1)
+        pm_error("Need at least one argument: size of (square) kernel");
+    else if (argc-1 == 1) {
+        if (atoi(argv[1]) <= 0)
+            pm_error("Dimension must be a positive number.  "
+                     "You specified '%s'", argv[1]);
+        cmdlineP->cols = atoi(argv[1]);
+        cmdlineP->rows = atoi(argv[1]);
+    } else if (argc-1 == 2) {
+        if (atoi(argv[1]) <= 0)
+            pm_error("Width must be a positive number.  "
+                     "You specified '%s'", argv[1]);
+        if (atoi(argv[2]) <= 0)
+            pm_error("Height must be a positive number.  "
+                     "You specified '%s'", argv[2]);
+        cmdlineP->cols = atoi(argv[1]);
+        cmdlineP->rows = atoi(argv[2]);
+    } else
+        pm_error("At most two arguments allowed.  "
+                 "You specified %u", argc-1);
+}
+
+
+
+static double
+t(double const dx2,
+  double const dy2,
+  double const weight) {
+/*----------------------------------------------------------------------------
+  The t value for a pixel that is (dx, dy) pixels away from the center of
+  the kernel, where 'dx2' is SQR(dx) and 'dy2' is SQR(dy), if the distance is
+  weighted by 'weight'.
+-----------------------------------------------------------------------------*/
+
+    return 1.0 / (1.0 + weight * sqrt(dx2 + dy2));
+}
+
+
+
+static double
+tMaxAllKernel(unsigned int const cols,
+              unsigned int const rows,
+              double       const weight) {
+/*----------------------------------------------------------------------------
+   The maximum t value over all pixels in the kernel, if the kernel is
+   'cols' by 'rows' pixels and distance is weighted by 'weight'.
+-----------------------------------------------------------------------------*/
+
+    /* It depends upon whether there is an even or odd number of rows
+       and columns.  If both dimensions are odd, there is a pixel right
+       at the center, and it has the greatest t value.  If both dimensions
+       are even, the center of the image is in the center of a 4-pixel
+       square and each of those 4 pixels has the greatest t value.  If
+       one dimension is even and the other odd, the center of the kernel
+       is midway between two pixels, horizontally or vertically, and one
+       of those two pixels has the greatest t value.
+    */
+
+    double dxMax, dyMax;
+
+    switch (cols % 2 + rows % 2) {
+    case 0:
+        dxMax = 0.5;
+        dyMax = 0.5;
+        break;
+    case 1:
+        dxMax = 0.5;
+        dyMax = 0.0;
+        break;
+    case 2:
+        dxMax = 0.0;
+        dyMax = 0.0;
     }
-    else if (argn == argc)
-        fysize = fxsize;
-    else
-        pm_usage( usage );
-
-    if (fxsize <= 1 || fysize <= 1)
-        pm_usage( usage );
-
-    kxcenter = (fxsize - 1) / 2.0;
-    kycenter = (fysize - 1) / 2.0;
-    ixsize = fxsize + 0.999;
-    iysize = fysize + 0.999;
-    MALLOCARRAY(fkernel, ixsize * iysize);
-    for (i = 0; i < iysize; i++) 
-        for (j = 0; j < ixsize; j++) {
-            fkernel[i*ixsize+j] = 1.0 / (1.0 + w * sqrt((double)
-                                                        (i-kycenter)*(i-kycenter)+
-                                                        (j-kxcenter)*(j-kxcenter)));
-            if (tmax < fkernel[i*ixsize+j])
-                tmax = fkernel[i*ixsize+j];
-        }
 
-    /* output PGM header + data (ASCII format only) */
-    printf("P2\n%d %d\n%d\n", ixsize, iysize, maxval);
+    return t(SQR(dxMax), SQR(dyMax), weight);
+}
+
+
+
+static void
+writeKernel(FILE *       const ofP,
+            unsigned int const cols,
+            unsigned int const rows,
+            gray         const maxval,
+            gray **      const halfKernel,
+            unsigned int const halfRows) {
+
+    unsigned int row;
     
-    for (i = 0; i < iysize; i++, printf("\n"))
-        for (j = 0; j < ixsize; j++)
-            printf(" %3d", (int)(maxval * (fkernel[i*ixsize+j] / 
-                                           (2*tmax) + 0.5)));
+    pgm_writepgminit(stdout, cols, rows, maxval, 0);
+
+    for (row = 0; row < halfRows; ++row)
+        pgm_writepgmrow(stdout, halfKernel[row], cols, maxval, 0);
+
+    /* Now write out the same rows in reverse order. */
     
-    exit(0);
+    for (; row < rows; ++row)
+        pgm_writepgmrow(stdout, halfKernel[rows-1-row], cols, maxval, 0);
 }
 
+
+
+int
+main(int argc, const char * argv[]) {
+
+    struct CmdlineInfo cmdline;
+    unsigned int arows;
+    int arow;
+    double xcenter, ycenter;
+        /* row, column "number" of center of kernel */
+    double tMax;
+        /* The maximum t value over all pixels */
+    gray ** destarray;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    xcenter = ((double) cmdline.cols - 1) / 2.0;
+    ycenter = ((double) cmdline.rows - 1) / 2.0;
+
+    tMax = tMaxAllKernel(cmdline.cols, cmdline.rows, cmdline.weight);
+
+    /* Output matrix is symmetric vertically and horizontally. */
+
+    arows = (cmdline.rows + 1) / 2;
+        /* Half the number of rows.  Add 1 if odd. */
+    destarray = pgm_allocarray(cmdline.cols, arows);
+
+    for (arow = 0; arow < arows; ++arow) {
+        double const dy2 = SQR(arow - ycenter);
+
+        unsigned int col;
+
+        for (col = 0; col < cmdline.cols; ++col) {
+            double const dx2 = SQR(col - xcenter);
+
+            double const normalized = t(dx2, dy2, cmdline.weight) / 2 / tMax;
+
+            destarray[arow][col] = destarray[arow][cmdline.cols - col - 1] =
+                ROUNDU(cmdline.maxval * (0.5 + normalized));
+        }
+    }
+
+    writeKernel(stdout, cmdline.cols, cmdline.rows, cmdline.maxval,
+                destarray, arows);
+
+    pgm_freearray(destarray, arows);
+
+    return 0;
+}
diff --git a/lib/Makefile b/lib/Makefile
index 8d9b3175..6512949f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -84,13 +84,12 @@ extra_staticlib: $(EXTRA_STATICLIB)
 # type, but request a static library in addition.
 #----------------------------------------------------------------------------
 
-# Note that the user may have configured -I options into CPPFLAGS/CFLAGS.
-CFLAGS_ALL = $(INCLUDES) -DNDEBUG $(CPPFLAGS) $(CFLAGS) $(CFLAGS_SHLIB) \
- $(CFLAGS_PERSONAL) $(CADD)
+$(LIBOBJECTS): CFLAGS_TARGET=$(CFLAGS_SHLIB)
+
+libpbm3.o: CFLAGS_TARGET+=$(CFLAGS_SSE)
 
 $(LIBOBJECTS): %.o: %.c importinc
-# We have to get the command all on one line to avoid messy make messages
-	$(CC) -c $(CFLAGS_ALL) -o $@ $<
+	$(CC) -c $(INCLUDES) $(CFLAGS_ALL) -o $@ $<
 
 MAJ = 11
 MIN = $(NETPBM_MINOR_RELEASE)
diff --git a/lib/libpbm3.c b/lib/libpbm3.c
index d6a953c2..020e1558 100644
--- a/lib/libpbm3.c
+++ b/lib/libpbm3.c
@@ -16,21 +16,28 @@
 #include "pbm.h"
 
 #ifndef PACKBITS_SSE
-#if HAVE_GCC_SSE2 && HAVE_GCC_BSWAP && defined(__SSE2__)
+#if WANT_SSE && defined(__SSE2__) && HAVE_GCC_BSWAP
   #define PACKBITS_SSE 2
 #else
   #define PACKBITS_SSE 0
 #endif
 #endif
 
-/* HAVE_GCC_SSE2 means we have the means to use SSE CPU facilities
-   to make PBM raster processing faster.  GCC only.
+/* WANT_SSE means we want to use SSE CPU facilities to make PBM raster
+   processing faster.  This implies it's actually possible - i.e. the
+   build environment has <emmintrin.h>.
 
-   The GNU Compiler -msse2 option makes SSE/SSE2 available.
-   For x86-32 with MMX/SSE, "-msse2" must be explicitly given.
+   The GNU Compiler -msse2 option makes SSE/SSE2 available, and is
+   evidenced by __SSE2__.
+   For x86-32 with SSE, "-msse2" must be explicitly given.
    For x86-64 and AMD64, "-msse2" is the default (from Gcc v.4.)
 */
 
+#if PACKBITS_SSE == 2
+  #include <emmintrin.h>
+#endif
+
+
 void
 pbm_writepbminit(FILE * const fileP, 
                  int    const cols, 
@@ -81,16 +88,28 @@ packBitsWithSse2(  FILE *          const fileP,
       PCMPGTB128  Packed CoMPare Greater Than Byte
     
         Compares 16 bytes in parallel
-        Result is x00 if greater than, xFF if not for each byte       
+        Result is x00 if greater than, xFF if not for each byte
+
     
       PMOVMSKB128 Packed MOVe MaSK Byte 
     
-        Result is a byte of the MSBs of 16 bytes
+        Result is 16 bits, the MSBs of 16 bytes
         x00 xFF x00 xFF xFF xFF x00 x00 xFF xFF xFF xFF x00 x00 x00 x00 
         --> 0101110011110000B = 0x5CF0
         
         The result is actually a 64 bit int, but the higher bits are
         always 0.
+
+      We use SSE instructions in "_mm_" form in favor of "__builtin_".
+      In GCC the "__builtin_" form is documented but "_mm_" is not.
+      Former versions of this source file used "__builtin_".  This was
+      changed to make possible compilation with clang, which does not
+      implement some "__builtin_" forms.
+
+      __builtin_ia32_pcmpgtb128 :  _mm_cmpgt_epi8
+      __builtin_ia32_pmovmskb128 : _mm_movemask_epi8
+
+      The conversion requires <emmintrin.h> .
     */
 
     typedef char v16qi __attribute__ ((vector_size(16)));
@@ -110,11 +129,10 @@ packBitsWithSse2(  FILE *          const fileP,
         bit128.i64[1]=__builtin_bswap64( *(uint64_t*) &bitrow[col+8]);
 
         {
-            v16qi const compare =
-                __builtin_ia32_pcmpgtb128(bit128.v16, zero128);
-            uint16_t const blackMask = 
-                (uint16_t) __builtin_ia32_pmovmskb128(compare);
-
+            v16qi const compare = (v16qi)
+                _mm_cmpgt_epi8((__m128i)bit128.v16, (__m128i) zero128);
+            uint16_t const blackMask = _mm_movemask_epi8 ((__m128i)compare);
+            
             *(uint16_t *) & packedBits[col/8] = blackMask;
         }
     }
@@ -128,10 +146,9 @@ packBitsWithSse2(  FILE *          const fileP,
             bit128.byte[ (i&8) + 7-(i&7) ] = bitrow[j];
       
         {
-            v16qi const compare =
-                __builtin_ia32_pcmpgtb128( bit128.v16, zero128 );
-            uint16_t const blackMask =
-                __builtin_ia32_pmovmskb128( compare );
+            v16qi const compare = (v16qi)
+                _mm_cmpgt_epi8((__m128i)bit128.v16, (__m128i) zero128);
+            uint16_t const blackMask = _mm_movemask_epi8 ((__m128i)compare);
 
             if ( cols%16 >8 )  /* Two partial bytes */
                 *(uint16_t *) & packedBits[col/8] = blackMask;
diff --git a/lib/libsystem.c b/lib/libsystem.c
index 8db663bc..48c6f06d 100644
--- a/lib/libsystem.c
+++ b/lib/libsystem.c
@@ -13,6 +13,7 @@
    Contributed to the public domain.
 =============================================================================*/
 #define _XOPEN_SOURCE
+#define _BSD_SOURCE  /* Make SIGWINCH defined on OpenBSD */
 
 #include <stdarg.h>
 #include <unistd.h>
@@ -220,6 +221,18 @@ spawnProcessor(const char *  const progName,
 static const char *
 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
+   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
+   it would take to do it right.
+
+   OpenBSD does not have SIGWINCH and SIGIO in 2013.  Everyone else seems
+   to have it.
+*/
     switch (signalClass) {
     case SIGHUP: /* POSIX.1 */
         return "SIGHUP";
@@ -273,12 +286,6 @@ signalName(unsigned int const signalClass) {
         return "SIGVTALRM";
     case SIGPROF:
         return "SIGPROF";
-/* Most systems have SIGWINCH and SIGIO, but at least OpenBSD, in 2013,
-   does not.  Systems that do don't necessarily supply it as a macro, so
-   the following tests are not perfect, but a false negative is a really,
-   really, small problem, so we don't bother with all the work it would
-   take to do better.
-*/
 #ifdef SIGWINCH
     case SIGWINCH:
         return "SIGWINCH";
@@ -287,16 +294,14 @@ signalName(unsigned int const signalClass) {
     case SIGIO:
         return "SIGIO";
 #endif
+#ifdef SIGPWR
+    case SIGPWR:
+        return "SIGPWR";
+#endif
     case SIGSYS:
         return "SIGSYS";
     default:
         return "???";
-
-        /* There are various other signal classes on some systems, but
-           not defined by POSIX and not on at least one system we
-           know of for which someone wanted to compile Netpbm.  The
-           list includes: SIGPWR, SIGLOST, SIGINFO, SIGRTxx.
-        */
     }
 }
 
diff --git a/lib/util/Makefile b/lib/util/Makefile
index 5bf1995e..28dfddfe 100644
--- a/lib/util/Makefile
+++ b/lib/util/Makefile
@@ -5,6 +5,8 @@ endif
 SUBDIR = lib/util
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
+default:all
+
 include $(BUILDDIR)/config.mk
 
 # nstring is required for asprintf(), etc.  Also some systems don't have
@@ -22,13 +24,14 @@ UTILOBJECTS = \
 
 MERGE_OBJECTS =
 
+include $(SRCDIR)/common.mk
+
 all: $(UTILOBJECTS)
 
-include $(SRCDIR)/common.mk
+$(UTILOBJECTS): CFLAGS_TARGET=$(CFLAGS_SHLIB)
 
 $(UTILOBJECTS):%.o:%.c importinc
-	$(CC) -c $(INCLUDES) -DNDEBUG $(CPPFLAGS) $(CFLAGS) $(CFLAGS_SHLIB) \
-	  $(CFLAGS_PERSONAL) $(CADD) -o $@ $<
+	$(CC) -c $(INCLUDES) $(CFLAGS_ALL) -o $@ $<
 
 testnstring: test.c nstring.h nstring.o
-	$(CC) $(CFLAGS) $(CADD) -o $@ nstring.o $<
+	$(CC) $(CFLAGS_ALL) -o $@ nstring.o $<
diff --git a/lib/util/nstring.c b/lib/util/nstring.c
index e95d9824..bb2ba92e 100644
--- a/lib/util/nstring.c
+++ b/lib/util/nstring.c
@@ -134,12 +134,6 @@
 
 #include "nstring.h"
 
-#if (defined(__GLIBC__) || defined(__GNU_LIBRARY__))
-  #define HAVE_VASPRINTF 1
-#else
-  #define HAVE_VASPRINTF 0
-#endif
-
 #ifdef isdigit
 #undef isdigit
 #endif
@@ -797,9 +791,12 @@ pm_asprintf(const char ** const resultP,
     va_list varargs;
     
 #if HAVE_VASPRINTF
+    int rc;
     va_start(varargs, fmt);
-    vasprintf((char **)&result, fmt, varargs);
+    rc = vasprintf((char **)&result, fmt, varargs);
     va_end(varargs);
+    if (rc < 0)
+        result = pm_strsol;
 #else
     size_t dryRunLen;
     
@@ -811,20 +808,23 @@ pm_asprintf(const char ** const resultP,
 
     if (dryRunLen + 1 < dryRunLen)
         /* arithmetic overflow */
-        result = NULL;
+        result = pm_strsol;
     else {
         size_t const allocSize = dryRunLen + 1;
-        result = malloc(allocSize);
-        if (result != NULL) {
+        char * buffer;
+        buffer = malloc(allocSize);
+        if (buffer != NULL) {
             va_list varargs;
             size_t realLen;
 
             va_start(varargs, fmt);
 
-            pm_vsnprintf(result, allocSize, fmt, varargs, &realLen);
+            pm_vsnprintf(buffer, allocSize, fmt, varargs, &realLen);
                 
             assert(realLen == dryRunLen);
             va_end(varargs);
+
+            result = buffer;
         }
     }
 #endif
diff --git a/lib/util/pm_c_util.h b/lib/util/pm_c_util.h
index 79897cf0..01a07657 100644
--- a/lib/util/pm_c_util.h
+++ b/lib/util/pm_c_util.h
@@ -83,7 +83,7 @@
   #define TRUE true
   #endif
 #ifndef FALSE
-#define FALSE false
+  #define FALSE false
   #endif
 
 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
diff --git a/lib/util/vasprintf.c b/lib/util/vasprintf.c
index 209827eb..e38252fa 100644
--- a/lib/util/vasprintf.c
+++ b/lib/util/vasprintf.c
@@ -18,9 +18,11 @@ pm_vasprintf(const char ** const resultP,
     char * result;
 
 #if HAVE_VASPRINTF
-    vasprintf(&result, format, varargs);
+    int rc;
 
-    if (result == NULL)
+    rc = vasprintf(&result, format, varargs);
+
+    if (rc < 0)
         *resultP = pm_strsol;
     else
         *resultP = result;
diff --git a/other/pamarith.c b/other/pamarith.c
index a53029da..b64f69fb 100644
--- a/other/pamarith.c
+++ b/other/pamarith.c
@@ -47,7 +47,7 @@ isDyadic(enum function const function) {
 
 
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -60,7 +60,7 @@ struct cmdlineInfo {
 
 static void
 parseCommandLine(int argc, const char ** const 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.
@@ -796,7 +796,7 @@ doUnNormalizedArith(struct pam *  const inpam1P,
 int
 main(int argc, const char *argv[]) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     struct pam inpam1;
     struct pam inpam2;
     struct pam outpam;
diff --git a/pm_config.in.h b/pm_config.in.h
index 9459be02..fd651e3a 100644
--- a/pm_config.in.h
+++ b/pm_config.in.h
@@ -187,22 +187,14 @@
 /* CONFIGURE: GNU Compiler extensions are used in performance critical places
    when available.  Test whether they exist.
 
-   Turn off by defining NO_GCC_BUILTINS.
-
-   Note that though these influence the resulting Netpbm machine code, the
-   compiler setting ultimately decides what instruction set the compiler uses.
-   If you want a generic build, check the manual and adjust CFLAGS in
-   config.mk accordingly.
-
-   For example, if you want binaries that run on all Intel x86-32
-   family CPUs back to 80386, adding "-march=i386" to CFLAGS in
-   config.mk is much better than setting NO_GCC_BUILTINS to 1.
-   If you want to be extra sure use:
-   "-march=i386 -mno-mmx -mno-sse -DNO_GCC_BUILTINS"
-
-   Gcc uses SSE and SSE2 instructions by default for AMD/Intel x86-64.
-   Tinkering with "-mno-sse" is not recommended for these machines.  If you
-   don't want SSE code, set NO_GCC_BUILTINS to 1.
+   Prevent the build from exploiting these extensions by defining
+   NO_GCC_UNIQUE.
+
+   Before Netpbm 10.65 (December 2013), Netpbm used GCC compiler extensions
+   to generate SSE code in Pamflip.  Starting in 10.65, Netpbm instead uses
+   the more standard operators defined in <emmtrins.h>.  To prevent Netpbm
+   from explicitly using any SSE instructions, set WANT_SSE to N in
+   config.mk.
 */
 
 /*
@@ -214,7 +206,7 @@
    > cc --version
      Apple clang version 4.0 (tags/Apple/clang-421.0.60) (based on LLVM 3.1svn)
 
-   which masquerades as GCC 4.2.1, but it does not have SSE2 function
+   which masquerades as GCC 4.2.1, but it does not have SSE2 operator
    __builtin_ia32_pcmpeqb128 .
 
   On the other hand, research by Prophet of the Way in September 2012
@@ -222,18 +214,24 @@
   compiled successfully with SSE exploitation), but 3.1 does not.  He did
   not find any mention in documentation of that change.
 
+  At least some versions of Clang that do not have __builtin_ia32_pcmpeqb128
+  nonetheless have other GCC SSE2 operators, such as __builtin_ia32_pcmpgtb128.
+  We did not detect a pattern.
+
   See below on compilers other than GCC that set __GNUC__:
   http://sourceforge.net/apps/mediawiki/predef/index.php?title=Compilers
 */
-#if defined(__GNUC__) && !defined(__clang__) && !defined(NO_GCC_BUILTINS)
+#if defined(__GNUC__) && !defined(__clang__) && !defined(NO_GCC_UNIQUE)
   #define GCCVERSION __GNUC__*100 + __GNUC_MINOR__
 #else
   #define GCCVERSION 0
 #endif
 
-/* HAVE_GCC_SSE2 means the compiler has GCC builtins to directly access
-   SSE/SSE2 features.  This is different from whether the compiler generates
-   code that uses these features at all.
+/* HAVE_GCC_SSE2 means the compiler has all of the GCC-specific builtins to
+   directly access SSE/SSE2 features.  This is different from whether the
+   compiler generates code that uses these features at all.  It is also
+   different from whether the compiler has the more standard operators defined
+   in <emmintrins.h>.
 */
 
 #ifndef HAVE_GCC_SSE2
@@ -260,10 +258,9 @@
 #endif
 
 #ifndef HAVE_GCC_BSWAP
-#if GCCVERSION >=403
+#if GCCVERSION >=403 || defined(__clang__)
   #define HAVE_GCC_BSWAP 1
   /* Use __builtin_bswap32(), __builtin_bswap64() for endian conversion.
-     Available from GCC v 4.3 onward.
      NOTE: On intel CPUs this may produce the bswap operand which is not
      available on 80386. */
 #else
diff --git a/test/Execute-Tests b/test/Execute-Tests
index 047cf4a3..7a1a3793 100755
--- a/test/Execute-Tests
+++ b/test/Execute-Tests
@@ -39,17 +39,10 @@ fi
 # export PBM_BINPREFIX=""
 export PBM_BINPREFIX=${PBM_TESTPREFIX}
 
-# Add PBM_BINPREFIX to PATH.
-# This is necessary for Netpbm programs (mosly scripts) that call
-# other Netpbm programs.
-
-if [ ! -z $PBM_BINPREFIX ]
-  then
-  export PATH=${PBM_BINPREFIX}:$PATH
-fi
-
-# Set srcdir, which is the directory which contains Execute-Tests
-# (this script), Test-Order *.test and *.ok files.
+# Set srcdir, which is the directory which contains Execute-Tests (this
+# script), programs that run the test, including *.test and helpers that they
+# invoke, the list of tests to run ('Test-Order'), and *.ok files that
+# indicate the expected results of tests.
 
 srcdir=$(dirname $0)
 
@@ -101,6 +94,16 @@ if [ ! -f ./testimg.ppm ]
   then cp -v ${srcdir}/testimg.ppm  ./testimg.ppm 
 fi
 
+# Add PBM_BINPREFIX to PATH.
+# This is necessary for Netpbm programs that call other Netpbm programs.
+
+if [ ! -z $PBM_BINPREFIX ]
+  then
+  export PATH=${PBM_BINPREFIX}:$PATH
+fi
+
+export PATH=${srcdir}:$PATH
+
 # Execute the tests, as described in the "Test-Order" file.
 #
 # Each test outputs a ".out" file, which is compared against a
diff --git a/test/Makefile b/test/Makefile
new file mode 100644
index 00000000..4d44285f
--- /dev/null
+++ b/test/Makefile
@@ -0,0 +1,24 @@
+ifeq ($(SRCDIR)x,x)
+  SRCDIR = $(CURDIR)/..
+  BUILDDIR = $(SRCDIR)
+endif
+SUBDIR = test
+VPATH = .:$(SRCDIR)/$(SUBDIR)
+include $(BUILDDIR)/config.mk
+
+MERGE_OBJECTS =
+
+PROGS = testrandom
+
+all: $(PROGS)
+
+PORTBINARIES = testrandom
+OBJECTS = $(PORTBINARIES:%=%.o)
+
+OMIT_TEST_RULE = 1
+include $(SRCDIR)/common.mk
+
+distclean clean: cleanlocal
+.PHONY: cleanlocal
+cleanlocal:
+	rm -f $(PROGS)
diff --git a/test/Test-Order b/test/Test-Order
index 698552b9..31cd5324 100644
--- a/test/Test-Order
+++ b/test/Test-Order
@@ -63,6 +63,7 @@ ppmbrighten.test
 ppmdither.test
 pamedge.test
 ppmdim.test
+pnmshear.test
 
 ppmmix.test
 
@@ -109,6 +110,7 @@ mrf-roundtrip.test
 pfm-roundtrip.test
 png-roundtrip.test
 ps-roundtrip.test
+ps-alt-roundtrip.test
 sunrast-roundtrip.test
 targa-roundtrip.test
 tiff-roundtrip.test
diff --git a/test/pnmshear.ok b/test/pnmshear.ok
new file mode 100644
index 00000000..d701faaf
--- /dev/null
+++ b/test/pnmshear.ok
@@ -0,0 +1 @@
+2080980136 22
diff --git a/test/pnmshear.test b/test/pnmshear.test
new file mode 100644
index 00000000..276e3e22
--- /dev/null
+++ b/test/pnmshear.test
@@ -0,0 +1,19 @@
+#! /bin/bash
+# This script tests: pnmshear
+# Also requires: pbmmake
+
+# Test.  Should produce 2080980136 22
+${PBM_BINPREFIX}pbmmake -g 7 7 | \
+   ${PBM_TESTPREFIX}pnmshear 45 -noantialias  | cksum
+
+# Output of above, in pbm plain format
+#
+# P1
+# 14 7
+# 01010101111111
+# 10101011111111
+# 10101010111111
+# 11101010111111
+# 11101010101111
+# 11111010101111
+# 11111010101011
diff --git a/test/ps-alt-roundtrip.ok b/test/ps-alt-roundtrip.ok
new file mode 100644
index 00000000..1cd73f75
--- /dev/null
+++ b/test/ps-alt-roundtrip.ok
@@ -0,0 +1,3 @@
+2425386270 41
+2425386270 41
+2916080186 235
diff --git a/test/ps-alt-roundtrip.test b/test/ps-alt-roundtrip.test
new file mode 100755
index 00000000..8ce1689d
--- /dev/null
+++ b/test/ps-alt-roundtrip.test
@@ -0,0 +1,46 @@
+#! /bin/bash
+# This script tests: pbmtoepsi pbmtopsg3 pbmtolps psidtopgm pstopnm
+# Also requires: gs pnmtopnm pnmcrop
+
+# This script is for testing alternative (or minor) utilities that
+# read/write Postscript and encapsulated Postscript:
+# pbmtoepsi, pbmtopsg3, pbmtolps 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.
+#
+# If ps-roundtrip.test succeeds and this test fails, it is most likely
+# a problem with one of the minor utilities, and vice versa.
+
+
+# Test 1. Should print: 2425386270 41
+${PBM_TESTPREFIX}pbmtopsg3 -dpi=72 testgrid.pbm \
+     > ${tmpdir}/testgrid1.ps && \
+${PBM_TESTPREFIX}pstopnm -xborder=0 -yborder=0 -llx=0 -lly=-16 -urx=14 \
+    -dpi=72 -stdout -quiet -pbm ${tmpdir}/testgrid1.ps | \
+    ${PBM_BINPREFIX}pnmcrop | cksum
+
+
+# Test 2. Should print: 2425386270 41
+${PBM_TESTPREFIX}pbmtolps -dpi 72 testgrid.pbm \
+     > ${tmpdir}/testgrid2.ps && \
+${PBM_TESTPREFIX}pstopnm -xborder=0 -yborder=0 -dpi=72 -stdout \
+    -quiet ${tmpdir}/testgrid2.ps -pbm | \
+  ${PBM_BINPREFIX}pnmcrop | cksum
+
+
+# Test 3. Should print: 2916080186 235
+# Output is pgm maxval=1 with black and white inverted.
+#
+${PBM_TESTPREFIX}pbmtoepsi testgrid.pbm > ${tmpdir}/testgrid.epsi && \
+xysizebps=`awk  '/BeginPreview/ {print $2,$3,$4}' \
+    ${tmpdir}/testgrid.epsi` && \
+awk '/^%%BeginPreview:/ { p=1; next } /^%%EndImage/ { p=0; next } \
+  p==1 && /%[ \t0-9a-fA-F]+/ { print substr($0,2); next } \
+  p==1 {print "!"$0}' \
+    ${tmpdir}/testgrid.epsi | ${PBM_TESTPREFIX}psidtopgm $xysizebps | cksum
+
+
+rm ${tmpdir}/testgrid[12].ps  ${tmpdir}/testgrid.epsi 
diff --git a/test/ps-roundtrip.ok b/test/ps-roundtrip.ok
index a267f7eb..0ebfb94a 100644
--- a/test/ps-roundtrip.ok
+++ b/test/ps-roundtrip.ok
@@ -1,3 +1,15 @@
 1926073387 101484
-2425386270 41
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+2918318199 62
+2918318199 62
+2918318199 62
+2918318199 62
+2918318199 62
+2918318199 62
+2918318199 62
+1386192571 507420
+1386192571 507420
 1386192571 507420
diff --git a/test/ps-roundtrip.test b/test/ps-roundtrip.test
index 60ecf60a..b7aa816c 100755
--- a/test/ps-roundtrip.test
+++ b/test/ps-roundtrip.test
@@ -1,38 +1,70 @@
 #! /bin/bash
 # This script tests: pnmtops pstopnm
-# Also requires: pnmtopnm pamtopnm gs
+# Also requires: pnmtopnm pamtopnm gs pbmmake pnmshear pnmpad pnmcat
 
-# Test 1.  Should print: 1926073387 101484
-${PBM_TESTPREFIX}pnmtops -nocenter -equalpixels -dpi 72 -noturn testimg.ppm \
-  > ${tmpdir}/testimg.ps
-xysize1=`awk  '/BoundingBox/ {print "-xsize="$4,"-ysize="$5}' \
-  ${tmpdir}/testimg.ps` 
-${PBM_TESTPREFIX}pstopnm -xborder=0 -yborder=0 $xysize1 -stdout \
-  -quiet ${tmpdir}/testimg.ps | \
-  ${PBM_BINPREFIX}pnmtopnm | cksum
+# Test 1.  Should print: 1926073387 101484 five times
+# *NOTE* Fifth iteration fails if pnmtops was compiled without zlib
+# (flate compression) support.
+for flag in "" "-ps" "-rle" "-ps -ascii" "-ps -flate"
+  do
+  ${PBM_TESTPREFIX}pnmtops -nocenter -equalpixels -dpi 72 -noturn \
+    ${flag} testimg.ppm \
+    > ${tmpdir}/testimg.ps
+  xysize1=`awk  '/BoundingBox/ {print "-xsize="$4,"-ysize="$5}' \
+    ${tmpdir}/testimg.ps` 
+  ${PBM_TESTPREFIX}pstopnm -xborder=0 -yborder=0 $xysize1 -stdout \
+    -quiet ${tmpdir}/testimg.ps | \
+    ${PBM_BINPREFIX}pnmtopnm | cksum
+  done
 
 
-# Test 2.  Should print: 2425386270 41
-${PBM_TESTPREFIX}pnmtops -nocenter -equalpixels -dpi 72 -noturn \
-  testgrid.pbm  > ${tmpdir}/testgrid.ps &&
-xysize2=`awk  '/BoundingBox/ {print "-xsize="$4,"-ysize="$5}' \
-  ${tmpdir}/testgrid.ps`
-${PBM_TESTPREFIX}pstopnm -xborder=0 -yborder=0 $xysize2 -stdout \
-  -quiet ${tmpdir}/testgrid.ps -pbm | \
-  ${PBM_BINPREFIX}pnmtopnm | cksum
+# Test 2.  Should print: 2918318199 62 seven times
+# Test image designed to detect problems with run-length compression
+#
+${PBM_BINPREFIX}pbmmake -g 2 2 > ${tmpdir}/g.pbm
+${PBM_BINPREFIX}pbmmake -g 8 4 | \
+  ${PBM_BINPREFIX}pnmshear 45 -noantialias -background=black | \
+  ${PBM_BINPREFIX}pnmpad -right 60 | \
+  ${PBM_BINPREFIX}pnmcat -tb -jright - ${tmpdir}/g.pbm > ${tmpdir}/t.pbm &&
+for flag in "" "-rle" "-ps -rle -ascii" \
+            "-bitspersample=2 -rle" "-ps -bitspersample=4 -rle" \
+            "-bitspersample=8 -rle" "-ps -bitspersample=12 -rle -dict" 
+  do
+  ${PBM_TESTPREFIX}pnmtops -nocenter -equalpixels -dpi 72 -noturn \
+    ${flag} ${tmpdir}/t.pbm  > ${tmpdir}/testgrid.ps &&
+  xysize2=`awk  '/BoundingBox/ {print "-xsize="$4,"-ysize="$5}' \
+    ${tmpdir}/testgrid.ps`
+  ${PBM_TESTPREFIX}pstopnm -xborder=0 -yborder=0 $xysize2 -stdout \
+    -quiet ${tmpdir}/testgrid.ps -pbm | \
+    ${PBM_BINPREFIX}pnmtopnm | cksum
+  done
 
 
-#Test 3. Should print: 1386192571 507420
+#Test 3. Should print: 1386192571 507420 three times
+# *NOTE* Second iteration fails if pnmtops was compiled without zlib
+# (flate compression) support.
+#
+# Special care is needed when conducting round-trips with multiple-image
+# files as input.
+# (1) pnmtops: -setpage is mandatory
+# (2) awk: xy values are taken from the first "BoundingBox" encountered.
+#          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.              
+#
+for flag in "" "-ps" \
+            "-ps -bitspersample=12 -flate -rle -vmreclaim"
+  do
 cat testimg.ppm testimg.ppm testimg.ppm testgrid.pbm testgrid.pbm | \
 ${PBM_TESTPREFIX}pnmtops -nocenter -equalpixels -dpi 72 -noturn -setpage \
-  > ${tmpdir}/testimg5.ps
+  ${flag}  > ${tmpdir}/testimg5.ps
 xysize3=`awk  '/BoundingBox/ {print "-xsize="$4,"-ysize="$5 ; exit}' \
   ${tmpdir}/testimg5.ps`
 ${PBM_TESTPREFIX}pstopnm -xborder=0 -yborder=0 $xysize3 \
     -stdout  ${tmpdir}/testimg5.ps | \
   ${PBM_BINPREFIX}pnmtopnm | cksum
+  done
 
 
-#rm  ${tmpdir}/testgrid.ps  ${tmpdir}/testimg.ps  ${tmpdir}/testimg5.ps
-rm   ${tmpdir}/testimg.ps  ${tmpdir}/testimg5.ps
-mv ${tmpdir}/testgrid.ps /tmp
+rm ${tmpdir}/testgrid.ps  ${tmpdir}/testimg.ps  ${tmpdir}/testimg5.ps \
+   ${tmpdir}/t.pbm
diff --git a/buildtools/testrandom.c b/test/testrandom.c
index 3f65f0d2..3f65f0d2 100644
--- a/buildtools/testrandom.c
+++ b/test/testrandom.c
diff --git a/urt/Makefile b/urt/Makefile
index b94da1b2..0aef5290 100644
--- a/urt/Makefile
+++ b/urt/Makefile
@@ -5,6 +5,8 @@ endif
 SUBDIR = urt
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
+default: all
+
 include $(BUILDDIR)/config.mk
 
 LIBOBJECTS = Runput.o cmd_name.o \
@@ -15,6 +17,9 @@ LIBOBJECTS = Runput.o cmd_name.o \
 
 MERGE_OBJECTS =
 
+OMIT_URT_RULE = 1
+include $(SRCDIR)/common.mk
+
 all: librle.a
 
 librle.a: $(LIBOBJECTS)
@@ -24,11 +29,8 @@ librle.a: $(LIBOBJECTS)
 
 # Rule for objects.
 $(LIBOBJECTS): %.o: %.c importinc
-	$(CC) -c $(INCLUDES) -o $@ \
-	  $< $(CPPFLAGS) $(CFLAGS) $(CFLAGS_PERSONAL) $(CADD)
+	$(CC) -c $(INCLUDES) -o $@ $< $(CFLAGS_ALL)
 
 BINARIES =
 SCRIPTS =
 
-OMIT_URT_RULE = 1
-include $(SRCDIR)/common.mk
diff --git a/version.mk b/version.mk
index 7f06da81..0b659594 100644
--- a/version.mk
+++ b/version.mk
@@ -1,4 +1,4 @@
 NETPBM_MAJOR_RELEASE = 10
-NETPBM_MINOR_RELEASE = 64
-NETPBM_POINT_RELEASE = 6
+NETPBM_MINOR_RELEASE = 65
+NETPBM_POINT_RELEASE = 0