about summary refs log tree commit diff
path: root/other
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2016-03-27 01:38:28 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2016-03-27 01:38:28 +0000
commit367c9cb514c9da766488b9bdb218a18e31cb7624 (patch)
treef9e343be94161a4837f0f1c1d072a35538ae0f63 /other
parent6e88e3326cb0c7f7975b56189278cab3f84ba1bd (diff)
downloadnetpbm-mirror-367c9cb514c9da766488b9bdb218a18e31cb7624.tar.gz
netpbm-mirror-367c9cb514c9da766488b9bdb218a18e31cb7624.tar.xz
netpbm-mirror-367c9cb514c9da766488b9bdb218a18e31cb7624.zip
Promote Stable (10.47) to Super Stable
git-svn-id: http://svn.code.sf.net/p/netpbm/code/super_stable@2691 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'other')
-rw-r--r--other/Makefile21
-rw-r--r--other/pamarith.c433
-rw-r--r--other/pambayer.c1
-rw-r--r--other/pamchannel.c1
-rw-r--r--other/pamdepth.c5
-rw-r--r--other/pamendian.c2
-rw-r--r--other/pamfixtrunc.c176
-rw-r--r--other/pamlookup.c1
-rw-r--r--other/pampick.c1
-rw-r--r--other/pamsplit.c2
-rw-r--r--other/pamstack.c1
-rw-r--r--other/pamsummcol.c1
-rw-r--r--other/pamx/Makefile7
-rw-r--r--other/pamx/Makefile251
-rw-r--r--other/pamx/image.c92
-rw-r--r--other/pamx/image.h5
-rw-r--r--other/pamx/pamx.c53
-rw-r--r--other/pamx/window.c4
-rw-r--r--other/pnmcolormap.c13
-rw-r--r--other/ppmsvgalib.c4
20 files changed, 617 insertions, 257 deletions
diff --git a/other/Makefile b/other/Makefile
index 9aaa9d93..f7333c64 100644
--- a/other/Makefile
+++ b/other/Makefile
@@ -5,13 +5,14 @@ endif
 SUBDIR = other
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
 SUBDIRS = pamx
 
+EXTERN_INCLUDES =
 ifneq ($(LINUXSVGALIB),NONE)
   ifneq ($(LINUXSVGAHDR_DIR),)
-    INCLUDES += -I$(LINUXSVGAHDR_DIR)
+    EXTERN_INCLUDES += -I$(LINUXSVGAHDR_DIR)
   endif
 endif
 
@@ -23,7 +24,7 @@ endif
 # build.
 
 PORTBINARIES = pamarith pambayer pamchannel pamdepth \
-	pamendian pamlookup pampick pamsplit \
+	pamendian pamfixtrunc pamlookup pampick pamsplit \
 	pamstack pamsummcol pnmcolormap \
 	ppmdcfont ppmddumpfont ppmdmkfont 
 
@@ -47,7 +48,7 @@ MERGE_OBJECTS = $(MERGEBINARIES:%=%.o2)
 .PHONY: all
 all: $(BINARIES) $(SUBDIRS:%=%/all)
 
-include $(SRCDIR)/Makefile.common
+include $(SRCDIR)/common.mk
 
 ppmsvgalib: %: %.o $(NETPBMLIB) $(LIBOPT)
 	$(LD) -o $@ $< \
@@ -60,15 +61,15 @@ install.bin.local: $(PKGDIR)/bin
 # Remember that $(SYMLINK) might just be a copy command.
 # In July 2002, pamarith replaced pnmarith
 	cd $(PKGDIR)/bin ; \
-	  rm -f pnmarith ; \
-	  $(SYMLINK) pamarith$(EXE) pnmarith
+	  rm -f pnmarith$(EXE) ; \
+	  $(SYMLINK) pamarith$(EXE) pnmarith$(EXE)
 # In December 2005, pamsplit replaced pnmsplit
 	cd $(PKGDIR)/bin ; \
-	  rm -f pnmsplit ; \
-	  $(SYMLINK) pamsplit$(EXE) pnmsplit
+	  rm -f pnmsplit$(EXE) ; \
+	  $(SYMLINK) pamsplit$(EXE) pnmsplit$(EXE)
 # In February 2006, pamdepth replaced pnmdepth
 	cd $(PKGDIR)/bin ; \
-	  rm -f pnmdepth ; \
-	  $(SYMLINK) pamdepth$(EXE) pnmdepth
+	  rm -f pnmdepth$(EXE) ; \
+	  $(SYMLINK) pamdepth$(EXE) pnmdepth$(EXE)
 
 FORCE:
diff --git a/other/pamarith.c b/other/pamarith.c
index c1e7f1ed..4374ee1c 100644
--- a/other/pamarith.c
+++ b/other/pamarith.c
@@ -1,6 +1,9 @@
 #include <assert.h>
 #include <string.h>
+#include <limits.h>
 
+#include "pm_c_util.h"
+#include "mallocvar.h"
 #include "shhopt.h"
 #include "pam.h"
 
@@ -10,25 +13,59 @@ enum function {FN_ADD, FN_SUBTRACT, FN_MULTIPLY, FN_DIVIDE, FN_DIFFERENCE,
                FN_SHIFTLEFT, FN_SHIFTRIGHT
               };
 
+
+
+static bool
+isDyadic(enum function const function) {
+
+    bool retval;
+    
+    switch (function) {
+    case FN_ADD:
+    case FN_MEAN:
+    case FN_AND:
+    case FN_OR:
+    case FN_XOR:
+        retval = FALSE;
+        break;
+    case FN_SUBTRACT:
+    case FN_DIFFERENCE:
+    case FN_MINIMUM:
+    case FN_MAXIMUM:
+    case FN_COMPARE:
+    case FN_MULTIPLY:
+    case FN_DIVIDE:
+    case FN_NAND:
+    case FN_NOR:
+    case FN_SHIFTLEFT:
+    case FN_SHIFTRIGHT:
+        retval = TRUE;
+        break;
+    }
+    return retval;
+}
+
+
+
 struct cmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    const char *input1Filespec;  
-    const char *input2Filespec;  
     enum function function;
+    unsigned int operandCt;
+    const char ** operandFileNames;
 };
 
 
 
 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
    was passed to us as the argv array.
 -----------------------------------------------------------------------------*/
-    optEntry *option_def = malloc(100*sizeof(optEntry));
+    optEntry * option_def;
         /* Instructions to OptParseOptions2 on how to parse our options.
          */
     optStruct3 opt;
@@ -41,6 +78,8 @@ parseCommandLine(int argc, char ** const argv,
         andSpec, orSpec, nandSpec, norSpec, xorSpec,
         shiftleftSpec, shiftrightSpec;
 
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
     option_def_index = 0;   /* incremented by OPTENTRY */
     OPTENT3(0, "add",         OPT_FLAG,   NULL, &addSpec,        0);
     OPTENT3(0, "subtract",    OPT_FLAG,   NULL, &subtractSpec,   0);
@@ -63,7 +102,7 @@ parseCommandLine(int argc, char ** const argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    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 (addSpec + subtractSpec + multiplySpec + divideSpec + differenceSpec +
@@ -72,15 +111,6 @@ parseCommandLine(int argc, char ** const argv,
         shiftleftSpec + shiftrightSpec > 1)
         pm_error("You may specify only one function");
 
-    if (argc-1 != 2)
-        pm_error("You must specify two arguments:  the files which are "
-                 "the operands of the "
-                 "dyadic function.  You specified %d", argc-1);
-    else {
-        cmdlineP->input1Filespec = argv[1];
-        cmdlineP->input2Filespec = argv[2];
-    }
-
     if (addSpec)
         cmdlineP->function = FN_ADD;
     else if (subtractSpec)
@@ -115,6 +145,21 @@ parseCommandLine(int argc, char ** const argv,
         cmdlineP->function = FN_SHIFTRIGHT;
     else
         pm_error("You must specify a function (e.g. '-add')");
+
+    if (argc-1 < 2)
+        pm_error("You must specify at least two arguments: the files which "
+                 "are the operands of the function.  You specified %u",
+                 argc-1);
+    else {
+        if (isDyadic(cmdlineP->function) && argc-1 > 2)
+            pm_error("You specified %u arguments, but a dyadic function.  "
+                     "For a dyadic function, you must specify 2 arguments:  "
+                     "the operands of the function", argc-1);
+        else {
+            cmdlineP->operandCt = argc-1;
+            cmdlineP->operandFileNames = &argv[1];
+        }
+    }
 }        
 
 
@@ -220,43 +265,124 @@ computeOutputType(struct pam *  const outpamP,
 
 
 
+static sample
+samplenSum(samplen      const operands[],
+           unsigned int const operandCt) {
+
+    unsigned int i;
+    samplen total;
+
+    for (i = 1, total = operands[0]; i < operandCt; ++i) {
+        total += operands[1];
+        if (total > 1.)
+            total = 1.;
+    }
+    return total;
+}
+
+
+
+static sample
+samplenMin(samplen      const operands[],
+           unsigned int const operandCt) {
+
+    unsigned int i;
+    samplen min;
+
+    for (i = 1, min = operands[0]; i < operandCt; ++i) {
+        if (operands[i] < min)
+            min = operands[i];
+    }
+    return min;
+}
+
+
+
+static sample
+samplenMax(samplen      const operands[],
+           unsigned int const operandCt) {
+
+    unsigned int i;
+    samplen max;
+
+    for (i = 1, max = operands[0]; i < operandCt; ++i) {
+        if (operands[i] > max)
+            max = operands[i];
+    }
+    return max;
+}
+
+
+
+static sample
+samplenMean(samplen      const operands[],
+            unsigned int const operandCt) {
+
+    unsigned int i;
+    double sum;
+
+    for (i = 0, sum = 0.; i < operandCt; ++i)
+        sum += operands[i];
+
+    return sum / operandCt;
+}
+
+
+
+static sample
+samplenProduct(samplen      const operands[],
+               unsigned int const operandCt) {
+
+    unsigned int i;
+    double product;
+
+    for (i = 1, product = operands[0]; i < operandCt; ++i)
+        product *= operands[i];
+
+    return product;
+}
+
+
+
 static samplen
 applyNormalizedFunction(enum function const function,
-                        samplen       const leftArg,
-                        samplen       const rightArg) {
+                        samplen       const operands[],
+                        unsigned int  const operandCt) {
 
     samplen result;
 
     switch (function) {
     case FN_ADD:
-        result = MIN(1., leftArg + rightArg);
+        result = samplenSum(operands, operandCt);
         break;
     case FN_SUBTRACT:
-        result = MAX(0., leftArg - rightArg);
+        result = MAX(0., operands[0] - operands[1]);
         break;
     case FN_MULTIPLY:
-        result = leftArg * rightArg;
+        result = samplenProduct(operands, operandCt);
         break;
     case FN_DIVIDE:
-        result = (rightArg > leftArg) ?
-        leftArg / rightArg : 1.;
+        result = (operands[1] > operands[0]) ?
+        operands[0] / operands[1] : 1.;
         break;
     case FN_DIFFERENCE:
-        result = leftArg > rightArg ? 
-            leftArg - rightArg : rightArg - leftArg;
+        result = operands[0] > operands[1] ? 
+            operands[0] - operands[1] : operands[1] - operands[0];
         break;
     case FN_MINIMUM:
-        result = MIN(leftArg, rightArg);
+        result = samplenMin(operands, operandCt);
         break;
     case FN_MAXIMUM:
-        result = MAX(leftArg, rightArg);
+        result = samplenMax(operands, operandCt);
         break;
     case FN_MEAN:
-        result = (leftArg + rightArg) / 2.0;
+        result = samplenMean(operands, operandCt);
         break;
     case FN_COMPARE:
         result = 
-            leftArg > rightArg ? 1. : leftArg < rightArg ? 0. : .5;
+            operands[0] > operands[1] ?
+            1. : operands[0] < operands[1] ?
+            0. : .5;
         break;
     default:
         pm_error("Internal error.  applyNormalizedFunction() called "
@@ -274,10 +400,15 @@ doNormalizedArith(struct pam *  const inpam1P,
                   struct pam *  const outpamP,
                   enum function const function) {
 
+    unsigned int const operandCt = 2;
+
     tuplen * tuplerown1;
     tuplen * tuplerown2;
     tuplen * tuplerownOut;
     unsigned int row;
+    samplen * operands;
+
+    MALLOCARRAY_NOFAIL(operands, operandCt);
 
     tuplerown1   = pnm_allocpamrown(inpam1P);
     tuplerown2   = pnm_allocpamrown(inpam2P);
@@ -295,10 +426,11 @@ doNormalizedArith(struct pam *  const inpam1P,
                 unsigned int const plane1 = MIN(outplane, inpam1P->depth-1);
                 unsigned int const plane2 = MIN(outplane, inpam2P->depth-1);
 
+                operands[0] = tuplerown1[col][plane1];
+                operands[1] = tuplerown2[col][plane2];
+
                 tuplerownOut[col][outplane] = 
-                    applyNormalizedFunction(function, 
-                                            tuplerown1[col][plane1], 
-                                            tuplerown2[col][plane2]);
+                    applyNormalizedFunction(function, operands, operandCt); 
                 assert(tuplerownOut[col][outplane] >= 0.);
                 assert(tuplerownOut[col][outplane] <= 1.);
 
@@ -310,75 +442,244 @@ doNormalizedArith(struct pam *  const inpam1P,
     pnm_freepamrown(tuplerown1);
     pnm_freepamrown(tuplerown2);
     pnm_freepamrown(tuplerownOut);
+    free(operands);
+}
+
+
+
+static sample
+sampleSum(sample       const operands[],
+          unsigned int const operandCt,
+          sample       const maxval) {
+
+    unsigned int i;
+    sample total;
+
+    for (i = 1, total = operands[0]; i < operandCt; ++i) {
+        total += operands[i];
+        if (total > maxval)
+            total = maxval;
+    }
+    return total;
+}
+
+
+
+static sample
+sampleMin(sample       const operands[],
+          unsigned int const operandCt) {
+
+    unsigned int i;
+    sample min;
+
+    for (i = 1, min = operands[0]; i < operandCt; ++i) {
+        if (operands[i] < min)
+            min = operands[i];
+    }
+    return min;
+}
+
+
+
+static sample
+sampleMax(sample       const operands[],
+          unsigned int const operandCt) {
+
+    unsigned int i;
+    sample max;
+
+    for (i = 1, max = operands[0]; i < operandCt; ++i) {
+        if (operands[i] > max)
+            max = operands[i];
+    }
+    return max;
+}
+
+
+
+static sample
+sampleMean(sample       const operands[],
+           unsigned int const operandCt) {
+
+    unsigned int i;
+    unsigned int sum;
+
+    for (i = 0, sum = 0; i < operandCt; ++i) {
+        sum += operands[i];
+        if (UINT_MAX - operands[i] < sum)
+            pm_error("Arithmetic overflow adding samples for mean");
+    }
+    return ROUNDDIV(sum, operandCt);
+}
+
+
+
+static sample
+sampleProduct(sample       const operands[],
+              unsigned int const operandCt,
+              sample       const maxval) {
+
+    unsigned int i;
+    double product;
+
+    for (i = 0, product = 1.0; i < operandCt; ++i) {
+        product *= ((double)operands[i]/maxval);
+    }
+    return (sample)(product * maxval + 0.5);
+}
+
+
+
+static sample
+sampleAnd(sample       const operands[],
+          unsigned int const operandCt) {
+
+    unsigned int i;
+    sample accum;
+
+    for (i = 1, accum = operands[0]; i < operandCt; ++i) {
+        accum &= operands[i];
+    }
+    return accum;
+}
+
+
+
+static sample
+sampleOr(sample       const operands[],
+         unsigned int const operandCt) {
+
+    unsigned int i;
+    sample accum;
+
+    for (i = 1, accum = operands[0]; i < operandCt; ++i) {
+        accum |= operands[i];
+    }
+    return accum;
+}
+
+
+
+static sample
+sampleNand(sample       const operands[],
+           unsigned int const operandCt,
+           sample       const maxval) {
+
+    unsigned int i;
+    sample accum;
+
+    for (i = 1, accum = operands[0]; i < operandCt; ++i) {
+        accum &= operands[i];
+    }
+    return ~accum & maxval;
+}
+
+
+
+static sample
+sampleNor(sample       const operands[],
+          unsigned int const operandCt,
+          sample       const maxval) {
+
+    unsigned int i;
+    sample accum;
+
+    for (i = 1, accum = operands[0]; i < operandCt; ++i) {
+        accum |= operands[i];
+    }
+    return ~accum & maxval;
+}
+
+
+
+static sample
+sampleXor(sample       const operands[],
+          unsigned int const operandCt) {
+
+    unsigned int i;
+    sample accum;
+
+    for (i = 1, accum = operands[0]; i < operandCt; ++i) {
+        accum ^= operands[i];
+    }
+    return accum;
 }
 
 
 
 static sample
 applyUnNormalizedFunction(enum function const function,
-                          sample        const leftArg,
-                          sample        const rightArg,
+                          sample        const operands[],
+                          unsigned int  const operandCt,
                           sample        const maxval) {
 /*----------------------------------------------------------------------------
-   Apply dyadic function 'function' to the arguments 'leftArg' and
-   'rightArg', assuming both are based on the same maxval 'maxval'.
-   Return a value which is also a fraction of 'maxval'.
+   Apply function 'function' to the arguments operands[] (there are
+   'operandCt' of them), assuming both are based on the same maxval
+   'maxval'.  Return a value which is also a fraction of 'maxval'.
 
-   Exception: for the shift operations, 'rightArg' is not based on any
+   Exception: for the shift operations, operands[1] is not based on any
    maxval.  It is an absolute bit count.
+
+   We assume 'operandCount' is sensible for 'function'.  E.g. if
+   'function' is FN_DIFFERENCE, 'operandCt' is 2.
+
+   For a function that has a concept of left and right argument,
+   operands[0] is the left and operands[1] is the right.
 -----------------------------------------------------------------------------*/
     sample result;
 
     switch (function) {
     case FN_ADD:
-        result = MIN(maxval, leftArg + rightArg);
+        result = sampleSum(operands, operandCt, maxval);
         break;
     case FN_SUBTRACT:
-        result = MAX(0, (int)leftArg - (int)rightArg);
+        result = MAX(0, (int)operands[0] - (int)operands[1]);
         break;
     case FN_DIFFERENCE:
-        result = leftArg > rightArg ? leftArg - rightArg : rightArg - leftArg;
+        result = operands[0] > operands[1] ?
+            operands[0] - operands[1] : operands[1] - operands[0];
         break;
     case FN_MINIMUM:
-        result = MIN(leftArg, rightArg);
+        result = sampleMin(operands, operandCt);
         break;
     case FN_MAXIMUM:
-        result = MAX(leftArg, rightArg);
+        result = sampleMax(operands, operandCt);
         break;
     case FN_MEAN:
-        result = (leftArg + rightArg + 1) / 2;
+        result = sampleMean(operands, operandCt);
         break;
     case FN_COMPARE:
-        result = leftArg > rightArg ? 2 : leftArg < rightArg ? 0 : 1;
+        result = operands[0] > operands[1] ?
+            2 : operands[0] < operands[1] ? 0 : 1;
         break;
     case FN_MULTIPLY:
-        result = (leftArg * rightArg + maxval/2) / maxval;
+        result = sampleProduct(operands, operandCt, maxval);
         break;
     case FN_DIVIDE:
-        result = (rightArg > leftArg) ?
-            (leftArg * maxval + rightArg/2) / rightArg : maxval;
+        result = (operands[1] > operands[0]) ?
+            ROUNDDIV(operands[0] * maxval, operands[1]) : maxval;
         break;
 
     case FN_AND:
-        result = leftArg & rightArg;
+        result = sampleAnd(operands, operandCt);
         break;
     case FN_OR:
-        result = leftArg | rightArg;
+        result = sampleOr(operands, operandCt);
         break;
     case FN_NAND:
-        result = ~(leftArg & rightArg) & maxval;
+        result = sampleNand(operands, operandCt, maxval);
         break;
     case FN_NOR:
-        result = ~(leftArg | rightArg) & maxval;
+        result = sampleNor(operands, operandCt, maxval);
         break;
     case FN_XOR:
-        result = leftArg ^ rightArg;
+        result = sampleXor(operands, operandCt);
         break;
     case FN_SHIFTLEFT:
-        result = (leftArg << rightArg) & maxval;
+        result = (operands[0] << operands[1]) & maxval;
         break;
     case FN_SHIFTRIGHT:
-        result = leftArg >> rightArg;
+        result = operands[0] >> operands[1];
         break;
     default:
         pm_error("Internal error.  applyUnNormalizedFunction() called "
@@ -400,18 +701,22 @@ doUnNormalizedArith(struct pam *  const inpam1P,
    maxval to do the computation without time-consuming normalization of
    sample values.
 -----------------------------------------------------------------------------*/
+    unsigned int const operandCt = 2;
     sample const maxval = outpamP->maxval;
 
     tuple * tuplerow1;
     tuple * tuplerow2;
     tuple * tuplerowOut;
     unsigned int row;
+    sample * operands;
 
     /* Input conditions: */
     assert(inpam1P->maxval == maxval);
     assert(inpam2P->maxval == maxval);
     assert(outpamP->maxval == maxval);
 
+    MALLOCARRAY_NOFAIL(operands, operandCt);
+
     tuplerow1   = pnm_allocpamrow(inpam1P);
     tuplerow2   = pnm_allocpamrow(inpam2P);
     tuplerowOut = pnm_allocpamrow(outpamP);
@@ -428,10 +733,11 @@ doUnNormalizedArith(struct pam *  const inpam1P,
                 unsigned int const plane1 = MIN(outplane, inpam1P->depth-1);
                 unsigned int const plane2 = MIN(outplane, inpam2P->depth-1);
 
+                operands[0] = tuplerow1[col][plane1];
+                operands[1] = tuplerow2[col][plane2];
+
                 tuplerowOut[col][outplane] = 
-                    applyUnNormalizedFunction(function, 
-                                              tuplerow1[col][plane1], 
-                                              tuplerow2[col][plane2],
+                    applyUnNormalizedFunction(function, operands, operandCt,
                                               maxval);
 
                 assert(tuplerowOut[col][outplane] >= 0);
@@ -444,12 +750,14 @@ doUnNormalizedArith(struct pam *  const inpam1P,
     pnm_freepamrow(tuplerow1);
     pnm_freepamrow(tuplerow2);
     pnm_freepamrow(tuplerowOut);
+
+    free(operands);
 }
 
 
 
 int
-main(int argc, char *argv[]) {
+main(int argc, const char *argv[]) {
 
     struct cmdlineInfo cmdline;
     struct pam inpam1;
@@ -458,12 +766,17 @@ main(int argc, char *argv[]) {
     FILE * if1P;
     FILE * if2P;
     
-    pnm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
-    if1P = pm_openr(cmdline.input1Filespec);
-    if2P = pm_openr(cmdline.input2Filespec);
+    if (cmdline.operandCt != 2)
+        /* Code for > 2 operands not written yet */
+        pm_error("You specified %u operands.  We understand only 2.",
+                 cmdline.operandCt);
+
+    if1P = pm_openr(cmdline.operandFileNames[0]);
+    if2P = pm_openr(cmdline.operandFileNames[1]);
 
     pnm_readpaminit(if1P, &inpam1, PAM_STRUCT_SIZE(tuple_type));
     pnm_readpaminit(if2P, &inpam2, PAM_STRUCT_SIZE(tuple_type));
diff --git a/other/pambayer.c b/other/pambayer.c
index 9c58a3f4..f8ce0db8 100644
--- a/other/pambayer.c
+++ b/other/pambayer.c
@@ -25,6 +25,7 @@
 #include <unistd.h>
 #include <stdio.h>
 
+#include "pm_c_util.h"
 #include "pam.h"
 #include "shhopt.h"
 #include "mallocvar.h"
diff --git a/other/pamchannel.c b/other/pamchannel.c
index ac7bae65..64ab728b 100644
--- a/other/pamchannel.c
+++ b/other/pamchannel.c
@@ -13,6 +13,7 @@
 
 #include <string.h>
 
+#include "pm_c_util.h"
 #include "pam.h"
 #include "shhopt.h"
 #include "mallocvar.h"
diff --git a/other/pamdepth.c b/other/pamdepth.c
index 0c4490ed..ee59a408 100644
--- a/other/pamdepth.c
+++ b/other/pamdepth.c
@@ -11,8 +11,9 @@
 =============================================================================*/
 #include <assert.h>
 
-#include "shhopt.h"
+#include "pm_c_util.h"
 #include "mallocvar.h"
+#include "shhopt.h"
 #include "pam.h"
 
 struct cmdlineInfo {
@@ -89,7 +90,7 @@ createSampleMap(sample   const oldMaxval,
     MALLOCARRAY_NOFAIL(sampleMap, oldMaxval+1);
 
     for (i = 0; i <= oldMaxval; ++i)
-        sampleMap[i] = (i * newMaxval + oldMaxval / 2) / oldMaxval;
+        sampleMap[i] = ROUNDDIV(i * newMaxval, oldMaxval);
 
     *sampleMapP = sampleMap;
 }
diff --git a/other/pamendian.c b/other/pamendian.c
index 16e1fe56..d82ebd38 100644
--- a/other/pamendian.c
+++ b/other/pamendian.c
@@ -1,5 +1,5 @@
 /******************************************************************************
-                              pnmendian
+                              pamendian
 *******************************************************************************
 
   Reverse the endianness of multi-byte samples in a Netpbm stream.
diff --git a/other/pamfixtrunc.c b/other/pamfixtrunc.c
new file mode 100644
index 00000000..6d71406f
--- /dev/null
+++ b/other/pamfixtrunc.c
@@ -0,0 +1,176 @@
+/*============================================================================
+                             pamfixtrunc
+==============================================================================
+  Fix a Netpbm image that has been truncated, e.g. by I/O error.
+
+  By Bryan Henderson, January 2007.
+
+  Contributed to the public domain by its author.
+
+============================================================================*/
+
+#include <setjmp.h>
+
+#include "pm_c_util.h"
+#include "pam.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+
+struct cmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char * inputFilespec;  /* Filespec of input file */
+    unsigned int verbose;
+};
+
+
+
+static void
+parseCommandLine(int argc, char ** const argv,
+                 struct cmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   Note that the file spec array we return is stored in the storage that
+   was passed to us as the argv array.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;
+
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+
+    MALLOCARRAY(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+
+    OPTENT3(0, "verbose",   OPT_FLAG,    NULL, &cmdlineP->verbose,       0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We don't parms that are negative numbers */
+
+    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (argc-1 == 0) 
+        cmdlineP->inputFilespec = "-";
+    else if (argc-1 != 1)
+        pm_error("Program takes zero or one argument (filename).  You "
+                 "specified %d", argc-1);
+    else
+        cmdlineP->inputFilespec = argv[1];
+}
+
+
+
+static unsigned int readErrRow;
+static bool readErrVerbose;
+
+static pm_usererrormsgfn discardMsg;
+
+static void
+discardMsg(const char * const msg) {
+    if (readErrVerbose)
+        pm_message("Error reading row %u: %s", readErrRow, msg);
+}
+
+
+
+static void
+countRows(const struct pam * const inpamP,
+          bool               const verbose,
+          unsigned int *     const goodRowCountP) {
+
+    tuple * tuplerow;
+    unsigned int row;
+    jmp_buf jmpbuf;
+    int rc;
+    unsigned int goodRowCount;
+    
+    tuplerow = pnm_allocpamrow(inpamP);
+
+    pm_setusererrormsgfn(discardMsg);
+
+    rc = setjmp(jmpbuf);
+    if (rc == 0) {
+        pm_setjmpbuf(&jmpbuf);
+
+        readErrVerbose = verbose;
+        goodRowCount = 0;  /* initial value */
+        for (row = 0; row < inpamP->height; ++row) {
+            readErrRow = row;
+            pnm_readpamrow(inpamP, tuplerow);
+            /* The above does not return if it can't read the next row from
+               the file.  Instead, it longjmps out of this loop.
+            */
+            ++goodRowCount;
+        }
+    }
+    *goodRowCountP = goodRowCount;
+
+    pnm_freepamrow(tuplerow);
+}
+
+
+
+static void
+copyGoodRows(const struct pam * const inpamP,
+             FILE *             const ofP,
+             unsigned int       const goodRowCount) {
+
+    struct pam outpam;
+    tuple * tuplerow;
+    unsigned int row;
+
+    outpam = *inpamP;  /* initial value */
+
+    outpam.file = ofP;
+    outpam.height = goodRowCount;
+
+    tuplerow = pnm_allocpamrow(inpamP);
+
+    pnm_writepaminit(&outpam);
+
+    for (row = 0; row < outpam.height; ++row) {
+        pnm_readpamrow(inpamP, tuplerow);
+        pnm_writepamrow(&outpam, tuplerow);
+    }
+    
+    pnm_freepamrow(tuplerow);
+}
+
+
+
+int
+main(int argc, char * argv[]) {
+    struct cmdlineInfo cmdline;
+    struct pam inpam;
+    FILE * ifP;
+    pm_filepos rasterPos;
+    unsigned int goodRowCount;
+
+    pnm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr_seekable(cmdline.inputFilespec);
+
+    pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
+
+    pm_tell2(ifP, &rasterPos, sizeof(rasterPos));
+
+    countRows(&inpam, cmdline.verbose, &goodRowCount);
+
+    pm_message("Copying %u good rows; %u bottom rows missing",
+               goodRowCount, inpam.height - goodRowCount);
+    
+    pm_seek2(ifP, &rasterPos, sizeof(rasterPos));
+
+    copyGoodRows(&inpam, stdout, goodRowCount);
+
+    pm_close(inpam.file);
+    
+    return 0;
+}
+
+
diff --git a/other/pamlookup.c b/other/pamlookup.c
index 2651d596..3b7a7f59 100644
--- a/other/pamlookup.c
+++ b/other/pamlookup.c
@@ -13,6 +13,7 @@
 
 ============================================================================*/
 
+#include "pm_c_util.h"
 #include "pam.h"
 #include "shhopt.h"
 #include "pm_system.h"
diff --git a/other/pampick.c b/other/pampick.c
index 5502a3cb..63f32968 100644
--- a/other/pampick.c
+++ b/other/pampick.c
@@ -12,6 +12,7 @@
 #include <string.h>
 #include <stdio.h>
 
+#include "pm_c_util.h"
 #include "pam.h"
 #include "shhopt.h"
 #include "nstring.h"
diff --git a/other/pamsplit.c b/other/pamsplit.c
index b9ff6247..a03353d7 100644
--- a/other/pamsplit.c
+++ b/other/pamsplit.c
@@ -14,6 +14,8 @@
 
 #include <string.h>
 #include <stdio.h>
+
+#include "pm_c_util.h"
 #include "pam.h"
 #include "shhopt.h"
 #include "nstring.h"
diff --git a/other/pamstack.c b/other/pamstack.c
index d9691f74..d826cf1f 100644
--- a/other/pamstack.c
+++ b/other/pamstack.c
@@ -14,6 +14,7 @@
 
 #include <string.h>
 
+#include "pm_c_util.h"
 #include "mallocvar.h"
 #include "nstring.h"
 #include "shhopt.h"
diff --git a/other/pamsummcol.c b/other/pamsummcol.c
index c2c3e46b..c31a9940 100644
--- a/other/pamsummcol.c
+++ b/other/pamsummcol.c
@@ -10,6 +10,7 @@
 
 ******************************************************************************/
 
+#include "pm_c_util.h"
 #include "pam.h"
 #include "shhopt.h"
 #include "mallocvar.h"
diff --git a/other/pamx/Makefile b/other/pamx/Makefile
index baff506d..a40ea3a6 100644
--- a/other/pamx/Makefile
+++ b/other/pamx/Makefile
@@ -5,11 +5,12 @@ endif
 SUBDIR = other/pamx
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
-include $(BUILDDIR)/Makefile.config
+include $(BUILDDIR)/config.mk
 
+EXTERN_INCLUDE =
 ifneq ($(X11LIB),NONE)
   ifneq ($(X11HDR_DIR),)
-    INCLUDES += -I$(X11HDR_DIR)
+    EXTERN_INCLUDES += -I$(X11HDR_DIR)
   endif
 endif
 
@@ -36,7 +37,7 @@ MERGEBINARIES = $(BINARIES)
 
 all: $(BINARIES)
 
-include $(SRCDIR)/Makefile.common
+include $(SRCDIR)/common.mk
 
 pamx: $(PAMX_OBJECTS) $(NETPBMLIB) $(LIBOPT)
 	$(LD) -o $@ $(PAMX_OBJECTS) \
diff --git a/other/pamx/Makefile2 b/other/pamx/Makefile2
deleted file mode 100644
index f69e103f..00000000
--- a/other/pamx/Makefile2
+++ /dev/null
@@ -1,51 +0,0 @@
-# C compiler to use, including special flags.
-CC=gcc
-
-WARNINGS = -Wall -Wmissing-declarations -Wundef -Wimplicit -Wwrite-strings \
-	-Winline \
-	-Wstrict-prototypes -Wmissing-prototypes \
-	-Werror
-
-CFLAGS = $(WARNINGS) -fno-common -g
-INCLUDES = -I /home/bryanh/netpbm/other/importinc
-
-# X11 include and library information.
-X11_LIB_DIR=-L/subsysx/X11R6/lib
-X11_LIB_NAME=-lX11
-NETPBMLIB = /home/bryanh/netpbm/lib/libnetpbm.so
-
-LIBS=$(X11_LIB_DIR) $(X11_LIB_NAME) -lm
-
-default: pamx
-
-# files for the image library
-IMAGE_SRCS= image.c
-IMAGE_OBJS= ${IMAGE_SRCS:.c=.o}
-
-# files for the image processing library
-PROCESS_HDRS=
-# no image processing.
-PROCESS_SRCS= fill.c
-PROCESS_OBJS= ${PROCESS_SRCS:.c=.o}
-
-X_SRCS= send.c window.c pamx.c
-X_OBJS= ${X_SRCS:.c=.o}
-
-OBJS= $(IMAGE_OBJS) $(PROCESS_OBJS) $(X_OBJS) $(NETPBMLIB)
-
-.c.o: $*.c
-	$(CC) -c $(CFLAGS) $(INCLUDES) $*.c $(CADD)
-
-pamx: $(OBJS) $(OPTIONAL_LIBS)
-	$(CC) -o $@ $(OBJS) $(OPTIONAL_LIBS) $(LIBS)
-
-clean::
-	rm -f *.o pamx
-
-dep:
-	$(CC) -MM -MG $(INCLUDES) *.c >Makefile.depend
-
-include Makefile.depend
-
-Makefile.depend:
-	>$@
diff --git a/other/pamx/image.c b/other/pamx/image.c
index 892a9768..0e719438 100644
--- a/other/pamx/image.c
+++ b/other/pamx/image.c
@@ -237,95 +237,3 @@ freeImage(Image * const imageP) {
 
     free(imageP);
 }
-
-
-
-
-static void
-fillRow1(struct pam *     const pamP,
-         tuple *          const tuplerow,
-         unsigned char ** const pP) {
-
-    unsigned int col;
-    
-    for (col = 0; col < pamP->width; ++col) {
-        unsigned int plane;
-        for (plane = 0; plane < pamP->depth; ++plane)
-            *(*pP)++ =
-                pnm_scalesample(tuplerow[col][0], pamP->maxval, 255);
-    }
-}
-
-
-
-static void
-fillRow3(struct pam *     const pamP,
-         tuple *          const tuplerow,
-         unsigned char ** const pP) {
-
-    unsigned int col;
-    
-    for (col = 0; col < pamP->width; ++col) {
-        unsigned int plane;
-        for (plane = 0; plane < pamP->depth; ++plane)
-            *(*pP)++ =
-                pnm_scalesample(tuplerow[col][plane], pamP->maxval, 255);
-    }
-}
-
-
-
-Image *
-pbmLoad(const char * const fullname,
-        const char * const name,
-        bool         const verbose) {
-
-    FILE * ifP;
-    struct pam pam;
-    Image * imageP;
-    unsigned int row;
-    const char * filename;
-    tuple * tuplerow;
-    unsigned char * p;
-    enum {DEPTH_1, DEPTH_3} depth;
-
-    if (STREQ(fullname, "stdin"))
-        filename = "-";
-    else
-        filename = fullname;
-
-    ifP = pm_openr(filename);
-
-    pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(tuple_type));
-
-    if (strncmp(pam.tuple_type, "RGB", 3) == 0) {
-        depth = DEPTH_3;
-        if (pam.depth < 3)
-            pm_error("Invalid depth %u for RGB tuple type.", pam.depth);
-    } else
-        depth = DEPTH_1;
-
-    imageP = newTrueImage(pam.width, pam.height);
-
-    p = &imageP->data[0];  /* initial value */
-
-    tuplerow = pnm_allocpamrow(&pam);
-
-    for (row = 0; row < pam.height; ++row) {
-        pnm_readpamrow(&pam, tuplerow);
-        
-        switch (depth) {
-        case DEPTH_3:
-            fillRow3(&pam, tuplerow, &p);
-            break;
-        case DEPTH_1:
-            fillRow1(&pam, tuplerow, &p);
-            break;
-        }
-    }
-    pnm_freepamrow(tuplerow);
-    
-    pm_close(ifP);
-
-    return imageP;
-}
diff --git a/other/pamx/image.h b/other/pamx/image.h
index ea597b2e..5b352a28 100644
--- a/other/pamx/image.h
+++ b/other/pamx/image.h
@@ -81,9 +81,4 @@ colorIntensity(unsigned int const red,
             BlueIntensity[blu / 256]);
 }
 
-Image *
-pbmLoad(const char * const fullname,
-        const char * const name,
-        bool         const verbose);
-
 #endif
diff --git a/other/pamx/pamx.c b/other/pamx/pamx.c
index 5fd525b7..130cc64c 100644
--- a/other/pamx/pamx.c
+++ b/other/pamx/pamx.c
@@ -9,6 +9,7 @@
 #include <errno.h>
 #include <string.h>
 
+#include "pm_c_util.h"
 #include "pam.h"
 #include "shhopt.h"
 #include "mallocvar.h"
@@ -176,35 +177,32 @@ errorHandler(Display *     const disp,
 
 
 
-static void
-fillRow1(struct pam *     const pamP,
-         tuple *          const tuplerow,
-         unsigned char ** const pP) {
-
-    unsigned int col;
-    
-    for (col = 0; col < pamP->width; ++col) {
-        unsigned int plane;
-        for (plane = 0; plane < 3; ++plane)
-            *(*pP)++ =
-                pnm_scalesample(tuplerow[col][0], pamP->maxval, 255);
-    }
-}
-
-
+enum usableDepth {DEPTH_1, DEPTH_3};
 
 static void
-fillRow3(struct pam *     const pamP,
-         tuple *          const tuplerow,
-         unsigned char ** const pP) {
+fillRow(struct pam *     const pamP,
+        tuple *          const tuplerow,
+        enum usableDepth const depth,
+        unsigned char ** const pP) {
+/*----------------------------------------------------------------------------
+   Add one row to the 24-bit truecolor image data at *pP, and advance
+   *pP just past that row.
 
+   Use either the first plane or the first 3 planes of tuplerow[]
+   for its contents, according to 'depth'.
+-----------------------------------------------------------------------------*/
     unsigned int col;
     
     for (col = 0; col < pamP->width; ++col) {
+        /* Truecolor image data has 3 bytes per pixel, one each for
+           red, green, and blue.
+        */
         unsigned int plane;
-        for (plane = 0; plane < pamP->depth; ++plane)
+        for (plane = 0; plane < 3; ++plane) {
+            unsigned int const tuplePlane = depth == DEPTH_3 ? plane : 0;
             *(*pP)++ =
-                pnm_scalesample(tuplerow[col][plane], pamP->maxval, 255);
+                pnm_scalesample(tuplerow[col][tuplePlane], pamP->maxval, 255);
+        }
     }
 }
 
@@ -219,7 +217,7 @@ loadPamImage(FILE *   const ifP,
     unsigned int row;
     tuple * tuplerow;
     unsigned char * p;
-    enum {DEPTH_1, DEPTH_3} depth;
+    enum usableDepth depth;
 
     pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(tuple_type));
 
@@ -239,12 +237,17 @@ loadPamImage(FILE *   const ifP,
     for (row = 0; row < pam.height; ++row) {
         pnm_readpamrow(&pam, tuplerow);
         
+        /* This semantically wasteful code allows a dumb compiler
+           optimizer to recognize that the depth is constant and
+           therefore not generate code that checks the depth every
+           time it processes a sample.
+        */
         switch (depth) {
         case DEPTH_3:
-            fillRow3(&pam, tuplerow, &p);
+            fillRow(&pam, tuplerow, DEPTH_3, &p);
             break;
         case DEPTH_1:
-            fillRow1(&pam, tuplerow, &p);
+            fillRow(&pam, tuplerow, DEPTH_1, &p);
             break;
         }
     }
@@ -297,7 +300,7 @@ determineTitle(struct cmdlineInfo const cmdline,
     if (cmdline.title)
         title = strdup(cmdline.title);
     else {
-        if (STREQ(cmdline.inputFileName, "-"))
+        if (streq(cmdline.inputFileName, "-"))
             title = NULL;
         else {
             title = pm_basename(cmdline.inputFileName);
diff --git a/other/pamx/window.c b/other/pamx/window.c
index 1a6e510b..2eb48241 100644
--- a/other/pamx/window.c
+++ b/other/pamx/window.c
@@ -6,6 +6,8 @@
    See COPYRIGHT file for copyright information.
 */
 
+#define _BSD_SOURCE    /* Make sure strcaseeq() is in nstring.h */
+
 #include <assert.h>
 #include <ctype.h>
 #include <signal.h>
@@ -555,7 +557,7 @@ visualClassFromName(const char * const name) {
     bool found;
     
     for (a = 0, found = FALSE; VisualClassName[a].name; ++a) {
-        if (STRCASEEQ(VisualClassName[a].name, name)) {
+        if (strcaseeq(VisualClassName[a].name, name)) {
             /* Check for uniqueness.  We special-case StaticGray
                because we have two spellings but they are unique if
                we find either.
diff --git a/other/pnmcolormap.c b/other/pnmcolormap.c
index 1be54ef8..42b03063 100644
--- a/other/pnmcolormap.c
+++ b/other/pnmcolormap.c
@@ -26,11 +26,12 @@
 #include <math.h>
 
 #include "pm_config.h"
-#include "pam.h"
-#include "pammap.h"
-#include "shhopt.h"
+#include "pm_c_util.h"
 #include "mallocvar.h"
 #include "nstring.h"
+#include "shhopt.h"
+#include "pam.h"
+#include "pammap.h"
 
 enum methodForLargest {LARGE_NORM, LARGE_LUM};
 
@@ -380,7 +381,7 @@ averageColors(int          const boxStart,
         for (i = 0; i < boxSize; ++i) 
             sum += colorfreqtable.table[boxStart+i]->tuple[plane];
 
-        newTuple[plane] = sum / boxSize;
+        newTuple[plane] = ROUNDDIV(sum, boxSize);
     }
 }
 
@@ -414,7 +415,7 @@ averagePixels(int          const boxStart,
             sum += colorfreqtable.table[boxStart+i]->tuple[plane]
                 * colorfreqtable.table[boxStart+i]->value;
 
-        newTuple[plane] = sum / n;
+        newTuple[plane] = ROUNDDIV(sum, n);
     }
 }
 
@@ -631,7 +632,7 @@ validateCompatibleImage(struct pam * const inpamP,
     if (inpamP->format != firstPamP->format)
         pm_error("Image %u format (%d) is not the same as Image 0 (%d)",
                  imageSeq, inpamP->format, firstPamP->format);
-    if (!STREQ(inpamP->tuple_type, firstPamP->tuple_type))
+    if (!streq(inpamP->tuple_type, firstPamP->tuple_type))
         pm_error("Image %u tuple type (%s) is not the same as Image 0 (%s)",
                  imageSeq, inpamP->tuple_type, firstPamP->tuple_type);
 }
diff --git a/other/ppmsvgalib.c b/other/ppmsvgalib.c
index 67cc2b1a..5bcabdc1 100644
--- a/other/ppmsvgalib.c
+++ b/other/ppmsvgalib.c
@@ -16,6 +16,8 @@
 #include <errno.h>
 #include <signal.h>
 #include <unistd.h>
+
+#include "pm_c_util.h"
 #include "ppm.h"
 #include "shhopt.h"
 
@@ -249,7 +251,7 @@ main(int argc, char *argv[]) {
     int format;
     int rc;
 
-    ppm_init( &argc, argv );
+    ppm_init(&argc, argv);
 
     rc = vga_init();         /* Initialize. */
     if (rc < 0)