about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--GNUmakefile10
-rw-r--r--converter/ppm/sldtoppm.c220
-rw-r--r--doc/HISTORY10
-rwxr-xr-xtest/Execute-Tests56
-rw-r--r--test/Makefile10
-rw-r--r--test/fiasco-roundtrip.ok2
-rwxr-xr-xtest/fiasco-roundtrip.test7
-rw-r--r--test/jpeg-roundtrip.ok6
-rwxr-xr-xtest/jpeg-roundtrip.test17
-rwxr-xr-xtest/jpeg2k-roundtrip.test2
-rw-r--r--test/palm-roundtrip.ok9
-rwxr-xr-xtest/palm-roundtrip.test9
-rwxr-xr-xtest/pamtopdbimg.test17
-rw-r--r--test/pgmnoise.rand-ok3
-rwxr-xr-xtest/pgmnoise.test22
-rw-r--r--test/ppmforge.rand-ok3
-rwxr-xr-xtest/ppmforge.test17
-rw-r--r--test/ppmpat-random.rand-ok7
-rwxr-xr-xtest/ppmpat-random.test30
-rw-r--r--test/ppmrough.rand-ok3
-rwxr-xr-xtest/ppmrough.test15
-rw-r--r--test/testrandom.c30
-rw-r--r--test/tiffcmyk-roundtrip.ok10
-rwxr-xr-xtest/tiffcmyk-roundtrip.test25
-rw-r--r--version.mk4
25 files changed, 316 insertions, 228 deletions
diff --git a/GNUmakefile b/GNUmakefile
index e5914648..c2139d2a 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -527,8 +527,12 @@ resultdir-backup: FORCE
 	fi; \
 	mkdir -p $(RESULTDIR); \
 
+.PHONY: testdir test
 
-check-tree: $(TESTRANDOM) resultdir-backup
+testdir:
+	$(MAKE) -C test
+
+check-tree: testdir resultdir-backup
 	cd $(RESULTDIR); \
 	  $(CHECK_VARS) \
 	  CHECK_TYPE=tree \
@@ -549,7 +553,7 @@ check-package : RGBDEF ?= $(PKGDIR)/misc/rgb.txt
 check-package : PALMMAPDIR ?= $(PKGDIR)/misc/
 check: check-package
 
-check-package: $(TESTRANDOM) resultdir-backup
+check-package: testdir resultdir-backup
 	cd $(RESULTDIR); \
 	  $(CHECK_VARS) \
 	  CHECK_TYPE=package \
@@ -560,7 +564,7 @@ check-package: $(TESTRANDOM) resultdir-backup
 
 # Check after install
 check-install: PALMMAPDIR ?= ""
-check-install: $(TESTRANDOM) resultdir-backup
+check-install: testdir resultdir-backup
 	cd $(RESULTDIR); \
 	  $(CHECK_VARS) \
 	  CHECK_TYPE=install \
diff --git a/converter/ppm/sldtoppm.c b/converter/ppm/sldtoppm.c
index 550eed5b..5ce92c2b 100644
--- a/converter/ppm/sldtoppm.c
+++ b/converter/ppm/sldtoppm.c
@@ -50,7 +50,7 @@ struct spoint {
 
 /* Screen polygon */
 
-struct spolygon { 
+struct spolygon {
     int npoints,              /* Number of points in polygon */
           fill;           /* Fill type */
     struct spoint pt[11];         /* Actual points */
@@ -130,7 +130,7 @@ sli(void) {
 
 /*  SLIB  --  Input byte from slide file  */
 
-static int 
+static int
 slib(void) {
     unsigned char ch;
 
@@ -154,85 +154,127 @@ vscale(int * const px,
 
 
 
+static void
+upcase(const char * const sname,
+       char *       const uname) {
+
+    unsigned int i;
+    const char * ip;
+
+    for (i = 0, ip = sname; i < 31; ++i) {
+        char const ch = *ip++;
+
+        if (ch != EOS)
+            uname[i] = islower(ch) ? toupper(ch) : ch;
+    }
+    uname[i] = EOS;
+}
+
+
+
+static void
+skipBytes(FILE *       const fileP,
+          unsigned int const count) {
+
+    unsigned int i;
+
+    for (i = 0; i < count; ++i)
+        getc(fileP);
+}
+
+
+
+static void
+scanDirectory(FILE *       const slFileP,
+              long         const dirPos,
+              bool         const dirOnly,
+              const char * const uname,
+              bool *       const foundP) {
+/*----------------------------------------------------------------------------
+   Scan the directory at the current position in *slFileP, either listing
+   the directory ('dirOnly' true) or searching for a slide named
+   'uname' ('dirOnly' false).
+
+   'dirPos' is the offset in the file of the directory, i.e. the current
+   position of *slFileP.
+
+   In the latter case, return as *foundP whether the slide name is there.
+-----------------------------------------------------------------------------*/
+    bool found;
+    bool eof;
+    long pos;
+    unsigned char libent[36];
+
+    for (found = false, eof = false, pos = dirPos; !found && !eof; ) {
+        size_t readCt;
+        readCt = fread(libent, 36, 1, slFileP);
+        if (readCt != 1)
+            eof = true;
+        else {
+            /* The directory entry is 32 bytes of NUL-terminated slide name
+               followed by 4 bytes of offset of the next directory entry.
+            */
+            const char * const slideName = (const char *)(&libent[0]);
+            if (strnlen(slideName, 32) == 32)
+                pm_error("Invalid input: slide name field is not "
+                         "nul-terminated");
+            else {
+                if (strlen(slideName) == 0)
+                    eof = true;
+                else {
+                    pos += 36;
+                    if (dirOnly) {
+                        pm_message("  %s", slideName);
+                    } else if (streq(slideName, uname)) {
+                        long const dpos =
+                            (((((libent[35] << 8) | libent[34]) << 8) |
+                              libent[33]) << 8) | libent[32];
+
+                        if ((slFileP == stdin) ||
+                            (fseek(slFileP, dpos, 0) == -1)) {
+
+                            skipBytes(slFileP, dpos - pos);
+                        }
+                        found = true;
+                    }
+                }
+            }
+        }
+    }
+    *foundP = found;
+}
+
 /*  SLIDEFIND  --  Find  a  slide  in  a  library  or,  if  DIRONLY is
            nonzero, print a directory listing of the  library.
            If  UCASEN  is nonzero, the requested slide name is
            converted to upper case. */
 
 static void
-slidefind(const char * const sname,
-          bool         const dironly,
+slidefind(const char * const slideName,
+          bool         const dirOnly,
           bool         const ucasen) {
 
-    char uname[32];
-    unsigned char libent[36];
-    long pos;
+    char uname[32];  /* upper case translation of 'slideName' */
+    char header[32]; /* (supposed) header read from file */
     bool found;
-    bool eof;
 
-    if (dironly)
+    if (dirOnly)
         pm_message("Slides in library:");
     else {
-        unsigned int i;
-        const char * ip;
-        
-        ip = sname; /* initial value */
-        
-        for (i = 0; i < 31; ++i) {
-            char const ch = *ip++;
-            if (ch == EOS)
-                break;
-
-            {
-                char const upperCh =
-                    ucasen && islower(ch) ? toupper(ch) : ch;
-                
-                uname[i] = upperCh;
-            }
-        }
-        uname[i] = EOS;
+        upcase(slideName, uname);
     }
-    
+
     /* Read slide library header and verify. */
-    
-    if ((fread(libent, 32, 1, slfile) != 1) ||
-        (!strneq((char *)libent, "AutoCAD Slide Library 1.0\015\012\32", 32))) {
+
+    if ((fread(header, 32, 1, slfile) != 1) ||
+        (!STRSEQ(header, "AutoCAD Slide Library 1.0\r\n\32"))) {
         pm_error("not an AutoCAD slide library file.");
     }
-    pos = 32;
-    
-    /* Search for a slide with the requested name or list the directory */
-    
-    for (found = false, eof = false; !found && !eof; ) {
-        size_t readCt;
-        readCt = fread(libent, 36, 1, slfile);
-        if (readCt != 1)
-            eof = true;
-        else if (strnlen((char *)libent, 32) == 0)
-            eof = true;
 
-        if (!eof) {
-            pos += 36;
-            if (dironly) {
-                pm_message("  %s", libent);
-            } else if (strneq((char *)libent, uname, 32)) {
-                long dpos;
-
-                dpos = (((((libent[35] << 8) | libent[34]) << 8) |
-                         libent[33]) << 8) | libent[32];
-        
-                if ((slfile == stdin) || (fseek(slfile, dpos, 0) == -1)) {
-                    dpos -= pos;
-
-                    while (dpos-- > 0)
-                        getc(slfile);
-                }
-                found = true;
-            }
-        }
-    }
-    if (!found && !dironly)
-        pm_error("slide '%s' not in library.", sname);
+    scanDirectory(slfile, 32, dirOnly, ucasen ? uname : slideName, &found);
+
+    if (!found && !dirOnly)
+        pm_error("slide '%s' not in library.", slideName);
 }
 
 
@@ -295,14 +337,14 @@ flood(struct spolygon * const poly,
         assert(poly->pt[i].x >= 0 && poly->pt[i].x < pixcols);
         assert(poly->pt[i].y >= 0 && poly->pt[i].y < pixrows);
         ppmd_line(pixels, pixcols, pixrows, pixmaxval,
-                  poly->pt[i].x, iydots - poly->pt[i].y, 
+                  poly->pt[i].x, iydots - poly->pt[i].y,
                   poly->pt[(i + 1) % poly->npoints].x,
                   iydots - poly->pt[(i + 1) % poly->npoints].y,
                   ppmd_fill_drawproc, handle);
     }
     ppmd_fill(pixels, pixcols, pixrows, pixmaxval,
               handle, PPMD_NULLDRAWPROC, (char *) &rgbcolor);
-    
+
     ppmd_fill_destroy(handle);
 }
 
@@ -333,11 +375,11 @@ slider(slvecfn   slvec,
     {"AutoCAD Slide\r\n\32", 86,2, 0,0, 0.0, 0};
     int curcolor = 7;             /* Current vector color */
     pixel rgbcolor;           /* Pixel used to clear pixmap */
-    
+
     lx = ly = 32000;
-    
+
     /* Process the header of the slide file.  */
-    
+
     sdrawkcab = false;            /* Initially guess byte order is OK */
     fread(slfrof.slh, 17, 1, slfile);
     fread(&slfrof.sntype, sizeof(char), 1, slfile);
@@ -361,12 +403,12 @@ slider(slvecfn   slvec,
         pm_error("incompatible slide file format");
 
     /* Build SDSAR value from long scaled version. */
-    
+
     ldsar = 0L;
     for (i = 3; i >= 0; --i)
         ldsar = (ldsar << 8) | ubfr[i];
     slfrof.sdsar = ((double) ldsar) / 1E7;
-    
+
     /* Examine the byte order test value.   If it's backwards, set the
        byte-reversal flag and correct all of the values we've read  in
        so far.
@@ -380,7 +422,7 @@ slider(slvecfn   slvec,
         rshort(slfrof.shwfill);
         #undef rshort
     }
-    
+
     /* Dump the header if we're blithering. */
 
     if (blither || info) {
@@ -455,29 +497,29 @@ slider(slvecfn   slvec,
         }
         iydots = sysize - 1;
     }
-    
+
     if (adjust) {
         pm_message(
             "Resized from %dx%d to %dx%d to correct pixel aspect ratio.",
             slfrof.sxdots + 1, slfrof.sydots + 1, ixdots + 1, iydots + 1);
     }
-    
+
     /* Allocate image buffer and clear it to black. */
-    
+
     pixels = ppm_allocarray(pixcols = ixdots + 1, pixrows = iydots + 1);
     PPM_ASSIGN(rgbcolor, 0, 0, 0);
     ppmd_filledrectangle(pixels, pixcols, pixrows, pixmaxval, 0, 0,
                          pixcols, pixrows, PPMD_NULLDRAWPROC,
                          (char *) &rgbcolor);
-    
+
     if ((rescale = slfrof.sxdots != ixdots ||
          slfrof.sydots != iydots ||
          slfrof.sdsar != dsar) != 0) {
-        
+
         /* Rescale all coords. so they'll look (more or less)
            right on this display.
         */
-        
+
         xfac = (ixdots + 1) * 0x10000L;
         xfac /= (long) (slfrof.sxdots + 1);
         yfac = (iydots + 1) * 0x10000L;
@@ -490,7 +532,7 @@ slider(slvecfn   slvec,
     }
 
     poly.npoints = 0;             /* No flood in progress. */
-    
+
     while ((cw = sli()) != 0xFC00) {
         switch (cw & 0xFF00) {
         case 0xFB00:          /*  Short vector compressed  */
@@ -508,10 +550,10 @@ slider(slvecfn   slvec,
             slx = vec.f.x;        /* Save scaled point */
             sly = vec.f.y;
             break;
-            
+
         case 0xFC00:          /*  End of file  */
             break;
-            
+
         case 0xFD00:          /*  Flood command  */
             vec.f.x = sli();
             vec.f.y = sli();
@@ -538,7 +580,7 @@ slider(slvecfn   slvec,
                 poly.npoints++;
             }
             break;
-            
+
         case 0xFE00:          /*  Common endpoint compressed  */
             vec.f.x = lx + extend(cw & 0xFF);
             vec.f.y = ly + slib();
@@ -553,7 +595,7 @@ slider(slvecfn   slvec,
             slx = vec.f.x;        /* Save scaled point */
             sly = vec.f.y;
             break;
-            
+
         case 0xFF00:          /*  Change color  */
             curcolor = cw & 0xFF;
             break;
@@ -661,7 +703,7 @@ main(int          argc,
     }
 
     /* If a file name is specified, open it.  Otherwise read from
-       standard input. 
+       standard input.
     */
 
     if (argn < argc) {
@@ -670,24 +712,24 @@ main(int          argc,
     } else {
         slfile = stdin;
     }
-    
+
     if (argn != argc) {           /* Extra bogus arguments ? */
         pm_usage(usage);
     }
-    
+
     /* If we're extracting an item from a slide library, position the
        input stream to the start of the chosen slide.
     */
- 
+
     if (dironly || slobber)
         slidefind(slobber, dironly, ucasen);
- 
+
     if (!dironly) {
         slider(draw, flood);
         ppm_writeppm(stdout, pixels, pixcols, pixrows, pixmaxval, 0);
     }
     pm_close(slfile);
     pm_close(stdout);
-    
+
     return 0;
 }
diff --git a/doc/HISTORY b/doc/HISTORY
index 5b39fb91..65d51e94 100644
--- a/doc/HISTORY
+++ b/doc/HISTORY
@@ -4,12 +4,7 @@ Netpbm.
 CHANGE HISTORY 
 --------------
 
-17.12.30 BJH  Release 10.80.02
-
-sldtoppm: fix bug: wild memory accesses, weird messages when
-              invalid input file has unterminated strings.
-              
-17.10.21 BJH  Release 10.80.01
+17.12.30 BJH  Release 10.81.00
 
               sldtoppm: -lib and -dir don't work - always says slide not
               found.  Broken in Netpbm 10.63 (June 2013).
@@ -18,6 +13,9 @@ sldtoppm: fix bug: wild memory accesses, weird messages when
               slide file.  Broken after Netpbm 10.26 (January 2005), but no
               later than 10.35 (August 2006).
 
+              sldtoppm: fix bug: wild memory accesses, weird messages when
+              invalid input file has unterminated strings.
+              
 17.09.30 BJH  Release 10.80.00
 
               pnmtopalm: Refuse to create a compressed image with more than 8
diff --git a/test/Execute-Tests b/test/Execute-Tests
index bf8ecb56..e69c84e7 100755
--- a/test/Execute-Tests
+++ b/test/Execute-Tests
@@ -237,30 +237,38 @@ if [ $VALGRIND_TESTS = "on" ]
 fi
 
 # Execute a single test and test its result.
-# But first see if the target programs and requirements are in place.
-
-${srcdir}/Available-Testprog \
-  `sed -n -e '/^# This script tests: /s/# This script tests: //p' \
-          -e '/^# Also requires: /s/^# Also requires: //p' \
-          -e '/^$/q' ${srcdir}/$tname | tr '\n' ' '`
-case $? in
-0)
-  PATH=${testpath} $vg_command ${srcdir}/$tname > ${tname%.test}.out;
-  let retval=$?
-  case $retval in
-  0)   cmp -s ${tname%.test}.out ${srcdir}/${tname%.test}.ok ;
-       if [ $? -eq 0 ]
-          then let result=0;  rm  ${tname%.test}.out ;
-          else let result=1;
-               grep "^##" ${srcdir}/$tname  # Print failure message.
-       fi ;;
-  80) let result=4 ;;
-  *)  let result=1 ;;
-  esac ;;
-
-1)   let result=4 ;;
-*)   let result=1 ;;
-esac
+# But first check if the .ok file exists.  (Some .ok files are
+# dynamically created.)  Then see if target programs and requirements
+# are in place.  If either of these conditions are not met, do
+# not execute the test and report "Not Testable".
+
+if [ ! -s ${srcdir}/${tname%.test}.ok ]
+then
+  let result=4;
+else
+  ${srcdir}/Available-Testprog \
+    `sed -n -e '/^# This script tests: /s/# This script tests: //p' \
+            -e '/^# Also requires: /s/^# Also requires: //p' \
+            -e '/^$/q' ${srcdir}/$tname | tr '\n' ' '`
+  case $? in
+  0)
+    PATH=${testpath} $vg_command ${srcdir}/$tname > ${tname%.test}.out;
+    let retval=$?
+    case $retval in
+    0)   cmp -s ${tname%.test}.out ${srcdir}/${tname%.test}.ok ;
+         if [ $? -eq 0 ]
+            then let result=0;  rm  ${tname%.test}.out ;
+            else let result=1;
+                 grep "^##" ${srcdir}/$tname  # Print failure message.
+         fi ;;
+    80) let result=4 ;;
+    *)  let result=1 ;;
+    esac ;;
+  
+  1)   let result=4 ;;
+  *)   let result=1 ;;
+  esac
+fi
 
 # Report whether a single test succeeded or failed.
 # Increment counters.
diff --git a/test/Makefile b/test/Makefile
index 9b7ab047..4f0c063f 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -10,7 +10,9 @@ MERGE_OBJECTS =
 
 PROGS = testrandom
 
-all: $(PROGS)
+OKSTOGENERATE = $(patsubst %.rand-ok, %.ok, $(wildcard *.rand-ok))
+
+all: $(PROGS) $(OKSTOGENERATE)
 
 testrandom.o: testrandom.c
 	$(CC_FOR_BUILD) -c -o $@ $(CFLAGS_FOR_BUILD) $<
@@ -18,6 +20,10 @@ testrandom.o: testrandom.c
 testrandom: testrandom.o
 	$(LD_FOR_BUILD) -o $@ $(LDFLAGS_FOR_BUILD) $<
 
+RAND_VARIETY ?= $(shell ./testrandom -x)
+
+$(OKSTOGENERATE): %.ok: %.rand-ok testrandom
+	sed -n "/^$(RAND_VARIETY)|/s/^$(RAND_VARIETY)|//p" $< > $@
 
 OMIT_TEST_RULE = 1
 include $(SRCDIR)/common.mk
@@ -25,4 +31,4 @@ include $(SRCDIR)/common.mk
 distclean clean: cleanlocal
 .PHONY: cleanlocal
 cleanlocal:
-	rm -f $(PROGS)
+	rm -f $(PROGS) $(OKSTOGENERATE)
diff --git a/test/fiasco-roundtrip.ok b/test/fiasco-roundtrip.ok
index 8a5e8ff6..544093d3 100644
--- a/test/fiasco-roundtrip.ok
+++ b/test/fiasco-roundtrip.ok
@@ -1 +1 @@
-  3 1 1 1
\ No newline at end of file
+  3 1000.00 1000.00 1000.00
\ No newline at end of file
diff --git a/test/fiasco-roundtrip.test b/test/fiasco-roundtrip.test
index 6fd43432..8325a37d 100755
--- a/test/fiasco-roundtrip.test
+++ b/test/fiasco-roundtrip.test
@@ -7,7 +7,7 @@
 # TODO: As in jpeg-rountrip.test the threshold has been determined
 # without much thought.
 
-# Should print 3 1 1 1
+# Should print 3 1000.00 1000.00 1000.00
 
 tmpdir=${tmpdir:-/tmp}
 padded_ppm=${tmpdir}/padded.ppm
@@ -15,6 +15,9 @@ padded_ppm=${tmpdir}/padded.ppm
 pnmpad --black --bottom 1 --left 1 testimg.ppm > ${padded_ppm} &&
 pnmtofiasco --progress-meter 0 ${padded_ppm} | fiascotopnm | \
     pnmpsnr -machine - ${padded_ppm} | \
-    awk '{printf("%3d %1d %1d %1d",NF,$1>14.0,$2>21.0,$3>$29.0)}'
+    awk '{printf("%3d %.2f %.2f %.2f", NF,
+                  $1>14.0 ? 1000.00 : $1,
+                  $2>21.0 ? 1000.00 : $2,
+                  $3>29.0 ? 1000.00 : $3) }'
 
 rm ${padded_ppm}
\ No newline at end of file
diff --git a/test/jpeg-roundtrip.ok b/test/jpeg-roundtrip.ok
index f32c58a2..9a93f216 100644
--- a/test/jpeg-roundtrip.ok
+++ b/test/jpeg-roundtrip.ok
@@ -1,3 +1,3 @@
-  3 1 1 1
-  3 1 1 1
-  3 1 1 1
+  3 1000.00 1000.00 1000.00
+  3 1000.00 1000.00 1000.00
+  3 1000.00 1000.00 1000.00
diff --git a/test/jpeg-roundtrip.test b/test/jpeg-roundtrip.test
index 1afc5423..23df6341 100755
--- a/test/jpeg-roundtrip.test
+++ b/test/jpeg-roundtrip.test
@@ -10,12 +10,23 @@
 
 pnmtojpeg testimg.ppm | jpegtopnm | \
   pnmpsnr -machine - testimg.ppm |\
-  awk '{printf("%3d %1d %1d %1d\n",NF,$1>55.0,$2>57.0,$3>48.0)}'
+  awk '{printf("%3d %.2f %.2f %.2f\n", NF,
+                $1>55.0 ? 1000.00 : $1,
+                $2>57.0 ? 1000.00 : $2,
+                $3>48.0 ? 1000.00 : $3) }'
+
 
 pnmtojpeg testimg.ppm -opt | jpegtopnm | \
   pnmpsnr -machine - testimg.ppm |\
-  awk '{printf("%3d %1d %1d %1d\n",NF,$1>55.0,$2>57.0,$3>48.0)}'
+  awk '{printf("%3d %.2f %.2f %.2f\n", NF,
+                $1>55.0 ? 1000.00 : $1,
+                $2>57.0 ? 1000.00 : $2,
+                $3>48.0 ? 1000.00 : $3) }'
+
 
 pnmtojpeg testimg.ppm -progressive | jpegtopnm | \
   pnmpsnr -machine - testimg.ppm |\
-  awk '{printf("%3d %1d %1d %1d\n",NF,$1>55.0,$2>57.0,$3>48.0)}'
\ No newline at end of file
+  awk '{printf("%3d %.2f %.2f %.2f\n", NF,
+                $1>55.0 ? 1000.00 : $1,
+                $2>57.0 ? 1000.00 : $2,
+                $3>48.0 ? 1000.00 : $3) }'
diff --git a/test/jpeg2k-roundtrip.test b/test/jpeg2k-roundtrip.test
index eab6fb1e..0995849d 100755
--- a/test/jpeg2k-roundtrip.test
+++ b/test/jpeg2k-roundtrip.test
@@ -1,6 +1,6 @@
 #! /bin/bash
 # This script tests: pamtojpeg2k jpeg2ktopam
-# Also requires: pnmpsnr
+# Also requires:
 
 # Should produce 1926073387 101484
 
diff --git a/test/palm-roundtrip.ok b/test/palm-roundtrip.ok
index 6c9114a4..5bd3cb0a 100644
--- a/test/palm-roundtrip.ok
+++ b/test/palm-roundtrip.ok
@@ -3,8 +3,7 @@
 584219238 236
 584219238 236
 584219238 236
-600373046 101484
-600373046 101484
-600373046 101484
-600373046 101484
-600373046 101484
+0
+0
+0
+0
diff --git a/test/palm-roundtrip.test b/test/palm-roundtrip.test
index 5570e968..9c053ba9 100755
--- a/test/palm-roundtrip.test
+++ b/test/palm-roundtrip.test
@@ -19,14 +19,17 @@ for flags in "" \
 rm ${test4bit_pgm}
 
 
-# Test 2. Should print 600373046 101484 5 times
+# Test 2. Should print 0 4 times
 
-pnmquant 256 testimg.ppm | tee ${test256color_ppm} | cksum
+pnmquant 256 testimg.ppm > ${test256color_ppm}
 
 for flags in "" \
              "-scanline_compression" \
              "-rle_compression" \
              "-packbits_compression" 
-  do pnmtopalm -colormap $flags ${test256color_ppm} | palmtopnm | cksum; done
+  do pnmtopalm -colormap $flags ${test256color_ppm} | palmtopnm | \
+     cmp -s - ${test256color_ppm} > /dev/null
+     echo $?
+  done
 
 rm ${test256color_ppm}
diff --git a/test/pamtopdbimg.test b/test/pamtopdbimg.test
index 267f6bc8..8de78a70 100755
--- a/test/pamtopdbimg.test
+++ b/test/pamtopdbimg.test
@@ -48,14 +48,20 @@ rm ${noise_pgm}
 # 0
 # 1
 # 0
+
+# Some versions of wc have extra whitespace in the output (e.g. MAC OS)
+# Delete with tr -d
+
 echo long titles 
 for flag in "" "-title=0123456789012345678901234567890" \
                "-title=01234567890123456789012345678901"
    do
-   pamtopdbimg $flag testgrid.pbm | wc -c ; echo ${PIPESTATUS[0]}
+   pamtopdbimg $flag testgrid.pbm | wc -c | tr -d ' '
+   echo ${PIPESTATUS[0]}
    done
 
 
+
 # Test 4. large notefile
 # Should succeed twice and fail once, producing:
 # 3344
@@ -76,11 +82,14 @@ awk 'BEGIN { ABC="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 
 head -c 65533 ${text65597} > ${text65533}
 head -c 65534 ${text65597} > ${text65534}
-pamtopdbimg -uncompressed testgrid.pbm | wc -c
+pamtopdbimg -uncompressed testgrid.pbm | \
+  wc -c | tr -d ' '
   echo ${PIPESTATUS[0]}
-pamtopdbimg -uncompressed -notefile=${text65533} testgrid.pbm | wc -c
+pamtopdbimg -uncompressed -notefile=${text65533} testgrid.pbm | \
+  wc -c | tr -d ' '
   echo ${PIPESTATUS[0]}
-pamtopdbimg -uncompressed -notefile=${text65534} testgrid.pbm | wc -c
+pamtopdbimg -uncompressed -notefile=${text65534} testgrid.pbm | \
+  wc -c | tr -d ' '
   echo ${PIPESTATUS[0]}
 
 rm ${text65533} ${text65534} ${text65597}
\ No newline at end of file
diff --git a/test/pgmnoise.rand-ok b/test/pgmnoise.rand-ok
new file mode 100644
index 00000000..b69f48e5
--- /dev/null
+++ b/test/pgmnoise.rand-ok
@@ -0,0 +1,3 @@
+000|0
+081|2005134911 10015
+082|3516404574 10015
diff --git a/test/pgmnoise.test b/test/pgmnoise.test
index 0b38553b..03301ce6 100755
--- a/test/pgmnoise.test
+++ b/test/pgmnoise.test
@@ -2,22 +2,6 @@
 # This script tests: pgmnoise
 # Also requires:
 
-
-# We first check whether random number generator is glibc rand().
-# If not, this test is skipped.
-
-testrandom
-
-case $? in
-   81)
-        # Should print: 1663614689 10015
-        pgmnoise --randomseed=0 100 100 | cksum ;;
-
-        # Any additional tests go here.
-
-   8[02-9] | 90)
-        echo "Skipping: random number generator is not glibc." 1>&2
-        exit 80;;
-
-   *)   exit 1;;  # testrandom failed
-esac
+# Should print: 1663614689 10015 (Glibc)
+#               3516404574 10015 (MAC OS)
+pgmnoise --randomseed=0 100 100 | cksum
diff --git a/test/ppmforge.rand-ok b/test/ppmforge.rand-ok
new file mode 100644
index 00000000..c8b3ac9f
--- /dev/null
+++ b/test/ppmforge.rand-ok
@@ -0,0 +1,3 @@
+000|0
+081|3634219838 196623
+082|3262664440 196623
diff --git a/test/ppmforge.test b/test/ppmforge.test
index 65280d14..3ebea88c 100755
--- a/test/ppmforge.test
+++ b/test/ppmforge.test
@@ -4,17 +4,6 @@
 
 # Use small x y values to avoid floating point issues.
 
-
-testrandom -q
-case $? in
-   81)
-      # Test 1: Should print: 3634219838 196623
-      ppmforge -night -seed 1 | cksum
-      ;;
-
-   8[02-9] | 90)
-       echo "Skipping: random number generator is not glibc." 1>&2
-       exit 80;;
-
-   *)  exit 1;;  # testrandom failed
-esac
+# Should print: 3634219838 196623 (Glibc)
+#               3262664440 196623 (MAC OS)
+ppmforge -night -seed 1 | cksum
diff --git a/test/ppmpat-random.rand-ok b/test/ppmpat-random.rand-ok
new file mode 100644
index 00000000..eb8779ab
--- /dev/null
+++ b/test/ppmpat-random.rand-ok
@@ -0,0 +1,7 @@
+000|0
+081|2219119109 36015
+081|3436846137 16813
+081|908097729 16813
+082|3606254242 36015
+082|3615722579 16813
+082|1756684515 16813
diff --git a/test/ppmpat-random.test b/test/ppmpat-random.test
index d9f69c18..a6daa982 100755
--- a/test/ppmpat-random.test
+++ b/test/ppmpat-random.test
@@ -7,24 +7,16 @@
 
 # These tests require random numbers.
 
-testrandom -q
-case $? in
-   81)
-   # Test 1. Should print: 2219119109 36015
-   ppmpat --randomseed=0 -camo 100 120 | cksum
+# Test 1. Should print: 2219119109 36015 (glibc)
+#                       3606254242 36015 (MAC OS)
+ppmpat --randomseed=0 -camo 100 120 | cksum
 
-   # Test 2. Should print: 3436846137 16813
-   ppmpat --randomseed=0 -anticamo 80 70 | cksum
+# Test 2. Should print: 3436846137 16813 (glibc)
+#                       3615722579 16813 (MAC OS)
+ppmpat --randomseed=0 -anticamo 80 70 | cksum
 
-   # Test 3. Should print: 908097729 16813
-   ppmpat --randomseed=0 --color \
-     rgb:55/c0/34,rgb:0/ff/0,rgb:0/ee/0,rgb:0/cd/0,rgb:0/8b/0,rgb:4f/4f/2f \
-     -camo 80 70 | cksum
-   ;;
-
-   8[02-9] | 90)
-       echo "Skipping: random number generator is not glibc." 1>&2
-       exit 80;;
-
-   *)  exit 1;;  # testrandom failed
-esac
+# Test 3. Should print: 908097729 16813 (glibc)
+#                       1756684515 16813 (MAC OS)
+ppmpat --randomseed=0 --color \
+  rgb:55/c0/34,rgb:0/ff/0,rgb:0/ee/0,rgb:0/cd/0,rgb:0/8b/0,rgb:4f/4f/2f \
+  -camo 80 70 | cksum
diff --git a/test/ppmrough.rand-ok b/test/ppmrough.rand-ok
new file mode 100644
index 00000000..216545c7
--- /dev/null
+++ b/test/ppmrough.rand-ok
@@ -0,0 +1,3 @@
+000|0
+081|378403602 30015
+082|378403602 30015
diff --git a/test/ppmrough.test b/test/ppmrough.test
index cf948f9f..bd4211a3 100755
--- a/test/ppmrough.test
+++ b/test/ppmrough.test
@@ -2,16 +2,5 @@
 # This script tests: ppmrough
 # Also requires:
 
-testrandom -q
-case $? in
-   81)
-      # Should print: 378403602 30015
-      ppmrough  -randomseed 1 | cksum
-      ;;
-
-   8[02-9] | 90)
-       echo "Skipping: random number generator is not glibc." 1>&2
-       exit 80;;
-
-   *)  exit 1;;  # testrandom failed
-esac
+# Should print: 378403602 30015 (Glibc and MAC OS)
+ppmrough  -randomseed 1 | cksum
diff --git a/test/testrandom.c b/test/testrandom.c
index 43414926..5b85a6e8 100644
--- a/test/testrandom.c
+++ b/test/testrandom.c
@@ -8,6 +8,7 @@
 
   Options:
     -q : quiet mode
+    -x : print exit code to stdout, otherwise equivalent to quite mode
     -v : verbose mode : Use to generate values for new table 
 
   This is a self-contained program which does not require any libnetpbm
@@ -16,11 +17,17 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#define  bool  int
+#define  TRUE  1
+#define  FALSE 0
+
+
 /* Exit values */
 #define EXIT_ERROR 1
 #define EXIT_UNKNOWN 80
 #define ISO_GLIBC 81
-/* 82-90: reserved */
+#define MAC_OS    82
+/* 83-90: reserved */
 
 typedef enum {QUIET=0, NORMAL=1, VERBOSE=2} VerbosityLevel;
 
@@ -41,11 +48,15 @@ static struct {
         /* Sample values returned from our tests */
     const char * const name;
         /* Name for this rand() function */
-} rTable[2] = {
+} rTable[3] = {
     { ISO_GLIBC,  /* glibc rand() */ 
       0x7fffffff, /* 31 bits */ 
       { 217313873, 969144303, 1757357552, 1096307597, 818311031 },
       "ISO C glibc rand() or equivalent" },
+    { MAC_OS,
+      0x7fffffff, /* 31 bits */
+      { 63715337, 1416812753, 1073261735, 1594828992, 1547470337 },
+      "MAC OS c library rand() or equivalent" },
     
     /* Insert additional entries here */
     
@@ -59,15 +70,19 @@ static struct {
 static void
 parseCommandLine(int              const argc,
                  const char *     const argv[],
-                 VerbosityLevel * const verbosityP) {
+                 VerbosityLevel * const verbosityP,
+                 bool *           const printExitCodeP) {
 
-    *verbosityP = NORMAL; /* Initial value */
+    *verbosityP = NORMAL;       /* Initial value */
+    *printExitCodeP = FALSE;    /* Initial value */
 
     if (argc == 2) {
         if (argv[1][0] == '-' && argv[1][2] == '\0') {
             switch ( argv[1][1] ) {
             case 'v' : *verbosityP = VERBOSE; break;
             case 'q' : *verbosityP = QUIET  ; break;
+            case 'x' : *verbosityP = QUIET  ;
+                       *printExitCodeP = TRUE ; break;
             default :  fprintf (stderr,
                                 "Error: Unrecognized argument: %s\n", argv[1]);
                 exit (EXIT_ERROR);
@@ -88,8 +103,9 @@ main(int const argc, const char * const argv[]) {
     unsigned int i;
     unsigned int res[5];
     VerbosityLevel verbosity;
+    bool printExitCode;
 
-    parseCommandLine(argc, argv, &verbosity);
+    parseCommandLine(argc, argv, &verbosity, &printExitCode);
 
     if (verbosity == VERBOSE) {
         if (RAND_MAX > 0)
@@ -120,12 +136,16 @@ main(int const argc, const char * const argv[]) {
                 fprintf(stderr,
                         "Random number generator is %s.\n", rTable[i].name);
 
+            if (printExitCode == TRUE)
+                printf("%03u", rTable[i].type);
             exit(rTable[i].type);
         }
     }
     /* No matches */
     if (verbosity != QUIET)   
         fprintf(stderr, "Random number generator is of unknown type.\n");
+    if (printExitCode == TRUE)
+        printf("%03u",EXIT_UNKNOWN);
     exit(EXIT_UNKNOWN);
 }
 
diff --git a/test/tiffcmyk-roundtrip.ok b/test/tiffcmyk-roundtrip.ok
index e152d0a7..5f4963cd 100644
--- a/test/tiffcmyk-roundtrip.ok
+++ b/test/tiffcmyk-roundtrip.ok
@@ -1,5 +1,5 @@
-  3 1 1 1
-  3 1 1 1
-  3 1 1 1
-  3 1 1 1
-  3 1 1 1
+  3 1000.00 1000.00 1000.00
+  3 1000.00 1000.00 1000.00
+  3 1000.00 1000.00 1000.00
+  3 1000.00 1000.00 1000.00
+  3 1000.00 1000.00 1000.00
diff --git a/test/tiffcmyk-roundtrip.test b/test/tiffcmyk-roundtrip.test
index e123d807..99e02c48 100755
--- a/test/tiffcmyk-roundtrip.test
+++ b/test/tiffcmyk-roundtrip.test
@@ -16,31 +16,46 @@ output_tiff=${tmpdir}/output.tiff
 pnmtotiffcmyk testimg.ppm > ${output_tiff} && \
   tifftopnm -headerdump -byrow ${output_tiff} | \
   pnmpsnr -machine - testimg.ppm | \
-  awk '{printf("%3d %1d %1d %1d\n",NF,$1>45.0,$2>59.5,$3>56.5)}'
+  awk '{printf("%3d %.2f %.2f %.2f\n", NF,
+                $1>45.0 ? 1000.00 : $1,
+                $2>59.5 ? 1000.00 : $2,
+                $3>56.5 ? 1000.00 : $3) }'
 
 
 # Note that "-rowsperstrip=1" does not work
 pnmtotiffcmyk -rowsperstrip 1 -lsb2msb testimg.ppm > ${output_tiff} && \
   tifftopnm -respectfillorder -byrow  ${output_tiff} | \
   pnmpsnr -machine - testimg.ppm | \
-  awk '{printf("%3d %1d %1d %1d\n",NF,$1>45.0,$2>59.5,$3>56.5)}'
+  awk '{printf("%3d %.2f %.2f %.2f\n", NF,
+                $1>45.0 ? 1000.00 : $1,
+                $2>59.5 ? 1000.00 : $2,
+                $3>56.5 ? 1000.00 : $3) }'
 
 
 pnmtotiffcmyk -packbits testimg.ppm > ${output_tiff} && \
   tifftopnm -byrow ${output_tiff} | \
   pnmpsnr -machine - testimg.ppm | \
-  awk '{printf("%3d %1d %1d %1d\n",NF,$1>45.0,$2>59.5,$3>56.5)}'
+  awk '{printf("%3d %.2f %.2f %.2f\n", NF,
+                $1>45.0 ? 1000.00 : $1,
+                $2>59.5 ? 1000.00 : $2,
+                $3>56.5 ? 1000.00 : $3) }'
 
 
 pnmtotiffcmyk -lzw testimg.ppm > ${output_tiff} && \
   tifftopnm -byrow ${output_tiff} | \
     pnmpsnr -machine - testimg.ppm | \
-  awk '{printf("%3d %1d %1d %1d\n",NF,$1>45.0,$2>59.5,$3>56.5)}'
+  awk '{printf("%3d %.2f %.2f %.2f\n", NF,
+                $1>45.0 ? 1000.00 : $1,
+                $2>59.5 ? 1000.00 : $2,
+                $3>56.5 ? 1000.00 : $3) }'
 
 
 pnmtotiffcmyk -lzw -predictor 2 testimg.ppm > ${output_tiff} && \
   tifftopnm -respectfillorder -byrow ${output_tiff} | \
   pnmpsnr -machine - testimg.ppm | \
-  awk '{printf("%3d %1d %1d %1d\n",NF,$1>45.0,$2>59.5,$3>56.5)}'
+  awk '{printf("%3d %.2f %.2f %.2f\n", NF,
+                $1>45.0 ? 1000.00 : $1,
+                $2>59.5 ? 1000.00 : $2,
+                $3>56.5 ? 1000.00 : $3) }'
 
 rm ${output_tiff}
\ No newline at end of file
diff --git a/version.mk b/version.mk
index ba31783b..431ba191 100644
--- a/version.mk
+++ b/version.mk
@@ -1,3 +1,3 @@
 NETPBM_MAJOR_RELEASE = 10
-NETPBM_MINOR_RELEASE = 80
-NETPBM_POINT_RELEASE = 2
+NETPBM_MINOR_RELEASE = 81
+NETPBM_POINT_RELEASE = 0