about summary refs log tree commit diff
path: root/analyzer
diff options
context:
space:
mode:
Diffstat (limited to 'analyzer')
-rw-r--r--analyzer/Makefile10
-rw-r--r--analyzer/pamfile.c1
-rw-r--r--analyzer/pamsharpmap.c1
-rw-r--r--analyzer/pamsharpness.c1
-rw-r--r--analyzer/pamslice.c1
-rw-r--r--analyzer/pamsumm.c1
-rw-r--r--analyzer/pamtilt.c1
-rw-r--r--analyzer/pbmminkowski.c199
-rw-r--r--analyzer/pgmhist.c225
-rw-r--r--analyzer/pnmhistmap.c85
-rw-r--r--analyzer/pnmpsnr.c81
-rw-r--r--analyzer/ppmhist.c33
12 files changed, 389 insertions, 250 deletions
diff --git a/analyzer/Makefile b/analyzer/Makefile
index 6a447ea7..ed180917 100644
--- a/analyzer/Makefile
+++ b/analyzer/Makefile
@@ -5,7 +5,7 @@ endif
 SUBDIR = analyzer
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
 # We tend to separate out the build targets so that we don't have
 # any more dependencies for a given target than it really needs.
@@ -15,7 +15,7 @@ include $(BUILDDIR)/Makefile.config
 # build.
 
 PORTBINARIES = pamfile pamslice pamsumm pamtilt \
-               pgmhist pnmhistmap ppmhist pgmminkowski
+               pbmminkowski pgmhist pnmhistmap ppmhist pgmminkowski
 MATHBINARIES = pamsharpmap pamsharpness pgmtexture pnmpsnr 
 
 BINARIES = $(PORTBINARIES) $(MATHBINARIES)
@@ -33,16 +33,16 @@ MERGE_OBJECTS = $(MERGEBINARIES:%=%.o2)
 .PHONY: all
 all: $(BINARIES)
 
-include $(SRCDIR)/Makefile.common
+include $(SRCDIR)/common.mk
 
 install.bin: install.bin.local
 .PHONY: install.bin.local
 install.bin.local: $(PKGDIR)/bin
 # Remember that $(SYMLINK) might just be a copy command.
 	cd $(PKGDIR)/bin ; \
-	$(SYMLINK) pamslice$(EXE) pgmslice
+	$(SYMLINK) pamslice$(EXE) pgmslice$(EXE)
 	cd $(PKGDIR)/bin ; \
-	$(SYMLINK) pamfile$(EXE) pnmfile
+	$(SYMLINK) pamfile$(EXE) pnmfile$(EXE)
 
 FORCE:
 
diff --git a/analyzer/pamfile.c b/analyzer/pamfile.c
index efb2cbee..4fa81330 100644
--- a/analyzer/pamfile.c
+++ b/analyzer/pamfile.c
@@ -10,6 +10,7 @@
 ** implied warranty.
 */
 
+#include "pm_c_util.h"
 #include "mallocvar.h"
 #include "nstring.h"
 #include "shhopt.h"
diff --git a/analyzer/pamsharpmap.c b/analyzer/pamsharpmap.c
index 8a08f981..ddeefe14 100644
--- a/analyzer/pamsharpmap.c
+++ b/analyzer/pamsharpmap.c
@@ -20,6 +20,7 @@
 #include <stdio.h>
 #include <math.h>
 
+#include "pm_c_util.h"
 #include "pam.h"
 #include "shhopt.h"
 #include "mallocvar.h"
diff --git a/analyzer/pamsharpness.c b/analyzer/pamsharpness.c
index 3850aa3a..8e2d9a3f 100644
--- a/analyzer/pamsharpness.c
+++ b/analyzer/pamsharpness.c
@@ -20,6 +20,7 @@
 #include <stdio.h>
 #include <math.h>
 
+#include "pm_c_util.h"
 #include "pam.h"
 #include "shhopt.h"
 
diff --git a/analyzer/pamslice.c b/analyzer/pamslice.c
index fc63a2cc..ab372c8a 100644
--- a/analyzer/pamslice.c
+++ b/analyzer/pamslice.c
@@ -22,6 +22,7 @@
 
 enum orientation {ROW, COLUMN};
 
+#include "pm_c_util.h"
 #include "pam.h"
 #include "shhopt.h"
 
diff --git a/analyzer/pamsumm.c b/analyzer/pamsumm.c
index 390b8ebb..c9b8a7bf 100644
--- a/analyzer/pamsumm.c
+++ b/analyzer/pamsumm.c
@@ -10,6 +10,7 @@
 
 ******************************************************************************/
 
+#include "pm_c_util.h"
 #include "pam.h"
 #include "shhopt.h"
 #include "mallocvar.h"
diff --git a/analyzer/pamtilt.c b/analyzer/pamtilt.c
index cc135ab6..d70f491b 100644
--- a/analyzer/pamtilt.c
+++ b/analyzer/pamtilt.c
@@ -15,6 +15,7 @@
 #include <assert.h>
 #include <math.h>
 
+#include "pm_c_util.h"
 #include "pam.h"
 #include "mallocvar.h"
 #include "shhopt.h"
diff --git a/analyzer/pbmminkowski.c b/analyzer/pbmminkowski.c
index 5edce506..0f7b47a9 100644
--- a/analyzer/pbmminkowski.c
+++ b/analyzer/pbmminkowski.c
@@ -15,154 +15,171 @@
 
 #include "pbm.h"
 
-#define ISWHITE(x) ( (x) == PBM_WHITE )
+#define ISWHITE(x) ((x) == PBM_WHITE)
 
 
-int main( int argc, char** argv ){
+int main(int argc, const char ** argv) {
 
-  FILE* ifp;
+    FILE * ifP;
 
-  bit* prevrow;
-  bit* thisrow;
-  bit* tmprow;
+    bit * prevrow;
+    bit * thisrow;
+    bit * tmprow;
   
-  int row;
-  int col; 
+    int row;
+    int col; 
 
-  int countTile=0;
-  int countEdgeX=0;
-  int countEdgeY=0;
-  int countVertex=0;
+    int countTile;
+    int countEdgeX;
+    int countEdgeY;
+    int countVertex;
   
-  int rows;
-  int cols;
-  int format;
+    int rows;
+    int cols;
+    int format;
 
-  int area, perimeter, eulerchi;
+    int area, perimeter, eulerchi;
 
 
-  /*
-   * parse arg and initialize
-   */ 
-
-  pbm_init( &argc, argv );
+    pm_proginit(&argc, argv);
   
-  if ( argc > 2 )
-    pm_usage( "[pbmfile]" );
+    if (argc > 2)
+        pm_usage("[pbmfile]");
   
-  if ( argc == 2 )
-    ifp = pm_openr( argv[1] );
-  else
-    ifp = stdin;
+    if (argc == 2)
+        ifP = pm_openr(argv[1]);
+    else
+        ifP = stdin;
   
-  pbm_readpbminit( ifp, &cols, &rows, &format );
+    pbm_readpbminit(ifP, &cols, &rows, &format);
+
+    prevrow = pbm_allocrow(cols);
+    thisrow = pbm_allocrow(cols);
 
-  prevrow = pbm_allocrow( cols );
-  thisrow = pbm_allocrow( cols );
 
+    /* first row */
 
-  /* first row */
+    pbm_readpbmrow(ifP, thisrow, cols, format);
 
-  pbm_readpbmrow( ifp, thisrow, cols, format );
+    countTile   = 0;
+    countEdgeX  = 0;
+    countEdgeY  = 0;
+    countVertex = 0;
 
-  /* tiles */
+    /* tiles */
 
-  for ( col = 0; col < cols; ++col ) 
-    if( ISWHITE(thisrow[col]) ) ++countTile;
+    for (col = 0; col < cols; ++col) 
+        if (ISWHITE(thisrow[col]))
+            ++countTile;
   
-  /* shortcut: for the first row, edgeY == countTile */
-  countEdgeY = countTile;
+    /* shortcut: for the first row, edgeY == countTile */
+    countEdgeY = countTile;
 
-  /* x-edges */
+    /* x-edges */
 
-  if( ISWHITE(thisrow[0]) ) ++countEdgeX;
+    if (ISWHITE(thisrow[0]))
+        ++countEdgeX;
 
-  for ( col = 0; col < cols-1; ++col ) 
-    if( ISWHITE(thisrow[col]) || ISWHITE(thisrow[col+1]) ) ++countEdgeX;
+    for (col = 0; col < cols-1; ++col) 
+        if (ISWHITE(thisrow[col]) || ISWHITE(thisrow[col+1]))
+            ++countEdgeX;
 
-  if( ISWHITE(thisrow[cols-1]) ) ++countEdgeX;
+    if (ISWHITE(thisrow[cols-1]))
+        ++countEdgeX;
 
-  /* shortcut: for the first row, countVertex == countEdgeX */
+    /* shortcut: for the first row, countVertex == countEdgeX */
   
-  countVertex = countEdgeX;
+    countVertex = countEdgeX;
   
 
-  for ( row = 1; row < rows; ++row ){  
+    for (row = 1; row < rows; ++row) {  
     
-    tmprow = prevrow; 
-    prevrow = thisrow;
-    thisrow = tmprow;
+        tmprow  = prevrow; 
+        prevrow = thisrow;
+        thisrow = tmprow;
  
-    pbm_readpbmrow( ifp, thisrow, cols, format );
+        pbm_readpbmrow(ifP, thisrow, cols, format);
   
-    /* tiles */
+        /* tiles */
 
-    for ( col = 0; col < cols; ++col ) 
-      if( ISWHITE(thisrow[col]) ) ++countTile;
+        for (col = 0; col < cols; ++col) 
+            if (ISWHITE(thisrow[col]))
+                ++countTile;
     
-    /* y-edges */
+        /* y-edges */
 
-    for ( col = 0; col < cols; ++col ) 
-      if( ISWHITE(thisrow[col]) || ISWHITE( prevrow[col] )) ++countEdgeY;
+        for (col = 0; col < cols; ++col) 
+            if (ISWHITE(thisrow[col]) || ISWHITE(prevrow[col]))
+                ++countEdgeY;
     
-    /* x-edges */
+        /* x-edges */
 
-    if( ISWHITE(thisrow[0]) ) ++countEdgeX;
+        if (ISWHITE(thisrow[0]))
+            ++countEdgeX;
 
-    for ( col = 0; col < cols-1; ++col ) 
-      if( ISWHITE(thisrow[col]) || ISWHITE(thisrow[col+1]) ) ++countEdgeX;
+        for (col = 0; col < cols-1; ++col) 
+            if (ISWHITE(thisrow[col]) || ISWHITE(thisrow[col+1]))
+                ++countEdgeX;
     
-    if( ISWHITE(thisrow[cols-1]) ) ++countEdgeX;
+        if (ISWHITE(thisrow[cols-1]))
+            ++countEdgeX;
     
-    /* vertices */
+        /* vertices */
 
-    if( ISWHITE(thisrow[0]) || ISWHITE(prevrow[0]) ) ++countVertex;
+        if (ISWHITE(thisrow[0]) || ISWHITE(prevrow[0]))
+            ++countVertex;
 
-    for ( col = 0; col < cols-1; ++col ) 
-      if(    ISWHITE(thisrow[col]) || ISWHITE(thisrow[col+1]) 
-	  || ISWHITE(prevrow[col]) || ISWHITE(prevrow[col+1]) ) ++countVertex;
+        for (col = 0; col < cols-1; ++col) 
+            if (ISWHITE(thisrow[col]) || ISWHITE(thisrow[col+1]) 
+                || ISWHITE(prevrow[col]) || ISWHITE(prevrow[col+1]))
+                ++countVertex;
 
-    if( ISWHITE(thisrow[cols-1]) || ISWHITE(prevrow[cols-1]) ) ++countVertex;
+        if (ISWHITE(thisrow[cols-1]) || ISWHITE(prevrow[cols-1]))
+            ++countVertex;
 
 	  
-  } /* for row */
+    } /* for row */
 
-  /* now thisrow contains the top row*/
-  /* tiles and x-edges have been counted, now y-edges and top vertices remain */
+    /* now thisrow contains the top row*/
+    /* tiles and x-edges have been counted, now y-edges and top
+       vertices remain
+    */
 
   
-  /* y-edges */
+    /* y-edges */
 
-  for ( col = 0; col < cols; ++col ) 
-    if( ISWHITE(thisrow[col]) ) ++countEdgeY;
+    for (col = 0; col < cols; ++col) 
+        if (ISWHITE(thisrow[col]))
+            ++countEdgeY;
 
-  /* vertices */
+    /* vertices */
   
-  if( ISWHITE(thisrow[0]) ) ++countVertex;
-
-  for ( col = 0; col < cols-1; ++col ) 
-    if( ISWHITE(thisrow[col]) || ISWHITE(thisrow[col+1]) ) ++countVertex;
+    if (ISWHITE(thisrow[0]))
+        ++countVertex;
 
-  if( ISWHITE(thisrow[cols-1]) ) ++countVertex;
+    for (col = 0; col < cols-1; ++col) 
+        if (ISWHITE(thisrow[col]) || ISWHITE(thisrow[col+1]))
+            ++countVertex;
 
+    if (ISWHITE(thisrow[cols-1]))
+        ++countVertex;
 
-  /* cleanup */
+    /* cleanup */
 
-  pm_close( ifp );
+    pm_close(ifP);
 
-  /* print results */
+    /* print results */
 
-  printf( "   tiles:\t%d\n x-edges:\t%d\n y-edges:\t%d\nvertices:\t%d\n",
-	  countTile, countEdgeX, countEdgeY,countVertex );
+    printf("   tiles:\t%d\n x-edges:\t%d\n y-edges:\t%d\nvertices:\t%d\n",
+           countTile, countEdgeX, countEdgeY,countVertex);
 
-  area      = countTile;
-  perimeter = 2*countEdgeX + 2*countEdgeY - 4*countTile;
-  eulerchi  = countTile - countEdgeX - countEdgeY + countVertex;
+    area      = countTile;
+    perimeter = 2*countEdgeX + 2*countEdgeY - 4*countTile;
+    eulerchi  = countTile - countEdgeX - countEdgeY + countVertex;
 
-  printf( "    area:\t%d\nperimeter:\t%d\n eulerchi:\t%d\n",
-	  area, perimeter, eulerchi );
+    printf("    area:\t%d\nperimeter:\t%d\n eulerchi:\t%d\n",
+           area, perimeter, eulerchi );
   
-  exit( 0 );
-
-} /* main */
+    return 0;
+}
 
diff --git a/analyzer/pgmhist.c b/analyzer/pgmhist.c
index 126fe693..4790ecba 100644
--- a/analyzer/pgmhist.c
+++ b/analyzer/pgmhist.c
@@ -1,4 +1,4 @@
-/* pgmhist.c - print a histogram of the values in a portable graymap
+/* pgmhist.c - print a histogram of the values in a PGM image
 **
 ** Copyright (C) 1989 by Jef Poskanzer.
 **
@@ -10,86 +10,189 @@
 ** implied warranty.
 */
 
+#include <assert.h>
 #include <limits.h>
 
-#include "pgm.h"
+#include "pm_c_util.h"
 #include "mallocvar.h"
+#include "shhopt.h"
+#include "pgm.h"
 
-int
-main( argc, argv )
-    int argc;
-    char *argv[];
-{
-    FILE *ifp;
-    gray maxval, *grayrow;
-    register gray *gP;
-    int argn, rows, cols, format, row;
-    int i, *hist, *rcount, count, size;
-    register int col;
-    const char * const usage = "[pgmfile]";
-
-    pgm_init( &argc, argv );
-
-    argn = 1;
-
-    if ( argn < argc )
-	{
-        ifp = pm_openr( argv[argn] );
-        argn++;
-	}
+
+
+struct cmdline_info {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char * inputFileName;  /* Filename of input files */
+};
+
+
+
+static void
+parseCommandLine(int argc, const char ** argv,
+                 struct cmdline_info * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   Note that the file spec array we return is stored in the storage that
+   was passed to us as the argv array.
+-----------------------------------------------------------------------------*/
+    optStruct3 opt;  /* set by OPTENT3 */
+    optEntry * option_def;
+    unsigned int option_def_index;
+    
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+
+    OPTENTINIT;
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
+
+    optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (argc-1 == 0) 
+        cmdlineP->inputFileName = "-";
+    else if (argc-1 != 1)
+        pm_error("Program takes zero or one argument (filename).  You "
+                 "specified %d", argc-1);
     else
-        ifp = stdin;
+        cmdlineP->inputFileName = argv[1];
+}
 
-    if ( argn != argc )
-        pm_usage( usage );
 
-    pgm_readpgminit( ifp, &cols, &rows, &maxval, &format );
+
+static void
+buildHistogram(FILE *          const ifP,
+               unsigned int ** const histP,
+               gray *          const maxvalP) {
+
+    gray * grayrow;
+    int rows, cols;
+    int format;
+    unsigned int row;
+    unsigned int i;
+    unsigned int * hist;  /* malloc'ed array */
+    gray maxval;
+
+    pgm_readpgminit(ifP, &cols, &rows, &maxval, &format);
 
     if (UINT_MAX / cols < rows)
         pm_error("Too many pixels (%u x %u) in image.  "
                  "Maximum computable is %u",
                  cols, rows, UINT_MAX);
 
-    grayrow = pgm_allocrow( cols );
+    grayrow = pgm_allocrow(cols);
 
-    /* Build histogram. */
     MALLOCARRAY(hist, maxval + 1);
-    MALLOCARRAY(rcount, maxval + 1);
-    if ( hist == NULL || rcount == NULL )
-        pm_error( "out of memory" );
-    for ( i = 0; i <= maxval; i++ )
+    if (hist == NULL)
+        pm_error("out of memory");
+
+    for (i = 0; i <= maxval; ++i)
         hist[i] = 0;
-    for ( row = 0; row < rows; row++ )
-	{
-        pgm_readpgmrow( ifp, grayrow, cols, maxval, format );
-        for ( col = 0, gP = grayrow; col < cols; col++, gP++ )
-            hist[(int) *gP]++;
-	}
 
-    pm_close( ifp );
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+
+        pgm_readpgmrow(ifP, grayrow, cols, maxval, format);
+
+        for (col = 0; col < cols; ++col) {
+            /* Because total pixels in image is limited: */
+            assert (hist[grayrow[col]] < INT_MAX);
+
+            ++hist[grayrow[col]];
+        }
+    }
+    pgm_freerow(grayrow);
+
+    *histP   = hist;
+    *maxvalP = maxval;
+}
+
+
+
+static void
+countCumulative(unsigned int    const hist[],
+                gray            const maxval,
+                unsigned int ** const rcountP) {
+
+    unsigned int * rcount;
+    unsigned int cumCount;
+    int i;
+    
+    MALLOCARRAY(rcount, maxval + 1);
+    if (rcount == NULL)
+        pm_error("out of memory");
+
+    for (i = maxval, cumCount = 0; i >= 0; --i) {
+        /* Because total pixels in image is limited: */
+        assert(UINT_MAX - hist[i] >= cumCount);
+
+        cumCount += hist[i];
+        rcount[i] = cumCount;
+    }
+
+    *rcountP = rcount;
+}
+
+
+
+static void
+report(unsigned int const hist[],
+       unsigned int const rcount[],
+       gray         const maxval) {
+
+    unsigned int const totalPixels = rcount[0];
+    unsigned int count;
+    unsigned int i;
+
+    printf("value  count  b%%      w%%   \n");
+    printf("-----  -----  ------  ------\n");
 
-    /* Compute count-down */
-    count = 0;
-    for ( i = maxval; i >= 0; i-- )
-	{
-        count += hist[i];
-        rcount[i] = count;
-	}
-
-    /* And print it. */
-    printf( "value\tcount\tb%%\tw%%\n" );
-    printf( "-----\t-----\t--\t--\n" );
     count = 0;
-    size = rows * cols;
-    for ( i = 0; i <= maxval; i++ )
-        if ( hist[i] > 0 )
-	    {
+
+    for (i = 0; i <= maxval; ++i) {
+        if (hist[i] > 0) {
             count += hist[i];
             printf(
-                "%d\t%d\t%5.3g%%\t%5.3g%%\n", i, hist[i],
-                (float) count * 100.0 / size, 
-                (float) rcount[i] * 100.0 / size );
-	    }
+                "%5d  %5d  %5.3g%%  %5.3g%%\n", i, hist[i],
+                (float) count * 100.0 / totalPixels, 
+                (float) rcount[i] * 100.0 / totalPixels);
+        }
+    }
+}
+
 
-    exit( 0 );
+
+int
+main(int argc, const char ** argv) {
+
+    struct cmdline_info cmdline;
+    FILE * ifP;
+    gray maxval;
+    unsigned int * rcount; /* malloc'ed array */
+    unsigned int * hist;   /* malloc'ed array */
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    buildHistogram(ifP, &hist, &maxval);
+
+    countCumulative(hist, maxval, &rcount);
+
+    report(hist, rcount, maxval);
+
+    free(rcount);
+    free(hist);
+    pm_close(ifP);
+
+    return 0;
 }
+
+
+
diff --git a/analyzer/pnmhistmap.c b/analyzer/pnmhistmap.c
index 0e5cf302..7e504734 100644
--- a/analyzer/pnmhistmap.c
+++ b/analyzer/pnmhistmap.c
@@ -19,6 +19,7 @@
 
 #include <string.h>
 
+#include "pm_c_util.h"
 #include "pnm.h"
 #include "shhopt.h"
 #include "mallocvar.h"
@@ -152,16 +153,16 @@ clipHistogram(unsigned int * const hist,
               unsigned int   const hist_width,
               unsigned int   const hmax) {
 
-            unsigned int i;
+    unsigned int i;
 
-            for (i = 0; i < hist_width; ++i)
-                hist[i] = MIN(hmax, hist[i]);
+    for (i = 0; i < hist_width; ++i)
+        hist[i] = MIN(hmax, hist[i]);
 }
 
 
 
 static void
-pgm_hist(FILE *       const fp,
+pgm_hist(FILE *       const ifP,
          int          const cols,
          int          const rows,
          xelval       const maxval,
@@ -186,41 +187,44 @@ pgm_hist(FILE *       const fp,
     unsigned int * ghist;
     double vscale;
     unsigned int hmax;
-
-    if ((ghist = calloc(hist_width, sizeof(int))) == NULL)
-        pm_error ("Not enough memory for histogram array (%d bytes)",
+    
+    MALLOCARRAY(ghist, hist_width);
+    if (ghist == NULL)
+        pm_error("Not enough memory for histogram array (%d bytes)",
                   hist_width * sizeof(int));
-    if ((bits = pbm_allocarray (hist_width, hist_height)) == NULL)
-        pm_error ("no space for output array (%d bits)",
-                  hist_width * hist_height);
-    memset (ghist, 0, sizeof (ghist));
+    bits = pbm_allocarray(hist_width, hist_height);
+    if (bits == NULL)
+        pm_error("no space for output array (%d bits)",
+                 hist_width * hist_height);
+    memset(ghist, 0, hist_width * sizeof(ghist[0]));
 
     /* read the pixel values into the histogram arrays */
-    grayrow = pgm_allocrow (cols);
-    /*XX error-check! */
-    if (verbose) pm_message ("making histogram...");
+    grayrow = pgm_allocrow(cols);
+
+    if (verbose)
+        pm_message("making histogram...");
+
     for (i = rows; i > 0; --i) {
-        pgm_readpgmrow (fp, grayrow, cols, maxval, format);
+        pgm_readpgmrow (ifP, grayrow, cols, maxval, format);
         for (j = cols-1; j >= 0; --j) {
-            int value;
+            int const value = grayrow[j];
 
-            if ((value = grayrow[j]) >= startval && value <= endval)
-                ghist[SCALE_H(value-startval)]++;
+            if (value >= startval && value <= endval)
+                ++ghist[SCALE_H(value-startval)];
         }
     }
-    pgm_freerow (grayrow);
-    fclose (fp);
+    pgm_freerow(grayrow);
 
     /* find the highest-valued slot and set the vertical scale value */
     if (verbose)
-        pm_message ("finding max. slot height...");
+        pm_message("finding max. slot height...");
     if (clipSpec)
         hmax = clipCount;
     else 
         hmax = maxSlotCount(ghist, hist_width, no_white, no_black);
 
     if (verbose)
-        pm_message ("Done: height = %u", hmax);
+        pm_message("Done: height = %u", hmax);
 
     clipHistogram(ghist, hist_width, hmax);
 
@@ -236,7 +240,7 @@ pgm_hist(FILE *       const fp,
             bits[j][i] = dots ? PBM_BLACK : PBM_WHITE;
     }
 
-    pbm_writepbm (stdout, bits, hist_width, hist_height, 0);
+    pbm_writepbm(stdout, bits, hist_width, hist_height, 0);
 }
 
 
@@ -309,7 +313,7 @@ clipHistogramAll(unsigned int * const hist[3],
 
 
 static void
-ppm_hist(FILE *       const fp,
+ppm_hist(FILE *       const ifP,
          int          const cols,
          int          const rows,
          xelval       const maxval,
@@ -329,8 +333,8 @@ ppm_hist(FILE *       const fp,
 
     bool const hscale_unity = hscale - 1 < epsilon;
 
-    pixel *pixrow;
-    pixel **pixels;
+    pixel * pixrow;
+    pixel ** pixels;
     int i, j;
     unsigned int * hist[3];  /* Subscript is enum wantedColor */
     double vscale;
@@ -339,17 +343,19 @@ ppm_hist(FILE *       const fp,
     createHist(colorWanted, hist_width, &hist);
 
     if ((pixels = ppm_allocarray (hist_width, hist_height)) == NULL)
-        pm_error ("no space for output array (%d pixels)",
-                  hist_width * hist_height);
+        pm_error("no space for output array (%d pixels)",
+                 hist_width * hist_height);
     for (i = 0; i < hist_height; ++i)
-        memset (pixels[i], 0, hist_width * sizeof (pixel));
+        memset(pixels[i], 0, hist_width * sizeof(pixels[i][0]));
 
     /* read the pixel values into the histogram arrays */
-    pixrow = ppm_allocrow (cols);
-    /*XX error-check! */
-    if (verbose) pm_message ("making histogram...");
+    pixrow = ppm_allocrow(cols);
+
+    if (verbose)
+        pm_message("making histogram...");
+
     for (i = rows; i > 0; --i) {
-        ppm_readppmrow (fp, pixrow, cols, maxval, format);
+        ppm_readppmrow(ifP, pixrow, cols, maxval, format);
         for (j = cols-1; j >= 0; --j) {
             int value;
 
@@ -367,12 +373,11 @@ ppm_hist(FILE *       const fp,
                 hist[WANT_BLU][SCALE_H(value-startval)]++;
         }
     }
-    ppm_freerow (pixrow);
-    fclose (fp);
+    ppm_freerow(pixrow);
 
     /* find the highest-valued slot and set the vertical scale value */
     if (verbose)
-        pm_message ("finding max. slot height...");
+        pm_message("finding max. slot height...");
     if (clipSpec)
         hmax = clipCount;
     else 
@@ -420,16 +425,16 @@ ppm_hist(FILE *       const fp,
             }
         }
     }
-    ppm_writeppm (stdout, pixels, hist_width, hist_height, maxval, 0);
+    ppm_writeppm(stdout, pixels, hist_width, hist_height, maxval, 0);
 }
 
 
 
 int
-main (int argc, char ** argv) {
+main(int argc, char ** argv) {
 
     struct cmdlineInfo cmdline;
-    FILE* ifP;
+    FILE * ifP;
     int cols, rows;
     xelval maxval;
     int format;
@@ -479,5 +484,7 @@ main (int argc, char ** argv) {
         pm_error("Cannot do a histogram of a a PBM file");
         break;
     }
+    pm_close(ifP);
+
     return 0;
 }
diff --git a/analyzer/pnmpsnr.c b/analyzer/pnmpsnr.c
index a7331d27..1160fff6 100644
--- a/analyzer/pnmpsnr.c
+++ b/analyzer/pnmpsnr.c
@@ -13,6 +13,7 @@
 #include <math.h>
 
 #include "pm_c_util.h"
+#include "nstring.h"
 #include "pam.h"
 
 #define MAXFILES 16
@@ -47,7 +48,7 @@ validate_input(const struct pam pam1, const struct pam pam2) {
         pm_error("images do not have the same maxval.  This programs works "
                  "only on like maxvals.  "
                  "The first image has maxval %u, "
-                 "while the second has %u.  Use Pnmdepth to change the "
+                 "while the second has %u.  Use Pamdepth to change the "
                  "maxval of one of them.",
                  (unsigned int) pam1.maxval, (unsigned int) pam2.maxval);
 
@@ -66,16 +67,18 @@ validate_input(const struct pam pam1, const struct pam pam2) {
 
 
 static void
-psnr_color(tuple const tuple1, tuple const tuple2,
+psnr_color(tuple    const tuple1,
+           tuple    const tuple2,
            double * const ySqDiffP, 
-           double * const cbSqDiffP, double * const crSqDiffP) {
+           double * const cbSqDiffP,
+           double * const crSqDiffP) {
 
     double y1, y2, cb1, cb2, cr1, cr2;
     
     pnm_YCbCrtuple(tuple1, &y1, &cb1, &cr1);
     pnm_YCbCrtuple(tuple2, &y2, &cb2, &cr2);
     
-    *ySqDiffP =  square(y1  - y2);
+    *ySqDiffP  = square(y1  - y2);
     *cbSqDiffP = square(cb1 - cb2);
     *crSqDiffP = square(cr1 - cr2);
 }
@@ -83,45 +86,49 @@ psnr_color(tuple const tuple1, tuple const tuple2,
 
 
 static void
-reportPsnr(struct pam const pam1, struct pam const pam2, 
-           double const ySumSqDiff, 
-           double const crSumSqDiff, double const cbSumSqDiff,
-           const char filespec1[], const char filespec2[]) {
+reportPsnr(struct pam const pam,
+           double     const ySumSqDiff, 
+           double     const crSumSqDiff,
+           double     const cbSumSqDiff,
+           char       const filespec1[],
+           char       const filespec2[]) {
 
-    bool const color = (strcmp(pam1.tuple_type, PAM_PPM_TUPLETYPE) == 0);
+    bool const color = streq(pam.tuple_type, PAM_PPM_TUPLETYPE);
 
-    /* The PSNR is the mean of the sum of squares of the differences,
-       normalized to the range 0..1
+    /* The PSNR is the ratio of the maximum possible mean square difference
+       to the actual mean square difference.
+    */
+    double const yPsnr =
+        square(pam.maxval) / (ySumSqDiff / (pam.width * pam.height));
+
+    /* Note that in the important special case that the images are
+       identical, the sum square differences are identically 0.0.  No
+       precision error; no rounding error.
     */
-    double const yPsnr = ySumSqDiff 
-        / (pam1.width * pam1.height) 
-        / square(pam1.maxval);
 
     if (color) {
-        double const cbPsnr = cbSumSqDiff 
-            / (pam1.width * pam1.height) 
-            / square(pam1.maxval);
-        double const crPsnr = crSumSqDiff 
-            / (pam1.width * pam1.height) 
-            / (pam1.maxval * pam2.maxval);
+        double const cbPsnr =
+            square(pam.maxval) / (cbSumSqDiff / (pam.width * pam.height));
+        double const crPsnr =
+            square(pam.maxval) / (crSumSqDiff / (pam.width * pam.height));
 
         pm_message("PSNR between %s and %s:", filespec1, filespec2);
-        if (yPsnr > 1e-9)
-            pm_message("Y  color component: %.2f dB", 10 * log10(1/yPsnr));
+        if (ySumSqDiff > 0)
+            pm_message("Y  color component: %.2f dB", 10 * log10(yPsnr));
         else
             pm_message("Y color component does not differ.");
-        if (cbPsnr > 1e-9)
-            pm_message("Cb color component: %.2f dB", 10 * log10(1/cbPsnr));
+        if (cbSumSqDiff > 0)
+            pm_message("Cb color component: %.2f dB", 10 * log10(cbPsnr));
         else
-        pm_message("Cb color component does not differ.");
-        if (crPsnr > 1e-9)
-            pm_message("Cr color component: %.2f dB", 10 * log10(1/crPsnr));
+            pm_message("Cb color component does not differ.");
+        if (crSumSqDiff > 0)
+            pm_message("Cr color component: %.2f dB", 10 * log10(crPsnr));
         else
             pm_message("Cr color component does not differ.");
     } else {
-        if (yPsnr > 1e-9)
+        if (ySumSqDiff > 0)
             pm_message("PSNR between %s and %s: %.2f dB",
-                       filespec1, filespec2, 10 * log10(1/yPsnr));
+                       filespec1, filespec2, 10 * log10(yPsnr));
         else
             pm_message("Images %s and %s don't differ.",
                        filespec1, filespec2);
@@ -166,7 +173,7 @@ main (int argc, char **argv) {
     tuplerow1 = pnm_allocpamrow(&pam1);
     tuplerow2 = pnm_allocpamrow(&pam2);
     
-    ySumSqDiff = 0.0;
+    ySumSqDiff  = 0.0;
     cbSumSqDiff = 0.0;
     crSumSqDiff = 0.0;
 
@@ -181,19 +188,19 @@ main (int argc, char **argv) {
                 double ySqDiff, cbSqDiff, crSqDiff;
                 psnr_color(tuplerow1[col], tuplerow2[col], 
                            &ySqDiff, &cbSqDiff, &crSqDiff);
-                ySumSqDiff += ySqDiff;
+                ySumSqDiff  += ySqDiff;
                 cbSumSqDiff += cbSqDiff;
                 crSumSqDiff += crSqDiff;
                 
             } else {
-                unsigned int yDiffSq;
-                yDiffSq = square(udiff(tuplerow1[col][0], tuplerow2[col][0]));
+                unsigned int const yDiffSq =
+                    square(udiff(tuplerow1[col][0], tuplerow2[col][0]));
                 ySumSqDiff += yDiffSq;
             }
         }
     }
 
-    reportPsnr(pam1, pam2, ySumSqDiff, crSumSqDiff, cbSumSqDiff,
+    reportPsnr(pam1, ySumSqDiff, crSumSqDiff, cbSumSqDiff,
                filespec1, filespec2);
 
     pnm_freepamrow(tuplerow1);
@@ -201,9 +208,3 @@ main (int argc, char **argv) {
 
     return 0;
 }
-
-
-
-
-
-
diff --git a/analyzer/ppmhist.c b/analyzer/ppmhist.c
index 4c4d3c55..673c8175 100644
--- a/analyzer/ppmhist.c
+++ b/analyzer/ppmhist.c
@@ -12,9 +12,11 @@
 
 #include <assert.h>
 
-#include "ppm.h"
-#include "shhopt.h"
+#include "pm_c_util.h"
+#include "mallocvar.h"
 #include "nstring.h"
+#include "shhopt.h"
+#include "ppm.h"
 
 enum sort {SORT_BY_FREQUENCY, SORT_BY_RGB};
 
@@ -24,7 +26,7 @@ struct cmdline_info {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    const char *input_filespec;  /* Filespecs of input files */
+    const char * inputFileName;  /* Name of input file */
     unsigned int noheader;    /* -noheader option */
     enum colorFmt colorFmt;
     unsigned int colorname;   /* -colorname option */
@@ -34,19 +36,21 @@ struct cmdline_info {
 
 
 static void
-parse_command_line(int argc, char ** argv,
-                   struct cmdline_info * const cmdlineP) {
+parseCommandLine(int argc, const char ** argv,
+                 struct cmdline_info * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that the file spec array we return is stored in the storage that
    was passed to us as the argv array.
 -----------------------------------------------------------------------------*/
     optStruct3 opt;  /* set by OPTENT3 */
-    optEntry *option_def = malloc(100*sizeof(optEntry));
+    optEntry * option_def;
     unsigned int option_def_index;
     
     unsigned int hexcolorOpt, floatOpt, mapOpt, nomapOpt;
     const char * sort_type;
 
+    MALLOCARRAY(option_def, 100);
+
     option_def_index = 0;   /* incremented by OPTENTRY */
     OPTENT3(0,   "map",       OPT_FLAG, NULL,  &mapOpt,                0);
     OPTENT3(0,   "nomap",     OPT_FLAG, NULL,  &nomapOpt,              0);
@@ -63,16 +67,16 @@ parse_command_line(int argc, char ** argv,
     /* Set defaults */
     sort_type = "frequency";
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (argc-1 == 0) 
-        cmdlineP->input_filespec = "-";
+        cmdlineP->inputFileName = "-";
     else if (argc-1 != 1)
         pm_error("Program takes zero or one argument (filename).  You "
                  "specified %d", argc-1);
     else
-        cmdlineP->input_filespec = argv[1];
+        cmdlineP->inputFileName = argv[1];
 
     if (hexcolorOpt + floatOpt + mapOpt > 1)
         pm_error("You can specify only one of -hexcolor, -float, and -map");
@@ -218,9 +222,10 @@ printColors(colorhist_vector const chv,
 
 
 int
-main(int argc, char *argv[] ) {
+main(int argc, const char *argv[]) {
+
     struct cmdline_info cmdline;
-    FILE* ifP;
+    FILE * ifP;
     colorhist_vector chv;
     int rows, cols;
     pixval maxval;
@@ -234,11 +239,11 @@ main(int argc, char *argv[] ) {
     const char ** dictColornames;
     pixel * dictColors;
 
-    ppm_init( &argc, argv );
+    pm_proginit(&argc, argv);
 
-    parse_command_line(argc, argv, &cmdline);
+    parseCommandLine(argc, argv, &cmdline);
 
-    ifP = pm_openr(cmdline.input_filespec);
+    ifP = pm_openr(cmdline.inputFileName);
 
     ppm_readppminit(ifP, &cols, &rows, &maxval, &format);