about summary refs log tree commit diff
path: root/generator
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2009-09-27 21:44:29 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2009-09-27 21:44:29 +0000
commit43939e66b1d4eeb2f3799c124f3598756755005a (patch)
tree15733092de55d52421a6ea02f5a43d5f8ff24393 /generator
parent49f4336c9bba33650573ba780b70bc501b38643e (diff)
downloadnetpbm-mirror-43939e66b1d4eeb2f3799c124f3598756755005a.tar.gz
netpbm-mirror-43939e66b1d4eeb2f3799c124f3598756755005a.tar.xz
netpbm-mirror-43939e66b1d4eeb2f3799c124f3598756755005a.zip
Rebase Stable series to current Advanced: 10.47.04
git-svn-id: http://svn.code.sf.net/p/netpbm/code/stable@995 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'generator')
-rw-r--r--generator/Makefile4
-rw-r--r--generator/pamgradient.c13
-rw-r--r--generator/pamseq.c1
-rw-r--r--generator/pamstereogram.c10
-rw-r--r--generator/pamstereogram.test8
-rw-r--r--generator/pbmmake.c13
-rw-r--r--generator/pbmtext.c426
-rw-r--r--generator/pbmtextps.c275
-rw-r--r--generator/pbmupc.c17
-rw-r--r--generator/pgmcrater.c8
-rw-r--r--generator/pgmmake.c10
-rw-r--r--generator/pgmnoise.c182
-rw-r--r--generator/pgmramp.c12
-rw-r--r--generator/ppmcolors.c1
-rw-r--r--generator/ppmforge.c6
-rw-r--r--generator/ppmmake.c10
-rw-r--r--generator/ppmpat.c1375
-rw-r--r--generator/ppmrough.c5
18 files changed, 1352 insertions, 1024 deletions
diff --git a/generator/Makefile b/generator/Makefile
index 52de9b10..3c30cdd0 100644
--- a/generator/Makefile
+++ b/generator/Makefile
@@ -5,7 +5,7 @@ endif
 SUBDIR = generator
 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.
@@ -37,4 +37,4 @@ MERGE_OBJECTS = $(MERGEBINARIES:%=%.o2)
 .PHONY: all
 all: $(BINARIES)
 
-include $(SRCDIR)/Makefile.common
+include $(SRCDIR)/common.mk
diff --git a/generator/pamgradient.c b/generator/pamgradient.c
index 08db86e3..aa559d27 100644
--- a/generator/pamgradient.c
+++ b/generator/pamgradient.c
@@ -1,5 +1,6 @@
 #include <string.h>
 
+#include "pm_c_util.h"
 #include "pam.h"
 #include "shhopt.h"
 #include "mallocvar.h"
@@ -11,7 +12,6 @@ struct cmdlineInfo {
     tuple colorTopRight;
     tuple colorBottomLeft;
     tuple colorBottomRight;
-    unsigned depth;
     unsigned int cols;
     unsigned int rows;
     unsigned int maxval;
@@ -121,8 +121,7 @@ interpolate(struct pam * const pamP,
 
 
 static int
-isgray(struct pam * const pamP,
-       tuple        const color) {
+isgray(tuple const color) {
 
     return (color[PAM_RED_PLANE] == color[PAM_GRN_PLANE])
             && (color[PAM_RED_PLANE] == color[PAM_BLU_PLANE]);
@@ -176,10 +175,10 @@ main(int argc, char *argv[]) {
     pam.maxval           = cmdline.maxval;
     pam.bytes_per_sample = pnm_bytespersample(pam.maxval);
     pam.format           = PAM_FORMAT;
-    if (isgray(&pam, cmdline.colorTopLeft)
-            && isgray(&pam, cmdline.colorTopRight)
-            && isgray(&pam, cmdline.colorBottomLeft)
-            && isgray(&pam, cmdline.colorBottomRight)) {
+    if (isgray(cmdline.colorTopLeft)
+            && isgray(cmdline.colorTopRight)
+            && isgray(cmdline.colorBottomLeft)
+            && isgray(cmdline.colorBottomRight)) {
         pam.depth = 1;
         strcpy(pam.tuple_type, PAM_PGM_TUPLETYPE);
     } else {
diff --git a/generator/pamseq.c b/generator/pamseq.c
index 58419d12..98eac1cc 100644
--- a/generator/pamseq.c
+++ b/generator/pamseq.c
@@ -3,6 +3,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 
+#include "pm_c_util.h"
 #include "pam.h"
 #include "shhopt.h"
 
diff --git a/generator/pamstereogram.c b/generator/pamstereogram.c
index 0e6e6cc9..0ce63853 100644
--- a/generator/pamstereogram.c
+++ b/generator/pamstereogram.c
@@ -50,6 +50,7 @@
 #include <assert.h>
 
 #include "pm_config.h"
+#include "pm_c_util.h"
 #include "pam.h"
 #include "shhopt.h"
 #include "mallocvar.h"
@@ -455,12 +456,17 @@ termPatternPixel(outGenerator * const outGenP) {
 static void
 initPatternPixel(outGenerator *     const outGenP,
                  struct cmdlineInfo const cmdline) {
-
+/*----------------------------------------------------------------------------
+   Initialize parts of output generator *outGenP that are based on the
+   supplied pattern file, assuming there is one.
+-----------------------------------------------------------------------------*/
     struct patternPixelState * stateP;
     FILE * patternFileP;
 
     MALLOCVAR_NOFAIL(stateP);
-        
+
+    assert(cmdline.patFilespec);
+    
     patternFileP = pm_openr(cmdline.patFilespec);
 
     stateP->patTuples =
diff --git a/generator/pamstereogram.test b/generator/pamstereogram.test
index 7eb01fff..80f70ee0 100644
--- a/generator/pamstereogram.test
+++ b/generator/pamstereogram.test
@@ -20,7 +20,7 @@ echo Test 10.  Should print 1266273778 293:
 ./pamstereogram -randomseed=1 -makemask ../testgrid.pbm | cksum 
 
 echo Test 11.  Should print 3034751595 1070:
-./pamgauss 100 10 -maxval=10000 -sigma 20 | pamfunc -multiplier=500 | \
+pamgauss 100 10 -maxval=10000 -sigma 20 | pamfunc -multiplier=500 | \
   ./pamstereogram -randomseed=1 -dpi=10 -makemask | cksum
 
 # Grayscale
@@ -28,11 +28,11 @@ echo Test 11.  Should print 3034751595 1070:
 echo Test 20.  Should print 2468969328 289:
 ./pamstereogram -randomseed=1 -grayscale ../testgrid.pbm | cksum 
 echo Test 21.  Should print 1946982115 4068:
-./pamseq 1 100 | pnmtile 200 20 | \
+pamseq 1 100 | pnmtile 200 20 | \
   ./pamstereogram -randomseed=1 -dpi=10 -grayscale | \
   cksum
 echo Test 22.  Should print 2078013430 4068:
-./pamseq 1 100 | pnmtile 200 20 | \
+pamseq 1 100 | pnmtile 200 20 | \
   ./pamstereogram -randomseed=1 -dpi=10 -grayscale -maxval 255 | \
   cksum
 
@@ -41,7 +41,7 @@ echo Test 22.  Should print 2078013430 4068:
 echo Test 30.  Should print 1319392622 731:
 ./pamstereogram -randomseed=1 -color ../testgrid.pbm | cksum 
 echo Test 31.  Should print 389886159 12062:
-./pamseq 1 100 | pnmtile 200 20 | \
+pamseq 1 100 | pnmtile 200 20 | \
   ./pamstereogram -randomseed=1 -dpi=10 -color | \
   cksum
 
diff --git a/generator/pbmmake.c b/generator/pbmmake.c
index afe1dac3..41d80274 100644
--- a/generator/pbmmake.c
+++ b/generator/pbmmake.c
@@ -11,6 +11,7 @@
 **
 */
 
+#include "pm_c_util.h"
 #include "shhopt.h"
 #include "mallocvar.h"
 #include "pbm.h"
@@ -75,16 +76,8 @@ parseCommandLine(int argc, char ** argv,
                  "non-option arguments: width and height in pixels",
                  argc-1);
     else {
-        cmdlineP->width  = atoi(argv[1]);
-        cmdlineP->height = atoi(argv[2]);
-
-        if (cmdlineP->width < 1) 
-            pm_error("Width must be positive.  You specified %d.", 
-                     cmdlineP->width);
-
-        if (cmdlineP->height < 1) 
-            pm_error("Height must be positive.  You specified %d.",
-                     cmdlineP->height);
+        cmdlineP->width  = pm_parse_width(argv[1]);
+        cmdlineP->height = pm_parse_height(argv[2]);
     }
 }
 
diff --git a/generator/pbmtext.c b/generator/pbmtext.c
index d0a6291b..693c3f59 100644
--- a/generator/pbmtext.c
+++ b/generator/pbmtext.c
@@ -14,69 +14,76 @@
 #define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
 
 #include <string.h>
+#include <limits.h>
+#include <assert.h>
 
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "shhopt.h"
 #include "pbm.h"
 #include "pbmfont.h"
-#include "shhopt.h"
-#include "mallocvar.h"
 
-struct cmdline_info {
+struct cmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    const char *text;    /* text from command line or NULL if none */
-    const char *font;    /* -font option value or NULL if none */
-    const char *builtin; /* -builtin option value or NULL if none */
+    const char * text;    /* text from command line or NULL if none */
+    const char * font;    /* -font option value or NULL if none */
+    const char * builtin; /* -builtin option value or NULL if none */
     unsigned int dump;   
         /* undocumented dump option for installing a new built-in font */
     float space;   /* -space option value or default */
     unsigned int width;     /* -width option value or zero */
     int lspace;    /* lspace option value or default */
     unsigned int nomargins;     /* -nomargins */
+    unsigned int verbose;
 };
 
 
 
 
 static void
-parse_command_line(int argc, char ** argv,
-                   struct cmdline_info *cmdline_p) {
+parseCommandLine(int argc, const char ** argv,
+                 struct cmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that the file spec array we return is stored in the storage that
    was passed to us as the argv array.
 -----------------------------------------------------------------------------*/
-    optEntry *option_def = malloc(100*sizeof(optEntry));
+    optEntry * option_def;
         /* Instructions to OptParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
 
     unsigned int option_def_index;
 
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
     option_def_index = 0;   /* incremented by OPTENTRY */
-    OPTENT3(0, "font",      OPT_STRING, &cmdline_p->font, NULL,        0);
-    OPTENT3(0, "builtin",   OPT_STRING, &cmdline_p->builtin, NULL,     0);
-    OPTENT3(0, "dump",      OPT_FLAG,   NULL, &cmdline_p->dump,        0);
-    OPTENT3(0, "space",     OPT_FLOAT,  &cmdline_p->space, NULL,       0);
-    OPTENT3(0, "width",     OPT_UINT,   &cmdline_p->width, NULL,       0);
-    OPTENT3(0, "lspace",    OPT_INT,    &cmdline_p->lspace, NULL,      0);
-    OPTENT3(0, "nomargins", OPT_FLAG,   NULL, &cmdline_p->nomargins,   0);
+    OPTENT3(0, "font",      OPT_STRING, &cmdlineP->font, NULL,        0);
+    OPTENT3(0, "builtin",   OPT_STRING, &cmdlineP->builtin, NULL,     0);
+    OPTENT3(0, "dump",      OPT_FLAG,   NULL, &cmdlineP->dump,        0);
+    OPTENT3(0, "space",     OPT_FLOAT,  &cmdlineP->space, NULL,       0);
+    OPTENT3(0, "width",     OPT_UINT,   &cmdlineP->width, NULL,       0);
+    OPTENT3(0, "lspace",    OPT_INT,    &cmdlineP->lspace, NULL,      0);
+    OPTENT3(0, "nomargins", OPT_FLAG,   NULL, &cmdlineP->nomargins,   0);
+    OPTENT3(0, "verbose",   OPT_FLAG,   NULL, &cmdlineP->verbose,     0);
 
     /* Set the defaults */
-    cmdline_p->font = NULL;
-    cmdline_p->builtin = NULL;
-    cmdline_p->space = 0.0;
-    cmdline_p->width = 0;
-    cmdline_p->lspace = 0;
+    cmdlineP->font = NULL;
+    cmdlineP->builtin = NULL;
+    cmdlineP->space = 0.0;
+    cmdlineP->width = 0;
+    cmdlineP->lspace = 0;
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
-        /* Uses and sets argc, argv, and some of *cmdline_p and others. */
+    optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (argc-1 == 0)
-        cmdline_p->text = NULL;
+        cmdlineP->text = NULL;
     else {
         char *text;
         int i;
@@ -87,7 +94,7 @@ parse_command_line(int argc, char ** argv,
         text = malloc(totaltextsize);  /* initial allocation */
         text[0] = '\0';
         
-        for (i = 1; i < argc; i++) {
+        for (i = 1; i < argc; ++i) {
             if (i > 1) {
                 totaltextsize += 1;
                 text = realloc(text, totaltextsize);
@@ -101,11 +108,59 @@ parse_command_line(int argc, char ** argv,
                 pm_error("out of memory allocating space for input text");
             strcat(text, argv[i]);
         }
-        cmdline_p->text = text;
+        cmdlineP->text = text;
+    }
+}
+
+
+
+static void
+reportFont(struct font * const fontP) {
+
+    unsigned int n;
+    unsigned int c;
+
+    pm_message("FONT:");
+    pm_message("  character dimensions: %uw x %uh",
+               fontP->maxwidth, fontP->maxheight);
+    pm_message("  Additional vert white space: %d pixels", fontP->y);
+
+    for (c = 0, n = 0; c < ARRAY_SIZE(fontP->glyph); ++c)
+        if (fontP->glyph[c])
+            ++n;
+
+    pm_message("  # characters: %u", n);
+}
+
+
+
+static void
+computeFont(struct cmdlineInfo const cmdline,
+            struct font **     const fontPP) {
+
+    struct font * fontP;
+
+    if (cmdline.font)
+        fontP = pbm_loadfont(cmdline.font);
+    else {
+        if (cmdline.builtin)
+            fontP = pbm_defaultfont(cmdline.builtin);
+        else
+            fontP = pbm_defaultfont("bdf");
     }
+
+    if (cmdline.verbose)
+        reportFont(fontP);
+
+    if (cmdline.dump) {
+        pbm_dumpfont(fontP);
+        exit(0);
+    }
+    *fontPP = fontP;
 }
 
 
+
 struct text {
     char **      textArray;  /* malloc'ed */
     unsigned int allocatedLineCount;
@@ -113,6 +168,7 @@ struct text {
 };
 
 
+
 static void
 allocTextArray(struct text * const textP,
                unsigned int  const maxLineCount,
@@ -131,6 +187,7 @@ allocTextArray(struct text * const textP,
 }
 
 
+
 static void
 freeTextArray(struct text const text) {
 
@@ -145,30 +202,72 @@ freeTextArray(struct text const text) {
 
 
 static void
-fix_control_chars(char * const buf, struct font * const fn) {
+fixControlChars(const char *  const input,
+                struct font * const fontP,
+                const char ** const outputP) {
+/*----------------------------------------------------------------------------
+   Return a translation of input[] that can be rendered as glyphs in
+   the font 'fontP'.  Return it as newly malloced *outputP.
 
-    int i;
+   Expand tabs to spaces.
 
-    /* chop off terminating newline */
-    if (strlen(buf) >= 1 && buf[strlen(buf)-1] == '\n')
-        buf[strlen(buf)-1] = '\0';
-    
-    for ( i = 0; buf[i] != '\0'; ++i ) {
-        if ( buf[i] == '\t' ) { 
-            /* Turn tabs into the right number of spaces. */
-            int j, n, l;
-            n = ( i + 8 ) / 8 * 8;
-            l = strlen( buf );
-            for ( j = l; j > i; --j )
-                buf[j + n - i - 1] = buf[j];
-            for ( ; i < n; ++i )
-                buf[i] = ' ';
-            --i;
+   Remove any trailing newline.  (But leave intermediate ones as line
+   delimiters).
+
+   Turn anything that isn't a code point in the font to a single space
+   (which isn't guaranteed to be in the font either, of course).
+-----------------------------------------------------------------------------*/
+    /* We don't know in advance how big the output will be because of the
+       tab expansions.  So we make sure before processing each input
+       character that there is space in the output buffer for a worst
+       case tab expansion, plus a terminating NUL, reallocating as
+       necessary.  And we originally allocate enough for the entire line
+       assuming no tabs.
+    */
+
+    unsigned int const tabSize = 8;
+
+    unsigned int inCursor, outCursor;
+    char * output;      /* Output buffer.  Malloced */
+    size_t outputSize;  /* Currently allocated size of 'output' */
+
+    outputSize = strlen(input) + 1 + tabSize;
+        /* Leave room for one worst case tab expansion and NUL terminator */
+    MALLOCARRAY(output, outputSize);
+
+    if (output == NULL)
+        pm_error("Couldn't allocate %u bytes for a line of text.", outputSize);
+
+    for (inCursor = 0, outCursor = 0; input[inCursor] != '\0'; ++inCursor) {
+        if (outCursor + 1 + tabSize > outputSize) {
+            outputSize = outCursor + 1 + 4 * tabSize;
+            REALLOCARRAY(output, outputSize);
+            if (output == NULL)
+                pm_error("Couldn't allocate %u bytes for a line of text.",
+                         outputSize);
         }
-        else if ( !fn->glyph[(unsigned char)buf[i]] )
-            /* Turn unknown chars into a single space. */
-            buf[i] = ' ';
+        if (input[inCursor] == '\n' && input[inCursor+1] == '\0') {
+            /* This is a terminating newline.  We don't do those. */
+        } else if (input[inCursor] == '\t') { 
+            /* Expand this tab into the right number of spaces. */
+            unsigned int const nextTabStop =
+                (outCursor + tabSize) / tabSize * tabSize;
+
+            while (outCursor < nextTabStop)
+                output[outCursor++] = ' ';
+        } else if (!fontP->glyph[(unsigned char)input[inCursor]]) {
+            /* Turn this unknown char into a single space. */
+            output[outCursor++] = ' ';
+        } else
+            output[outCursor++] = input[inCursor];
+
+        assert(outCursor <= outputSize);
     }
+    output[outCursor++] = '\0';
+
+    assert(outCursor <= outputSize);
+
+    *outputP = output;
 }
 
 
@@ -195,35 +294,34 @@ fill_rect(bit** const bits,
 static void
 get_line_dimensions(const char line[], const struct font * const font_p, 
                     const float intercharacter_space,
-                    int * const bwid_p, int * const backup_space_needed_p) {
+                    double * const bwidP, int * const backup_space_needed_p) {
 /*----------------------------------------------------------------------------
    Determine the width in pixels of the line of text line[] in the font
-   *font_p, and return it as *bwid_p.  Also determine how much of this
+   *font_p, and return it as *bwidP.  Also determine how much of this
    width goes to the left of the nominal starting point of the line because
    the first character in the line has a "backup" distance.  Return that
    as *backup_space_needed_p.
 -----------------------------------------------------------------------------*/
     int cursor;  /* cursor into the line of text */
-    float accumulated_ics;
+    double accumulatedIcs;
         /* accumulated intercharacter space so far in the line we are 
            stepping through.  Because the intercharacter space might not be
            an integer, we accumulate it here and realize full pixels whenever
-           we have more than one pixel.
-           */
-
-    int no_chars_yet; 
-        /* logical: we haven't seen any renderable characters yet in 
-           the line.
+           we have more than one pixel.  Note that this can be negative
+           (which means were crowding, rather than spreading, text).
         */
+    double bwid;
+    bool no_chars_yet; 
+        /* We haven't seen any renderable characters yet in the line. */
     struct glyph * lastGlyphP;
         /* Glyph of last character processed so far.  Undefined if
            'no_chars_yet'.
         */
 
     no_chars_yet = TRUE;   /* initial value */
-    *bwid_p = 0;  /* initial value */
-    accumulated_ics = 0.0;  /* initial value */
-
+    accumulatedIcs = 0.0;  /* initial value */
+    bwid = 0.0;  /* initial value */
+    
     for (cursor = 0; line[cursor] != '\0'; cursor++) {
         struct glyph * const glyphP = 
             font_p->glyph[(unsigned char)line[cursor]];
@@ -235,18 +333,23 @@ get_line_dimensions(const char line[], const struct font * const font_p,
                     *backup_space_needed_p = -glyphP->x;
                 else {
                     *backup_space_needed_p = 0;
-                    *bwid_p += glyphP->x;
+                    bwid += glyphP->x;
                 }
             } else {
                 /* handle extra intercharacter space (-space option) */
-                int full_pixels;  /* integer part of accumulated_ics */
-                accumulated_ics += intercharacter_space;
-                full_pixels = (int) accumulated_ics;
-                *bwid_p += full_pixels;
-                accumulated_ics -= full_pixels;
+                accumulatedIcs += intercharacter_space;
+                if (accumulatedIcs >= INT_MAX)
+                    pm_error("Image width too large.");
+                if (accumulatedIcs <= INT_MIN)
+                    pm_error("Absurdly large negative -space value.");
+                {
+                    int const fullPixels = (int) accumulatedIcs;
+                    bwid           += fullPixels;
+                    accumulatedIcs -= fullPixels;
+                }
             }
             lastGlyphP = glyphP;
-            *bwid_p += glyphP->xadd;
+            bwid += glyphP->xadd;
         }
     }
     if (no_chars_yet)
@@ -258,9 +361,13 @@ get_line_dimensions(const char line[], const struct font * const font_p,
            right at the right edge of the glyph (no extra space to
            anticipate another character).
         */
-        *bwid_p -= lastGlyphP->xadd;
-        *bwid_p += lastGlyphP->width + lastGlyphP->x;
+        bwid -= lastGlyphP->xadd;
+        bwid += lastGlyphP->width + lastGlyphP->x;
     }
+    if (bwid > INT_MAX)
+        pm_error("Image width too large.");
+    else
+        *bwidP = bwid; 
 }
 
 
@@ -377,7 +484,8 @@ struct outputTextCursor {
            are stepping through.  Because the intercharacter space
            might not be an integer, we accumulate it here and
            realize full pixels whenever we have more than one
-           pixel.  
+           pixel.  Note that this is negative if we're crowding, rather
+           than spreading, characters.
         */
 };
 
@@ -442,11 +550,12 @@ placeCharacterInOutput(char                      const lastch,
                     cursorP->widthSoFar += fontP->glyph[glyphIndex]->x;
             } else {
                 /* handle extra intercharacter space (-space option) */
-                int fullPixels;  /* integer part of accumulatedIcs */
                 cursorP->accumulatedIcs += cursorP->intercharacterSpace;
-                fullPixels = (int) cursorP->accumulatedIcs;
-                cursorP->widthSoFar     += fullPixels;
-                cursorP->accumulatedIcs -= fullPixels;
+                {
+                    int const fullPixels = (int)cursorP->accumulatedIcs;
+                    cursorP->widthSoFar     += fullPixels;
+                    cursorP->accumulatedIcs -= fullPixels;
+                }
             }
             cursorP->widthSoFar += fontP->glyph[glyphIndex]->xadd;
         }
@@ -522,8 +631,9 @@ truncateText(struct text   const inputText,
         /* accumulated intercharacter space so far in the line we are 
            stepping through.  Because the intercharacter space might not be
            an integer, we accumulate it here and realize full pixels whenever
-           we have more than one pixel.
-           */
+           we have more than one pixel.  Note that this is negative if we're
+           crowding, not spreading, characters.
+        */
 
         int noCharsYet; 
         /* logical: we haven't seen any renderable characters yet in 
@@ -546,11 +656,12 @@ truncateText(struct text   const inputText,
                         widthSoFar += fontP->glyph[lastch]->x;
                 } else {
                     /* handle extra intercharacter space (-space option) */
-                    int fullPixels;  /* integer part of accumulatedIcs */
                     accumulatedIcs += intercharacterSpace;
-                    fullPixels = (int) intercharacterSpace;
-                    widthSoFar     += fullPixels;
-                    accumulatedIcs -= fullPixels;
+                    {
+                        int const fullPixels = (int) intercharacterSpace;
+                        widthSoFar     += fullPixels;
+                        accumulatedIcs -= fullPixels;
+                    }
                 }
                 widthSoFar += fontP->glyph[lastch]->xadd;
             }
@@ -569,16 +680,17 @@ truncateText(struct text   const inputText,
 
 static void
 getText(const char          cmdline_text[], 
-        struct font * const fn, 
+        struct font * const fontP,
         struct text * const input_textP) {
 
     struct text input_text;
 
     if (cmdline_text) {
-        allocTextArray(&input_text, 1, strlen(cmdline_text)*8);
-        strcpy(input_text.textArray[0], cmdline_text);
-        fix_control_chars(input_text.textArray[0], fn);
+        MALLOCARRAY_NOFAIL(input_text.textArray, 1);
+        input_text.allocatedLineCount = 1;
         input_text.lineCount = 1;
+        fixControlChars(cmdline_text, fontP,
+                        (const char**)&input_text.textArray[0]);
     } else {
         /* Read text from stdin. */
 
@@ -595,18 +707,16 @@ getText(const char          cmdline_text[],
         
         lineCount = 0;  /* initial value */
         while (fgets(buf, sizeof(buf), stdin) != NULL) {
-            if (strlen(buf)*8 + 1 >= sizeof(buf))
+            if (strlen(buf) + 1 >= sizeof(buf))
                 pm_error("A line of input text is longer than %u characters."
-                         "Cannot process.", (sizeof(buf)-1)/8);
-            fix_control_chars(buf, fn);
+                         "Cannot process.", sizeof(buf)-1);
             if (lineCount >= maxlines) {
                 maxlines *= 2;
-                text_array = (char**) realloc((char*) text_array, 
-                                              maxlines * sizeof(char*));
+                REALLOCARRAY(text_array, maxlines);
                 if (text_array == NULL)
                     pm_error("out of memory");
             }
-            text_array[lineCount] = strdup(buf);
+            fixControlChars(buf, fontP, (const char **)&text_array[lineCount]);
             if (text_array[lineCount] == NULL)
                 pm_error("out of memory");
             ++lineCount;
@@ -621,62 +731,97 @@ getText(const char          cmdline_text[],
 
 
 static void
-compute_image_width(struct text         const lp, 
-                    const struct font * const fn,
-                    float               const intercharacter_space,
-                    int *               const maxwidthP, 
-                    int *               const maxleftbP) {
-    int line;
-    
-    *maxwidthP = 0;  /* initial value */
-    *maxleftbP = 0;  /* initial value */
-    for (line = 0; line < lp.lineCount; ++line) {
-        int bwid, backup_space_needed;
-        
-        get_line_dimensions(lp.textArray[line], fn, intercharacter_space,
-                            &bwid, &backup_space_needed);
+computeImageHeight(struct text         const formattedText, 
+                   const struct font * const fontP,
+                   int                 const interlineSpace,
+                   unsigned int        const vmargin,
+                   unsigned int *      const rowsP) {
+
+    if (interlineSpace < 0 && fontP->maxheight < -interlineSpace)
+        pm_error("-lspace value (%d) negative and exceeds font height.",
+                 interlineSpace);     
+    else {
+        double const rowsD = 2 * (double) vmargin + 
+            (double) formattedText.lineCount * fontP->maxheight + 
+            (double) (formattedText.lineCount-1) * interlineSpace;
         
-        *maxwidthP = MAX(*maxwidthP, bwid);
-        *maxleftbP = MAX(*maxleftbP, backup_space_needed);
+        if (rowsD > INT_MAX-10)
+            pm_error("Image height too large.");
+        else
+            *rowsP = (unsigned int) rowsD;
+    }
+}
+
+
+
+static void
+computeImageWidth(struct text         const formattedText, 
+                  const struct font * const fontP,
+                  float               const intercharacterSpace,
+                  unsigned int        const hmargin,
+                  unsigned int *      const colsP,
+                  int *               const maxleftbP) {
+
+    if (intercharacterSpace < 0 && fontP->maxwidth < -intercharacterSpace)
+        pm_error("-space value (%f) negative; exceeds font width.",
+                 intercharacterSpace);     
+    else {
+        /* Find the widest line, and the one that backs up the most past
+           the nominal start of the line.
+        */
+    
+        unsigned int line;
+        double maxwidth;
+        int maxleftb;
+        double colsD;
+
+        for (line = 0, maxwidth = 0.0, maxleftb = 0;
+             line < formattedText.lineCount;
+             ++line) {
+
+            double bwid;
+            int backupSpaceNeeded;
+            
+            get_line_dimensions(formattedText.textArray[line], fontP,
+                                intercharacterSpace,
+                                &bwid, &backupSpaceNeeded);
+            
+            maxwidth = MAX(maxwidth, bwid);
+            maxleftb = MAX(maxleftb, backupSpaceNeeded);
+        }
+        colsD = 2 * (double) hmargin + (double) maxwidth;
+    
+        if (colsD > INT_MAX-10)
+            pm_error("Image width too large.");
+        else
+            *colsP = (unsigned int) colsD;
+    
+        *maxleftbP = maxleftb;
     }
 }
 
 
 
 int
-main(int argc, char *argv[]) {
+main(int argc, const char *argv[]) {
 
-    struct cmdline_info cmdline;
-    bit** bits;
-    int rows, cols;
-    struct font* fontP;
-    int vmargin, hmargin;
+    struct cmdlineInfo cmdline;
+    bit ** bits;
+    unsigned int rows, cols;
+    struct font * fontP;
+    unsigned int vmargin, hmargin;
     struct text inputText;
     struct text formattedText;
-    int maxwidth;
-        /* width in pixels of the longest line of text in the image */
     int maxleftb;
 
-    pbm_init( &argc, argv );
+    pm_proginit(&argc, argv);
 
-    parse_command_line(argc, argv, &cmdline);
+    parseCommandLine(argc, argv, &cmdline);
     
-    if (cmdline.font)
-        fontP = pbm_loadfont(cmdline.font);
-    else {
-        if (cmdline.builtin)
-            fontP = pbm_defaultfont(cmdline.builtin);
-        else
-            fontP = pbm_defaultfont("bdf");
-    }
-
-    if (cmdline.dump) {
-        pbm_dumpfont(fontP);
-        exit(0);
-    }
+    computeFont(cmdline, &fontP);
 
     getText(cmdline.text, fontP, &inputText);
-    
+       
     if (cmdline.nomargins) {
         vmargin = 0;
         hmargin = 0;
@@ -689,8 +834,11 @@ main(int argc, char *argv[]) {
             hmargin = 2 * fontP->maxwidth;
         }
     }
-
+    
     if (cmdline.width > 0) {
+        if (cmdline.width > INT_MAX -10)
+            pm_error("-width value too large: %u", cmdline.width);
+            
         /* Flow or truncate lines to meet user's width request */
         if (inputText.lineCount == 1) 
             flowText(inputText, cmdline.width, fontP, cmdline.space,
@@ -701,19 +849,18 @@ main(int argc, char *argv[]) {
         freeTextArray(inputText);
     } else
         formattedText = inputText;
+        
+    if (formattedText.lineCount == 0)
+        pm_error("No input text.");
     
-    rows = 2 * vmargin + 
-        formattedText.lineCount * fontP->maxheight + 
-        (formattedText.lineCount-1) * cmdline.lspace;
-
-    compute_image_width(formattedText, fontP, cmdline.space,
-                        &maxwidth, &maxleftb);
+    computeImageHeight(formattedText, fontP, cmdline.lspace, vmargin,
+                       &rows);
 
-    cols = 2 * hmargin + maxwidth;
+    computeImageWidth(formattedText, fontP, cmdline.space, hmargin,
+                      &cols, &maxleftb);
 
     if (cols == 0 || rows == 0)
-        pm_error("Input is all whitespace and/or non-renderable characters.  "
-                 "No output.");
+        pm_error("Input is all whitespace and/or non-renderable characters.");
 
     bits = pbm_allocarray(cols, rows);
 
@@ -724,9 +871,10 @@ main(int argc, char *argv[]) {
     insert_characters(bits, formattedText, fontP, vmargin, hmargin + maxleftb, 
                       cmdline.space, cmdline.lspace);
 
-    /* All done. */
     pbm_writepbm(stdout, bits, cols, rows, 0);
 
+    pbm_freearray(bits, rows);
+
     freeTextArray(formattedText);
     pm_close(stdout);
 
diff --git a/generator/pbmtextps.c b/generator/pbmtextps.c
index 08c77564..f879fa88 100644
--- a/generator/pbmtextps.c
+++ b/generator/pbmtextps.c
@@ -17,37 +17,27 @@
  */
 #define _XOPEN_SOURCE   /* Make sure popen() is in stdio.h */
 #define _BSD_SOURCE     /* Make sure stdrup() is in string.h */
+#include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include "pbm.h"
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
 #include "nstring.h"
 #include "shhopt.h"
+#include "pbm.h"
 
 
 #define BUFFER_SIZE 2048
 
-static const char *gs_exe_path = 
-#ifdef GHOSTSCRIPT_EXECUTABLE_PATH
-GHOSTSCRIPT_EXECUTABLE_PATH;
-#else
-0;
-#endif
-
-static const char *pnmcrop_exe_path = 
-#ifdef PNMCROP_EXECUTABLE_PATH
-PNMCROP_EXECUTABLE_PATH;
-#else
-0;
-#endif
-
 struct cmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    int          res;         /* resolution, DPI */
-    int          fontsize;    /* Size of font in points */
+    unsigned int res;         /* resolution, DPI */
+    unsigned int fontsize;    /* Size of font in points */
     const char * font;      /* Name of postscript font */
     float        stroke;
         /* Width of stroke in points (only for outline font) */
@@ -58,26 +48,85 @@ struct cmdlineInfo {
 
 
 static void
+writeFileToStdout(const char * const fileName){
+    /* simple pbmtopbm */
+
+    FILE * ifP;
+    int format;
+    int cols, rows, row ;
+    unsigned char * bitrow; 
+    
+    ifP = pm_openr(fileName);
+    pbm_readpbminit(ifP, &cols, &rows, &format);
+
+    if (cols==0 || rows==0 || cols>INT_MAX-10 || rows>INT_MAX-10)
+      pm_error("Abnormal output from gs program.  "
+               "width x height = %u x %u", cols, rows);
+               
+    pbm_writepbminit(stdout, cols, rows, 0);           
+               
+    bitrow = pbm_allocrow_packed(cols);
+    
+    for (row = 0; row < rows; ++row) {
+        pbm_readpbmrow_packed(ifP, bitrow, cols, format);
+        pbm_writepbmrow_packed(stdout, bitrow, cols, 0);
+    }
+    pbm_freerow_packed(bitrow);
+}
+
+
+
+static void
+buildTextFromArgs(int           const argc,
+                  char **       const argv,
+                  const char ** const textP) {
+
+    char * text;
+    unsigned int totalTextSize;
+    unsigned int i;
+
+    text = strdup("");
+    totalTextSize = 1;
+
+    for (i = 1; i < argc; ++i) {
+        if (i > 1) {
+            totalTextSize += 1;
+            text = realloc(text, totalTextSize);
+            if (text == NULL)
+                pm_error("out of memory");
+            strcat(text, " ");
+        } 
+        totalTextSize += strlen(argv[i]);
+        text = realloc(text, totalTextSize);
+        if (text == NULL)
+            pm_error("out of memory");
+        strcat(text, argv[i]);
+    }
+    *textP = text;
+}
+
+
+
+static void
 parseCommandLine(int argc, char ** argv,
                  struct cmdlineInfo *cmdlineP) {
 /*---------------------------------------------------------------------------
   Note that the file spec array we return is stored in the storage that
   was passed to us as the argv array.
 ---------------------------------------------------------------------------*/
-    optEntry *option_def = malloc(100*sizeof(optEntry));
+    optEntry * option_def;
     /* Instructions to OptParseOptions2 on how to parse our options.
    */
     optStruct3 opt;
 
     unsigned int option_def_index;
-    int i;
-    char * text;
-    int totaltextsize = 0;
+
+    MALLOCARRAY(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENTRY */
-    OPTENT3(0, "resolution", OPT_INT,    &cmdlineP->res,            NULL,  0);
+    OPTENT3(0, "resolution", OPT_UINT,   &cmdlineP->res,            NULL,  0);
     OPTENT3(0, "font",       OPT_STRING, &cmdlineP->font,           NULL,  0);
-    OPTENT3(0, "fontsize",   OPT_INT,    &cmdlineP->fontsize,       NULL,  0);
+    OPTENT3(0, "fontsize",   OPT_UINT,   &cmdlineP->fontsize,       NULL,  0);
     OPTENT3(0, "stroke",     OPT_FLOAT,  &cmdlineP->stroke,         NULL,  0);
     OPTENT3(0, "verbose",    OPT_FLAG,   NULL, &cmdlineP->verbose,         0);
 
@@ -93,48 +142,43 @@ parseCommandLine(int argc, char ** argv,
 
     optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
 
-    text = strdup("");
-    totaltextsize = 1;
-
-    for (i = 1; i < argc; i++) {
-        if (i > 1) {
-            totaltextsize += 1;
-            text = realloc(text, totaltextsize);
-            if (text == NULL)
-                pm_error("out of memory");
-            strcat(text, " ");
-        } 
-        totaltextsize += strlen(argv[i]);
-        text = realloc(text, totaltextsize);
-        if (text == NULL)
-            pm_error("out of memory");
-        strcat(text, argv[i]);
-    }
-    cmdlineP->text = text;
+    buildTextFromArgs(argc, argv, &cmdlineP->text);
 }
 
 
 
 static const char *
-construct_postscript(struct cmdlineInfo const cmdl) {
+construct_postscript(struct cmdlineInfo const cmdline) {
 
     const char * retval;
     const char * template;
 
-    if (cmdl.stroke <= 0) 
-        template = "/%s findfont\n%d scalefont\nsetfont\n12 36 moveto\n"
-            "(%s) show\nshowpage\n";
+    if (cmdline.stroke < 0) 
+        template =
+            "/%s findfont\n"
+            "%d scalefont\n"
+            "setfont\n"
+            "12 36 moveto\n"
+            "(%s) show\n"
+            "showpage\n";
     else 
-        template = "/%s findfont\n%d scalefont\nsetfont\n12 36 moveto\n"
-            "%f setlinewidth\n0 setgray\n"
-            "(%s) true charpath\nstroke\nshowpage\n";
-
-    if (cmdl.stroke < 0)
-        asprintfN(&retval, template, cmdl.font, cmdl.fontsize, 
-                  cmdl.text);
+        template =
+            "/%s findfont\n"
+            "%d scalefont\n"
+            "setfont\n"
+            "12 36 moveto\n"
+            "%f setlinewidth\n"
+            "0 setgray\n"
+            "(%s) true charpath\n"
+            "stroke\n"
+            "showpage\n";
+
+    if (cmdline.stroke < 0)
+        asprintfN(&retval, template, cmdline.font, cmdline.fontsize, 
+                  cmdline.text);
     else
-        asprintfN(&retval, template, cmdl.font, cmdl.fontsize, 
-                  cmdl.stroke, cmdl.text);
+        asprintfN(&retval, template, cmdline.font, cmdline.fontsize, 
+                  cmdline.stroke, cmdline.text);
 
     return retval;
 }
@@ -142,24 +186,27 @@ construct_postscript(struct cmdlineInfo const cmdl) {
 
 
 static const char *
-gs_executable_name()
-{
+gsExecutableName() {
+
+    const char * const which = "which gs";
+
     static char buffer[BUFFER_SIZE];
-    if(! gs_exe_path) {
-        const char * const which = "which gs";
-        FILE *f;
-        memset(buffer, 0, BUFFER_SIZE);
-        if(!(f = popen(which, "r")))
-            pm_error("Can't find ghostscript");
-        fread(buffer, 1, BUFFER_SIZE, f);
-        if(buffer[strlen(buffer) - 1] == '\n')
-            buffer[strlen(buffer) - 1] = 0;
-        pclose(f);
-        if(buffer[0] != '/' && buffer[0] != '.')
-            pm_error("Can't find ghostscript");
-    }
-    else
-        strcpy(buffer, gs_exe_path);
+
+    FILE * f;
+
+    memset(buffer, 0, BUFFER_SIZE);
+
+    f = popen(which, "r");
+    if (!f)
+        pm_error("Can't find ghostscript");
+
+    fread(buffer, 1, BUFFER_SIZE, f);
+    if (buffer[strlen(buffer) - 1] == '\n')
+        buffer[strlen(buffer) - 1] = '\0';
+    pclose(f);
+    
+    if (buffer[0] != '/' && buffer[0] != '.')
+        pm_error("Can't find ghostscript");
 
     return buffer;
 }
@@ -167,30 +214,33 @@ gs_executable_name()
 
 
 static const char *
-crop_executable_name()
-{
+cropExecutableName(void) {
+
+    const char * const which = "which pnmcrop";
+
     static char buffer[BUFFER_SIZE];
-    if(! pnmcrop_exe_path) {
-        const char * const which = "which pnmcrop";
-        FILE *f;
-        memset(buffer, 0, BUFFER_SIZE);
-        if(!(f = popen(which, "r"))) {
-            return 0;
-        }
-    
+    const char * retval;
+
+    FILE * f;
+
+    memset(buffer, 0, BUFFER_SIZE);
+
+    f = popen(which, "r");
+    if (!f)
+        retval = NULL;
+    else {
         fread(buffer, 1, BUFFER_SIZE, f);
-        if(buffer[strlen(buffer) - 1] == '\n')
+        if (buffer[strlen(buffer) - 1] == '\n')
             buffer[strlen(buffer) - 1] = 0;
         pclose(f);
-        if(buffer[0] != '/' && buffer[0] != '.') {
-            buffer[0] = 0;
+            
+        if (buffer[0] != '/' && buffer[0] != '.') {
+            retval = NULL;
             pm_message("Can't find pnmcrop");
-        }
+        } else
+            retval = buffer;
     }
-    else
-        strcpy(buffer, pnmcrop_exe_path);
-
-    return buffer;
+    return retval;
 }
 
 
@@ -201,12 +251,33 @@ gsCommand(const char *       const psFname,
           struct cmdlineInfo const cmdline) {
 
     const char * retval;
-    int const x = cmdline.res * 11;
-    int const y = cmdline.res * (cmdline.fontsize * 2 + 72)  / 72.;
+    double const x = (double) cmdline.res * 11;
+    double const y = (double) cmdline.res * 
+                     ((double) cmdline.fontsize * 2 + 72)  / 72;
+    
+    if (cmdline.res <= 0)
+         pm_error("Resolution (dpi) must be positive.");
+    
+    if (cmdline.fontsize <= 0)
+         pm_error("Font size must be positive.");
+    
+    /* The following checks are for guarding against overflows in this 
+       function.  Huge x,y values that pass these checks may be
+       rejected by the 'gs' program.
+    */
+    
+    if (x > (double) INT_MAX-10)
+         pm_error("Absurdly fine resolution: %u. Output width too large.",
+                   cmdline.res );
+    if (y > (double) INT_MAX-10)
+         pm_error("Absurdly fine resolution (%u) and/or huge font size (%u). "
+                  "Output height too large.", cmdline.res, cmdline.fontsize);
+         
     asprintfN(&retval, "%s -g%dx%d -r%d -sDEVICE=pbm "
               "-sOutputFile=%s -q -dBATCH -dNOPAUSE %s </dev/null >/dev/null", 
-              gs_executable_name(), x, y, cmdline.res, 
+              gsExecutableName(), (int) x, (int) y, cmdline.res, 
               outputFilename, psFname);
+
     return retval;
 }
 
@@ -216,11 +287,12 @@ static const char *
 cropCommand(const char * const inputFileName) {
 
     const char * retval;
+    const char * plainOpt = pm_plain_output ? "-plain" : "" ;
     
-    if (crop_executable_name()) {
-        asprintfN(&retval, "%s -top -right %s", 
-                  crop_executable_name(), inputFileName);
-        if (retval == NULL)
+    if (cropExecutableName()) {
+        asprintfN(&retval, "%s -top -right %s %s", 
+                  cropExecutableName(), plainOpt, inputFileName);
+        if (retval == strsol)
             pm_error("Unable to allocate memory");
     } else
         retval = NULL;
@@ -234,7 +306,7 @@ static void
 writeProgram(const char *       const psFname,
              struct cmdlineInfo const cmdline) {
 
-    const char *ps;
+    const char * ps;
     FILE * psfile;
 
     psfile = fopen(psFname, "w");
@@ -288,14 +360,13 @@ cropToStdout(const char * const inputFileName,
     const char * com;
 
     com = cropCommand(inputFileName);
+
     if (com == NULL) {
         /* No pnmcrop.  So don't crop. */
         pm_message("Can't find pnmcrop command, image will be large");
-        asprintfN(&com, "cat %s", inputFileName);
-        if (com == NULL) 
-            pm_error("Unable to allocate memory.");
+        writeFileToStdout(inputFileName);
     } else {
-        FILE *pnmcrop;
+        FILE * pnmcrop;
 
         if (verbose)
             pm_message("Running crop command '%s'", com);
@@ -326,8 +397,8 @@ cropToStdout(const char * const inputFileName,
             }
             fclose(pnmcrop);
         }
+        strfree(com);
     }
-    strfree(com);
 }
 
 
diff --git a/generator/pbmupc.c b/generator/pbmupc.c
index 5f694a00..6ef75654 100644
--- a/generator/pbmupc.c
+++ b/generator/pbmupc.c
@@ -433,17 +433,8 @@ putdigit( d, bits, row0, col0 )
 	    bits[row0 + row][col0 + col] = digits[d][row][col];
     }
 
-#if __STDC__
 static int
 addlines( int d, bit** bits, int row0, int col0, int height, bit color )
-#else /*__STDC__*/
-static int
-addlines( d, bits, row0, col0, height, color )
-    int d;
-    bit** bits;
-    int row0, col0, height;
-    bit color;
-#endif /*__STDC__*/
     {
     switch ( d )
 	{
@@ -524,16 +515,8 @@ addlines( d, bits, row0, col0, height, color )
     return col0;
     }
 
-#if __STDC__
 static int
 rect( bit** bits, int row0, int col0, int height, int width, bit color )
-#else /*__STDC__*/
-static int
-rect( bits, row0, col0, height, width, color )
-    bit** bits;
-    int row0, col0, height, width;
-    bit color;
-#endif /*__STDC__*/
     {
     int row, col;
 
diff --git a/generator/pgmcrater.c b/generator/pgmcrater.c
index a48f3de1..ec592381 100644
--- a/generator/pgmcrater.c
+++ b/generator/pgmcrater.c
@@ -53,7 +53,6 @@
 
 #include <assert.h>
 #include <math.h>
-#include <unistd.h>
 
 #include "pm_c_util.h"
 #include "pgm.h"
@@ -107,11 +106,10 @@ static int modulo(int t, int n)
 
 static void initseed()
 {
-    int i;
+    unsigned int i;
 
-    i = time(NULL) ^ getpid();
-    srand(i);
-    for (i = 0; i < 7; i++) 
+    srand(pm_randseed());
+    for (i = 0; i < 7; ++i) 
         V rand();
 }
 
diff --git a/generator/pgmmake.c b/generator/pgmmake.c
index 42d96581..bc7f025c 100644
--- a/generator/pgmmake.c
+++ b/generator/pgmmake.c
@@ -70,14 +70,8 @@ parseCommandLine(int argc, char ** argv,
             pm_error("Gray level must be in the range [0.0, 1.0].  "
                      "You specified %f", grayLevel);
         cmdlineP->grayLevel = ROUNDU(grayLevel * cmdlineP->maxval);
-        cmdlineP->cols = atoi(argv[2]);
-        cmdlineP->rows = atoi(argv[3]);
-        if (cmdlineP->cols <= 0)
-            pm_error("width argument must be a positive number.  You "
-                     "specified '%s'", argv[2]);
-        if (cmdlineP->rows <= 0)
-            pm_error("height argument must be a positive number.  You "
-                     "specified '%s'", argv[3]);
+        cmdlineP->cols = pm_parse_width(argv[2]);
+        cmdlineP->rows = pm_parse_height(argv[3]);
     }
 }
 
diff --git a/generator/pgmnoise.c b/generator/pgmnoise.c
index 708d0cd9..215cbfeb 100644
--- a/generator/pgmnoise.c
+++ b/generator/pgmnoise.c
@@ -1,79 +1,115 @@
+/*********************************************************************
+   pgmnoise -  create a PGM with white noise
+   Frank Neumann, October 1993
+*********************************************************************/
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "shhopt.h"
+#include "pgm.h"
 
-/*********************************************************************/
-/* pgmnoise -  create a portable graymap with white noise            */
-/* Frank Neumann, October 1993                                       */
-/* V1.1 16.11.1993                                                   */
-/*                                                                   */
-/* version history:                                                  */
-/* V1.0 12.10.1993  first version                                    */
-/* V1.1 16.11.1993  Rewritten to be NetPBM.programming conforming    */
-/*********************************************************************/
 
-#include <unistd.h>
+struct cmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    unsigned int width;
+    unsigned int height;
+    unsigned int randomseed;
+    unsigned int randomseedSpec;
+};
+
+
+
+
+static void
+parseCommandLine(int argc, const char ** const argv,
+                 struct cmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   Note that the file spec array we return is stored in the storage that
+   was passed to us as the argv array.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;
+        /* Instructions to OptParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+    unsigned int option_def_index;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0,   "randomseed",   OPT_INT,    &cmdlineP->randomseed,
+            &cmdlineP->randomseedSpec,      0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We may have parms that are negative numbers */
+
+    optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (argc-1 != 2)
+        pm_error("Wrong number of arguments: %u.  "
+                 "Arguments are width and height of image, in pixels",
+                 argc-1);
+    else {
+        int const width  = atoi(argv[1]);
+        int const height = atoi(argv[2]);
+        
+        if (width <= 0)
+            pm_error("Width must be positive, not %d", width);
+        else
+            cmdlineP->width = width;
+
+        if (height <= 0)
+            pm_error("Height must be positive, not %d", width);
+        else
+            cmdlineP->height = height;
+    }
+}
 
-#include "pgm.h"
 
-/* global variables */
-#ifdef AMIGA
-static char *version = "$VER: pgmnoise 1.1 (16.11.93)"; /* Amiga version identification */
-#endif
-
-/**************************/
-/* start of main function */
-/**************************/
-int main(argc, argv)
-int argc;
-char *argv[];
-{
-	int argn, rows, cols, i, j;
-	gray *destrow;
-	const char * const usage = "width height\n        width and height are picture dimensions in pixels\n";
-	time_t timenow;
-
-	/* parse in 'default' parameters */
-	pgm_init(&argc, argv);
-
-	argn = 1;
-
-	/* parse in dim factor */
-	if (argn == argc)
-		pm_usage(usage);
-	if (sscanf(argv[argn], "%d", &cols) != 1)
-		pm_usage(usage);
-	argn++;
-	if (argn == argc)
-		pm_usage(usage);
-	if (sscanf(argv[argn], "%d", &rows) != 1)
-		pm_usage(usage);
-
-	if (cols <= 0 || rows <= 0)
-		pm_error("picture dimensions should be positive numbers");
-	++argn;
-
-	if (argn != argc)
-		pm_usage(usage);
-
-	/* no error checking required here, ppmlib does it all for us */
-	destrow = pgm_allocrow(cols);
-
-	pgm_writepgminit(stdout, cols, rows, PGM_MAXMAXVAL, 0);
-
-	/* get time of day to feed the random number generator */
-	timenow = time(NULL);
-	srand(timenow ^ getpid());
-
-	/* create the (gray) noise */
-	for (i = 0; i < rows; i++)
-	{
-		for (j = 0; j < cols; j++)
-			destrow[j] = rand() % (PGM_MAXMAXVAL+1);
-
-		/* write out one line of graphic data */
-		pgm_writepgmrow(stdout, destrow, cols, PGM_MAXMAXVAL, 0);
-	}
-
-	pgm_freerow(destrow);
-
-	exit(0);
+
+
+static void
+pgmnoise(FILE * const ofP,
+         unsigned int const cols,
+         unsigned int const rows,
+         gray         const maxval) {
+
+    unsigned int row;
+    gray * destrow;
+
+    destrow = pgm_allocrow(cols);
+
+    pgm_writepgminit(ofP, cols, rows, maxval, 0);
+
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+        for (col = 0; col < cols; ++col)
+            destrow[col] = rand() % (maxval + 1);
+
+        pgm_writepgmrow(ofP, destrow, cols, maxval, 0);
+    }
+
+    pgm_freerow(destrow);
+}
+
+
+
+int main(int          argc,
+         const char * argv[]) {
+    
+    struct cmdlineInfo cmdline;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    srand(cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed());
+
+    pgmnoise(stdout, cmdline.width, cmdline.height, PGM_MAXMAXVAL);
+
+    return 0;
 }
 
diff --git a/generator/pgmramp.c b/generator/pgmramp.c
index b84ed345..c0fb42b1 100644
--- a/generator/pgmramp.c
+++ b/generator/pgmramp.c
@@ -11,6 +11,8 @@
 */
 
 #include <math.h>
+
+#include "pm_c_util.h"
 #include "pgm.h"
 #include "shhopt.h"
 
@@ -96,14 +98,8 @@ parseCommandLine(int argc, char ** argv,
         pm_error("Only two arguments allowed: width and height.  "
                  "You specified %d", argc-1);
     else {
-        cmdlineP->cols = atoi(argv[1]);
-        cmdlineP->rows = atoi(argv[2]);
-        if (cmdlineP->cols <= 0)
-            pm_error("width argument must be a positive number.  You "
-                     "specified '%s'", argv[1]);
-        if (cmdlineP->rows <= 0)
-            pm_error("height argument must be a positive number.  You "
-                     "specified '%s'", argv[2]);
+        cmdlineP->cols = pm_parse_width(argv[1]);
+        cmdlineP->rows = pm_parse_height(argv[2]);
     }
 }
 
diff --git a/generator/ppmcolors.c b/generator/ppmcolors.c
index 9112e1b8..ecae2285 100644
--- a/generator/ppmcolors.c
+++ b/generator/ppmcolors.c
@@ -9,6 +9,7 @@
 
 ******************************************************************************/
 
+#include "pm_c_util.h"
 #include "ppm.h"
 #include "shhopt.h"
 #include "nstring.h"
diff --git a/generator/ppmforge.c b/generator/ppmforge.c
index fcbbc1f1..80e35822 100644
--- a/generator/ppmforge.c
+++ b/generator/ppmforge.c
@@ -35,7 +35,6 @@
 
 #include <math.h>
 #include <assert.h>
-#include <unistd.h>
 
 #include "pm_c_util.h"
 #include "ppm.h"
@@ -283,10 +282,9 @@ static unsigned int
 initseed(void) {
     /*  Generate initial random seed.  */
 
-    int i;
+    unsigned int i;
 
-    i = time(NULL) ^ getpid();
-    srand(i);
+    srand(pm_randseed());
     for (i = 0; i < 7; ++i)
         rand();
     return rand();
diff --git a/generator/ppmmake.c b/generator/ppmmake.c
index eee32485..e59b47d5 100644
--- a/generator/ppmmake.c
+++ b/generator/ppmmake.c
@@ -76,14 +76,8 @@ parseCommandLine(int argc, char ** argv,
                  "You specified %d", argc-1);
     else {
         cmdlineP->color = ppm_parsecolor(argv[1], cmdlineP->maxval);
-        cmdlineP->cols = atoi(argv[2]);
-        cmdlineP->rows = atoi(argv[3]);
-        if (cmdlineP->cols <= 0)
-            pm_error("width argument must be a positive number.  You "
-                     "specified '%s'", argv[2]);
-        if (cmdlineP->rows <= 0)
-            pm_error("height argument must be a positive number.  You "
-                     "specified '%s'", argv[3]);
+        cmdlineP->cols = pm_parse_width(argv[2]);
+        cmdlineP->rows = pm_parse_height(argv[3]);
     }
 }
 
diff --git a/generator/ppmpat.c b/generator/ppmpat.c
index 9e2f6d05..82acafae 100644
--- a/generator/ppmpat.c
+++ b/generator/ppmpat.c
@@ -12,17 +12,244 @@
 
 #define _XOPEN_SOURCE  /* get M_PI in math.h */
 
+#include <assert.h>
 #include <math.h>
+#include <limits.h>
 
 #include "pm_c_util.h"
+#include "mallocvar.h"
+#include "shhopt.h"
 #include "ppm.h"
 #include "ppmdraw.h"
 
 
+typedef enum {
+    PAT_GINGHAM2,
+    PAT_GINGHAM3,
+    PAT_MADRAS,
+    PAT_TARTAN,
+    PAT_POLES,
+    PAT_SQUIG,
+    PAT_CAMO,
+    PAT_ANTICAMO
+} pattern;
+
+struct cmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    pattern basePattern;
+    unsigned int width;
+    unsigned int height;
+};
+
+
+
+static void
+parseCommandLine(int argc, const char ** argv,
+                 struct cmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   Note that the file spec array we return is stored in the storage that
+   was passed to us as the argv array.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;
+        /* Instructions to OptParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+    unsigned int basePatternCount;
+    unsigned int gingham2;
+    unsigned int gingham3;
+    unsigned int madras;
+    unsigned int tartan;
+    unsigned int poles;
+    unsigned int squig;
+    unsigned int camo;
+    unsigned int anticamo;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "gingham2",  OPT_FLAG,   NULL, &gingham2,   0);
+    OPTENT3(0, "g2",        OPT_FLAG,   NULL, &gingham2,   0);
+    OPTENT3(0, "gingham3",  OPT_FLAG,   NULL, &gingham3,   0);
+    OPTENT3(0, "g3",        OPT_FLAG,   NULL, &gingham3,   0);
+    OPTENT3(0, "madras",    OPT_FLAG,   NULL, &madras,     0);
+    OPTENT3(0, "tartan",    OPT_FLAG,   NULL, &tartan,     0);
+    OPTENT3(0, "poles",     OPT_FLAG,   NULL, &poles,      0);
+    OPTENT3(0, "squig",     OPT_FLAG,   NULL, &squig,      0);
+    OPTENT3(0, "camo",      OPT_FLAG,   NULL, &camo,       0);
+    OPTENT3(0, "anticamo",  OPT_FLAG,   NULL, &anticamo,   0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
+
+    optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    basePatternCount =
+        gingham2 +
+        gingham3 +
+        madras +
+        tartan +
+        poles +
+        squig +
+        camo +
+        anticamo;
+
+    if (basePatternCount < 1)
+        pm_error("You must specify a base pattern option such as -gingham2");
+    else if (basePatternCount > 1)
+        pm_error("You may not specify more than one base pattern option.  "
+                 "You specified %u", basePatternCount);
+    else {
+        if (gingham2)
+            cmdlineP->basePattern = PAT_GINGHAM2;
+        else if (gingham3)
+            cmdlineP->basePattern = PAT_GINGHAM3;
+        else if (madras)
+            cmdlineP->basePattern = PAT_MADRAS;
+        else if (tartan)
+            cmdlineP->basePattern = PAT_TARTAN;
+        else if (poles)
+            cmdlineP->basePattern = PAT_POLES;
+        else if (squig)
+            cmdlineP->basePattern = PAT_SQUIG;
+        else if (camo)
+            cmdlineP->basePattern = PAT_CAMO;
+        else if (anticamo)
+            cmdlineP->basePattern = PAT_ANTICAMO;
+        else
+            assert(false);  /* Every possibility is accounted for */
+    }
+    if (argc-1 != 2)
+        pm_error("You must specify 2 non-option arguments: width and height "
+                 "in pixels.  You specified %u", argc-1);
+    else {
+        cmdlineP->width  = atoi(argv[1]);
+        cmdlineP->height = atoi(argv[2]);
+
+        if (cmdlineP->width < 1)
+            pm_error("Width must be at least 1 pixel");
+        if (cmdlineP->height < 1)
+            pm_error("Height must be at least 1 pixel");
+    }
+}
+
+
+
+static void
+validateComputableDimensions(unsigned int const cols,
+                             unsigned int const rows) {
+
+    /*
+      Notes on width and height limits:
+
+      cols * 3, rows * 3 appear in madras, tartan
+      cols*rows appears in poles
+      cols+rows appears in squig
+
+      PPMD functions use signed integers for pixel positions
+      (because they allow you to specify points off the canvas).
+    */
+      
+    if (cols > INT_MAX/4 || rows > INT_MAX/4 || rows > INT_MAX/cols)
+        pm_error("Width and/or height are way too large: %u x %u",
+                 cols, rows);
+}
+
+
+
+static pixel
+randomColor(pixval const maxval) {
+
+    pixel p;
+
+    PPM_ASSIGN(p,
+               rand() % (maxval + 1),
+               rand() % (maxval + 1),
+               rand() % (maxval + 1)
+        );
+    
+    return p;
+}
+
+
+
+#define DARK_THRESH 0.25
+
+static pixel
+randomBrightColor(pixval const maxval) {
+
+    pixel p;
+
+    do {
+        p = randomColor(maxval);
+    } while (PPM_LUMIN(p) <= maxval * DARK_THRESH);
+
+    return p;
+}
+
+
+
+static pixel
+randomDarkColor(pixval const maxval) {
+
+    pixel p;
+
+    do {
+        p = randomColor(maxval);
+    } while (PPM_LUMIN(p) > maxval * DARK_THRESH);
+
+    return p;
+}
+
+
+
+static pixel
+averageTwoColors(pixel const p1,
+                 pixel const p2) {
+
+    pixel p;
+
+    PPM_ASSIGN(p,
+               (PPM_GETR(p1) + PPM_GETR(p2)) / 2,
+               (PPM_GETG(p1) + PPM_GETG(p2)) / 2,
+               (PPM_GETB(p1) + PPM_GETB(p2)) / 2);
+
+    return p;
+}
+
+
+
+static ppmd_drawproc average_drawproc;
+
+static void
+average_drawproc(pixel **     const pixels, 
+                 int          const cols, 
+                 int          const rows, 
+                 pixval       const maxval, 
+                 int          const col, 
+                 int          const row, 
+                 const void * const clientdata) {
+
+    if (col >= 0 && col < cols && row >= 0 && row < rows)
+        pixels[row][col] =
+            averageTwoColors(pixels[row][col], *((const pixel*) clientdata));
+}
+
+
+
+/*----------------------------------------------------------------------------
+   Camouflage stuff
+-----------------------------------------------------------------------------*/
+
 
 
 static pixel
-random_anticamo_color(pixval const maxval) {
+randomAnticamoColor(pixval const maxval) {
 
     int v1, v2, v3;
     pixel p;
@@ -70,17 +297,14 @@ random_anticamo_color(pixval const maxval) {
 
 
 
-/* Camouflage stuff. */
-
 static pixel
-random_camo_color(pixval const maxval) {
+randomCamoColor(pixval const maxval) {
 
-    int v1, v2, v3;
-    pixel p;
+    int const v1 = (maxval + 1 ) / 8;
+    int const v2 = (maxval + 1 ) / 4;
+    int const v3 = (maxval + 1 ) / 2;
 
-    v1 = (maxval + 1 ) / 8;
-    v2 = (maxval + 1 ) / 4;
-    v3 = (maxval + 1 ) / 2;
+    pixel p;
 
     switch (rand() % 10) {
     case 0:
@@ -122,6 +346,46 @@ rnduni(void) {
 
 
 
+static void
+clearBackground(pixel **     const pixels,
+                unsigned int const cols,
+                unsigned int const rows,
+                pixval       const maxval,
+                bool         const antiflag) {
+
+    pixel color;
+
+    if (antiflag)
+        color = randomAnticamoColor(maxval);
+    else
+        color = randomCamoColor(maxval);
+
+    ppmd_filledrectangle(
+        pixels, cols, rows, maxval, 0, 0, cols, rows, PPMD_NULLDRAWPROC,
+        &color);
+}
+
+
+static void
+camoFill(pixel **         const pixels,
+         unsigned int     const cols,
+         unsigned int     const rows,
+         pixval           const maxval,
+         struct fillobj * const fh,
+         bool             const antiflag) {
+         
+    pixel color;
+
+    if (antiflag)
+        color = randomAnticamoColor(maxval);
+    else
+        color = randomCamoColor(maxval);
+
+    ppmd_fill(pixels, cols, rows, maxval, fh, PPMD_NULLDRAWPROC, &color);
+}        
+
+
+
 #define BLOBRAD 50
 
 #define MIN_POINTS 7
@@ -136,63 +400,68 @@ rnduni(void) {
 
 
 static void
+computeXsYs(int *        const xs,
+            int *        const ys,
+            unsigned int const cols,
+            unsigned int const rows,
+            unsigned int const pointCt) {
+
+    unsigned int const cx = rand() % cols;
+    unsigned int const cy = rand() % rows;
+    double const a = rnduni() * (MAX_ELLIPSE_FACTOR - MIN_ELLIPSE_FACTOR) +
+        MIN_ELLIPSE_FACTOR;
+    double const b = rnduni() * (MAX_ELLIPSE_FACTOR - MIN_ELLIPSE_FACTOR) +
+        MIN_ELLIPSE_FACTOR;
+    double const theta = rnduni() * 2.0 * M_PI;
+    
+    unsigned int p;
+        
+    for (p = 0; p < pointCt; ++p) {
+        double const c = rnduni() * (MAX_POINT_FACTOR - MIN_POINT_FACTOR) +
+            MIN_POINT_FACTOR;
+        double const tx   = a * sin(p * 2.0 * M_PI / pointCt);
+        double const ty   = b * cos(p * 2.0 * M_PI / pointCt);
+        double const tang = atan2(ty, tx) + theta;
+        xs[p] = MAX(0, MIN(cols-1, cx + BLOBRAD * c * sin(tang)));
+        ys[p] = MAX(0, MIN(rows-1, cy + BLOBRAD * c * cos(tang)));
+    }
+}
+
+
+
+static void
 camo(pixel **     const pixels,
      unsigned int const cols,
      unsigned int const rows,
      pixval       const maxval,
      bool         const antiflag) {
 
-    pixel color;
-    int n, i, cx, cy;
-    struct fillobj * fh;
+    unsigned int const n = (rows * cols) / (BLOBRAD * BLOBRAD) * 5;
 
-    /* Clear background. */
-    if (antiflag)
-        color = random_anticamo_color( maxval );
-    else
-        color = random_camo_color( maxval );
+    unsigned int i;
 
-    ppmd_filledrectangle(
-        pixels, cols, rows, maxval, 0, 0, cols, rows, PPMD_NULLDRAWPROC,
-        &color);
+    clearBackground(pixels, cols, rows, maxval, antiflag);
 
-    n = (rows * cols) / (BLOBRAD * BLOBRAD) * 5;
     for (i = 0; i < n; ++i) {
-        int points, p, xs[MAX_POINTS], ys[MAX_POINTS], x0, y0;
-        float a, b, c, theta, tang, tx, ty;
-        
-        cx = rand() % cols;
-        cy = rand() % rows;
-        
-        points = rand() % ( MAX_POINTS - MIN_POINTS + 1 ) + MIN_POINTS;
-        a = rnduni() * (MAX_ELLIPSE_FACTOR - MIN_ELLIPSE_FACTOR) +
-            MIN_ELLIPSE_FACTOR;
-        b = rnduni() * (MAX_ELLIPSE_FACTOR - MIN_ELLIPSE_FACTOR) +
-            MIN_ELLIPSE_FACTOR;
-        theta = rnduni() * 2.0 * M_PI;
-        for (p = 0; p < points; ++p) {
-            tx = a * sin(p * 2.0 * M_PI / points);
-            ty = b * cos(p * 2.0 * M_PI / points);
-            tang = atan2(ty, tx) + theta;
-            c = rnduni() * (MAX_POINT_FACTOR - MIN_POINT_FACTOR) +
-                MIN_POINT_FACTOR;
-            xs[p] = cx + BLOBRAD * c * sin(tang);
-            ys[p] = cy + BLOBRAD * c * cos(tang);
-        }
-        x0 = (xs[0] + xs[points - 1]) / 2;
-        y0 = (ys[0] + ys[points - 1]) / 2;
+        unsigned int const pointCt =
+            rand() % (MAX_POINTS - MIN_POINTS + 1) + MIN_POINTS;
+
+        int xs[MAX_POINTS], ys[MAX_POINTS];
+        int x0, y0;
+        struct fillobj * fh;
+
+        computeXsYs(xs, ys, cols, rows, pointCt);
+
+        x0 = (xs[0] + xs[pointCt - 1]) / 2;
+        y0 = (ys[0] + ys[pointCt - 1]) / 2;
 
         fh = ppmd_fill_create();
 
         ppmd_polyspline(
-            pixels, cols, rows, maxval, x0, y0, points, xs, ys, x0, y0,
-            ppmd_fill_drawproc, fh );
+            pixels, cols, rows, maxval, x0, y0, pointCt, xs, ys, x0, y0,
+            ppmd_fill_drawproc, fh);
         
-        if (antiflag)
-            color = random_anticamo_color(maxval);
-        else
-            color = random_camo_color(maxval);
-        ppmd_fill(pixels, cols, rows, maxval, fh, PPMD_NULLDRAWPROC, &color);
+        camoFill(pixels, cols, rows, maxval, fh, antiflag);
         
         ppmd_fill_destroy(fh);
     }
@@ -200,499 +469,454 @@ camo(pixel **     const pixels,
 
 
 
-static pixel
-random_color(pixval const maxval) {
-
-    pixel p;
-
-    PPM_ASSIGN(p,
-               rand() % (maxval + 1),
-               rand() % (maxval + 1),
-               rand() % (maxval + 1)
-        );
-    
-    return p;
-}
-
-
-
-#define DARK_THRESH 0.25
+/*----------------------------------------------------------------------------
+   Gingham stuff
+-----------------------------------------------------------------------------*/
 
-#if __STDC__
-static pixel
-random_bright_color( pixval maxval )
-#else /*__STDC__*/
-static pixel
-random_bright_color( maxval )
-    pixval maxval;
-#endif /*__STDC__*/
-    {
-    pixel p;
 
-    do
-    {
-    p = random_color( maxval );
-    }
-    while ( PPM_LUMIN( p ) <= maxval * DARK_THRESH );
-
-    return p;
-    }
-
-#if __STDC__
-static pixel
-random_dark_color( pixval maxval )
-#else /*__STDC__*/
-static pixel
-random_dark_color( maxval )
-    pixval maxval;
-#endif /*__STDC__*/
-    {
-    pixel p;
-
-    do
-    {
-    p = random_color( maxval );
-    }
-    while ( PPM_LUMIN( p ) > maxval * DARK_THRESH );
-
-    return p;
-    }
-
-static pixel
-average_two_colors( p1, p2 )
-pixel p1, p2;
-    {
-    pixel p;
-
-    PPM_ASSIGN(
-    p, ( (int) PPM_GETR(p1) + (int) PPM_GETR(p2) ) / 2,
-    ( (int) PPM_GETG(p1) + (int) PPM_GETG(p2) ) / 2,
-    ( (int) PPM_GETB(p1) + (int) PPM_GETB(p2) ) / 2 );
-
-    return p;
-    }
-
-/* Gingham stuff. */
 
 static void
-average_drawproc(pixel** const pixels, 
-                 int const cols, 
-                 int const rows, 
-                 pixval const maxval, 
-                 int const col, 
-                 int const row, 
-                 const void* const clientdata )
-{
-    if ( col >= 0 && col < cols && row >= 0 && row < rows )
-        pixels[row][col] =
-            average_two_colors( pixels[row][col], *( (pixel*) clientdata ) );
-}
+gingham2(pixel **     const pixels,
+         unsigned int const cols,
+         unsigned int const rows,
+         pixval       const maxval) {
 
-static void
-gingham2( pixel** pixels, int cols, int rows, pixval maxval )
-{
-    pixel const backcolor = random_dark_color( maxval );
-    pixel const forecolor = random_bright_color( maxval );
-    int const colso2 = cols / 2;
-    int const rowso2 = rows / 2;
+    pixel const backcolor = randomDarkColor(maxval);
+    pixel const forecolor = randomBrightColor(maxval);
+    unsigned int const colso2 = cols / 2;
+    unsigned int const rowso2 = rows / 2;
 
     /* Warp. */
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 0, colso2, rows, PPMD_NULLDRAWPROC,
-        &backcolor );
+        &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, colso2, 0, cols - colso2, rows,
-        PPMD_NULLDRAWPROC, &forecolor );
+        PPMD_NULLDRAWPROC, &forecolor);
 
     /* Woof. */
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 0, cols, rowso2, average_drawproc,
-        &backcolor );
+        &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rowso2, cols, rows - rowso2,
-        average_drawproc, &forecolor );
-    }
+        average_drawproc, &forecolor);
+}
+
+
 
-#if __STDC__
-static void
-gingham3( pixel** pixels, int cols, int rows, pixval maxval )
-#else /*__STDC__*/
 static void
-gingham3( pixels, cols, rows, maxval )
-    pixel** pixels;
-    int cols, rows;
-    pixval maxval;
-#endif /*__STDC__*/
-    {
-    int colso4, rowso4;
-    pixel backcolor, fore1color, fore2color;
-
-    colso4 = cols / 4;
-    rowso4 = rows / 4;
-    backcolor = random_dark_color( maxval );
-    fore1color = random_bright_color( maxval );
-    fore2color = random_bright_color( maxval );
+gingham3(pixel **     const pixels,
+         unsigned int const cols,
+         unsigned int const rows,
+         pixval       const maxval) {
+
+    unsigned int const colso4 = cols / 4;
+    unsigned int const rowso4 = rows / 4;
+
+    pixel const backcolor  = randomDarkColor(maxval);
+    pixel const fore1color = randomBrightColor(maxval);
+    pixel const fore2color = randomBrightColor(maxval);
 
     /* Warp. */
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 0, colso4, rows, PPMD_NULLDRAWPROC,
-        &backcolor );
+        &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, colso4, 0, colso4, rows, PPMD_NULLDRAWPROC,
-        &fore1color );
+        &fore1color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 2 * colso4, 0, colso4, rows,
-        PPMD_NULLDRAWPROC, &fore2color );
+        PPMD_NULLDRAWPROC, &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 3 * colso4, 0, cols - colso4, rows,
-        PPMD_NULLDRAWPROC, &fore1color );
+        PPMD_NULLDRAWPROC, &fore1color);
 
     /* Woof. */
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 0, cols, rowso4, average_drawproc,
-        &backcolor );
+        &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rowso4, cols, rowso4, average_drawproc,
-        &fore1color );
+        &fore1color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 2 * rowso4, cols, rowso4,
-        average_drawproc, &fore2color );
+        average_drawproc, &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 3 * rowso4, cols, rows - rowso4,
-        average_drawproc, &fore1color );
-    }
+        average_drawproc, &fore1color);
+}
+
+
 
-#if __STDC__
-static void
-madras( pixel** pixels, int cols, int rows, pixval maxval )
-#else /*__STDC__*/
 static void
-madras( pixels, cols, rows, maxval )
-    pixel** pixels;
-    int cols, rows;
-    pixval maxval;
-#endif /*__STDC__*/
-    {
-    int cols2, rows2, cols3, rows3, cols12, rows12, cols6a, rows6a, cols6b,
-    rows6b;
-    pixel backcolor, fore1color, fore2color;
-
-    cols2 = cols * 2 / 44;
-    rows2 = rows * 2 / 44;
-    cols3 = cols * 3 / 44;
-    rows3 = rows * 3 / 44;
-    cols12 = cols - 10 * cols2 - 4 * cols3;
-    rows12 = rows - 10 * rows2 - 4 * rows3;
-    cols6a = cols12 / 2;
-    rows6a = rows12 / 2;
-    cols6b = cols12 - cols6a;
-    rows6b = rows12 - rows6a;
-    backcolor = random_dark_color( maxval );
-    fore1color = random_bright_color( maxval );
-    fore2color = random_bright_color( maxval );
+madras(pixel **     const pixels,
+       unsigned int const cols,
+       unsigned int const rows,
+       pixval       const maxval) {
+
+    unsigned int const cols2  = cols * 2 / 44;
+    unsigned int const rows2  = rows * 2 / 44;
+    unsigned int const cols3  = cols * 3 / 44;
+    unsigned int const rows3  = rows * 3 / 44;
+    unsigned int const cols12 = cols - 10 * cols2 - 4 * cols3;
+    unsigned int const rows12 = rows - 10 * rows2 - 4 * rows3;
+    unsigned int const cols6a = cols12 / 2;
+    unsigned int const rows6a = rows12 / 2;
+    unsigned int const cols6b = cols12 - cols6a;
+    unsigned int const rows6b = rows12 - rows6a;
+    pixel const backcolor  = randomDarkColor(maxval);
+    pixel const fore1color = randomBrightColor(maxval);
+    pixel const fore2color = randomBrightColor(maxval);
 
     /* Warp. */
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 0, cols2, rows, PPMD_NULLDRAWPROC,
-        &backcolor );
+        &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, cols2, 0, cols3, rows, PPMD_NULLDRAWPROC,
-        &fore1color );
+        &fore1color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, cols2 + cols3, 0, cols2, rows,
-        PPMD_NULLDRAWPROC, &backcolor );
+        PPMD_NULLDRAWPROC, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 2 * cols2 + cols3, 0, cols2, rows,
-        PPMD_NULLDRAWPROC, &fore2color );
+        PPMD_NULLDRAWPROC, &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 3 * cols2 + cols3, 0, cols2, rows,
-        PPMD_NULLDRAWPROC, &backcolor );
+        PPMD_NULLDRAWPROC, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 4 * cols2 + cols3, 0, cols6a, rows,
-        PPMD_NULLDRAWPROC, &fore1color );
+        PPMD_NULLDRAWPROC, &fore1color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 4 * cols2 + cols3 + cols6a, 0, cols2, rows,
-        PPMD_NULLDRAWPROC, &backcolor );
+        PPMD_NULLDRAWPROC, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 5 * cols2 + cols3 + cols6a, 0, cols3, rows,
-        PPMD_NULLDRAWPROC, &fore2color );
+        PPMD_NULLDRAWPROC, &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 5 * cols2 + 2 * cols3 + cols6a, 0, cols2,
-        rows, PPMD_NULLDRAWPROC, &backcolor );
+        rows, PPMD_NULLDRAWPROC, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 6 * cols2 + 2 * cols3 + cols6a, 0, cols3,
-        rows, PPMD_NULLDRAWPROC, &fore2color );
+        rows, PPMD_NULLDRAWPROC, &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 6 * cols2 + 3 * cols3 + cols6a, 0, cols2,
-        rows, PPMD_NULLDRAWPROC, &backcolor );
+        rows, PPMD_NULLDRAWPROC, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 7 * cols2 + 3 * cols3 + cols6a, 0, cols6b,
-        rows, PPMD_NULLDRAWPROC, &fore1color );
+        rows, PPMD_NULLDRAWPROC, &fore1color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 7 * cols2 + 3 * cols3 + cols6a + cols6b, 0,
-        cols2, rows, PPMD_NULLDRAWPROC, &backcolor );
+        cols2, rows, PPMD_NULLDRAWPROC, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 8 * cols2 + 3 * cols3 + cols6a + cols6b, 0,
-        cols2, rows, PPMD_NULLDRAWPROC, &fore2color );
+        cols2, rows, PPMD_NULLDRAWPROC, &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 9 * cols2 + 3 * cols3 + cols6a + cols6b, 0,
-        cols2, rows, PPMD_NULLDRAWPROC, &backcolor );
+        cols2, rows, PPMD_NULLDRAWPROC, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 10 * cols2 + 3 * cols3 + cols6a + cols6b, 
-        0, cols3, rows, PPMD_NULLDRAWPROC, &fore1color );
+        0, cols3, rows, PPMD_NULLDRAWPROC, &fore1color);
 
     /* Woof. */
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 0, cols, rows2, average_drawproc,
-        &backcolor );
+        &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rows2, cols, rows3, average_drawproc,
-        &fore2color );
+        &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rows2 + rows3, cols, rows2,
-        average_drawproc, &backcolor );
+        average_drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 2 * rows2 + rows3, cols, rows2,
-        average_drawproc, &fore1color );
+        average_drawproc, &fore1color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 3 * rows2 + rows3, cols, rows2,
-        average_drawproc, &backcolor );
+        average_drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 4 * rows2 + rows3, cols, rows6a,
-        average_drawproc, &fore2color );
+        average_drawproc, &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 4 * rows2 + rows3 + rows6a, cols, rows2,
-        average_drawproc, &backcolor );
+        average_drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 5 * rows2 + rows3 + rows6a, cols, rows3,
-        average_drawproc, &fore1color );
+        average_drawproc, &fore1color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 5 * rows2 + 2 * rows3 + rows6a, cols,
-        rows2, average_drawproc, &backcolor );
+        rows2, average_drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 6 * rows2 + 2 * rows3 + rows6a, cols,
-        rows3, average_drawproc, &fore1color );
+        rows3, average_drawproc, &fore1color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 6 * rows2 + 3 * rows3 + rows6a, cols,
-        rows2, average_drawproc, &backcolor );
+        rows2, average_drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 7 * rows2 + 3 * rows3 + rows6a, cols,
-        rows6b, average_drawproc, &fore2color );
+        rows6b, average_drawproc, &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 7 * rows2 + 3 * rows3 + rows6a + rows6b,
-        cols, rows2, average_drawproc, &backcolor );
+        cols, rows2, average_drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 8 * rows2 + 3 * rows3 + rows6a + rows6b,
-        cols, rows2, average_drawproc, &fore1color );
+        cols, rows2, average_drawproc, &fore1color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 9 * rows2 + 3 * rows3 + rows6a + rows6b,
-        cols, rows2, average_drawproc, &backcolor );
+        cols, rows2, average_drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 
         10 * rows2 + 3 * rows3 + rows6a + rows6b,
-        cols, rows3, average_drawproc, &fore2color );
-    }
+        cols, rows3, average_drawproc, &fore2color);
+}
+
+
 
-#if __STDC__
-static void
-tartan( pixel** pixels, int cols, int rows, pixval maxval )
-#else /*__STDC__*/
 static void
-tartan( pixels, cols, rows, maxval )
-    pixel** pixels;
-    int cols, rows;
-    pixval maxval;
-#endif /*__STDC__*/
-    {
-    int cols1, rows1, cols3, rows3, cols10, rows10, cols5a, rows5a, cols5b,
-    rows5b;
-    pixel backcolor, fore1color, fore2color;
-
-    cols1 = cols / 22;
-    rows1 = rows / 22;
-    cols3 = cols * 3 / 22;
-    rows3 = rows * 3 / 22;
-    cols10 = cols - 3 * cols1 - 3 * cols3;
-    rows10 = rows - 3 * rows1 - 3 * rows3;
-    cols5a = cols10 / 2;
-    rows5a = rows10 / 2;
-    cols5b = cols10 - cols5a;
-    rows5b = rows10 - rows5a;
-    backcolor = random_dark_color( maxval );
-    fore1color = random_bright_color( maxval );
-    fore2color = random_bright_color( maxval );
+tartan(pixel **     const pixels,
+       unsigned int const cols,
+       unsigned int const rows,
+       pixval       const maxval) {
+
+    unsigned int const cols1  = cols / 22;
+    unsigned int const rows1  = rows / 22;
+    unsigned int const cols3  = cols * 3 / 22;
+    unsigned int const rows3  = rows * 3 / 22;
+    unsigned int const cols10 = cols - 3 * cols1 - 3 * cols3;
+    unsigned int const rows10 = rows - 3 * rows1 - 3 * rows3;
+    unsigned int const cols5a = cols10 / 2;
+    unsigned int const rows5a = rows10 / 2;
+    unsigned int const cols5b = cols10 - cols5a;
+    unsigned int const rows5b = rows10 - rows5a;
+    pixel const backcolor  = randomDarkColor(maxval);
+    pixel const fore1color = randomBrightColor(maxval);
+    pixel const fore2color = randomBrightColor(maxval);
 
     /* Warp. */
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 0, cols5a, rows, PPMD_NULLDRAWPROC,
-        &backcolor );
+        &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, cols5a, 0, cols1, rows, PPMD_NULLDRAWPROC,
-        &fore1color );
+        &fore1color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, cols5a + cols1, 0, cols5b, rows,
         PPMD_NULLDRAWPROC, &backcolor );
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, cols10 + cols1, 0, cols3, rows,
-        PPMD_NULLDRAWPROC, &fore2color );
+        PPMD_NULLDRAWPROC, &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, cols10 + cols1 + cols3, 0, cols1, rows,
-        PPMD_NULLDRAWPROC, &backcolor );
+        PPMD_NULLDRAWPROC, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, cols10 + 2 * cols1 + cols3, 0, cols3, rows,
-        PPMD_NULLDRAWPROC, &fore2color );
+        PPMD_NULLDRAWPROC, &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, cols10 + 2 * cols1 + 2 * cols3, 0, cols1,
-        rows, PPMD_NULLDRAWPROC, (char*) &backcolor );
+        rows, PPMD_NULLDRAWPROC, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, cols10 + 3 * cols1 + 2 * cols3, 0, cols3,
-        rows, PPMD_NULLDRAWPROC, &fore2color );
+        rows, PPMD_NULLDRAWPROC, &fore2color);
 
     /* Woof. */
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 0, cols, rows5a, average_drawproc,
-        &backcolor );
+        &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rows5a, cols, rows1, average_drawproc,
-        &fore1color );
+        &fore1color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rows5a + rows1, cols, rows5b,
-        average_drawproc, &backcolor );
+        average_drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rows10 + rows1, cols, rows3,
-        average_drawproc, &fore2color );
+        average_drawproc, &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rows10 + rows1 + rows3, cols, rows1,
-        average_drawproc, &backcolor );
+        average_drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rows10 + 2 * rows1 + rows3, cols, rows3,
-        average_drawproc, &fore2color );
+        average_drawproc, &fore2color);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rows10 + 2 * rows1 + 2 * rows3, cols,
-        rows1, average_drawproc, &backcolor );
+        rows1, average_drawproc, &backcolor);
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, rows10 + 3 * rows1 + 2 * rows3, cols,
-        rows3, average_drawproc, &fore2color );
-    }
+        rows3, average_drawproc, &fore2color);
+}
+
+
+
+/*----------------------------------------------------------------------------
+   Poles stuff
+-----------------------------------------------------------------------------*/
+
 
-/* Poles stuff. */
 
 #define MAXPOLES 500
 
-#if __STDC__
-static void
-poles( pixel** pixels, int cols, int rows, pixval maxval )
-#else /*__STDC__*/
+
+
 static void
-poles( pixels, cols, rows, maxval )
-    pixel** pixels;
-    int cols, rows;
-    pixval maxval;
-#endif /*__STDC__*/
-    {
-    int poles, i, xs[MAXPOLES], ys[MAXPOLES], col, row;
-    pixel colors[MAXPOLES];
+placeAndColorPolesRandomly(int *        const xs,
+                           int *        const ys,
+                           pixel *      const colors,
+                           unsigned int const cols,
+                           unsigned int const rows,
+                           pixval       const maxval,
+                           unsigned int const poleCt) {
 
-    poles = cols * rows / 30000;
+    unsigned int i;
 
-    /* Place and color poles randomly. */
-    for ( i = 0; i < poles; ++i )
-    {
-    xs[i] = rand() % cols;
-    ys[i] = rand() % rows;
-    colors[i] = random_bright_color( maxval );
+    for (i = 0; i < poleCt; ++i) {
+        xs[i] = rand() % cols;
+        ys[i] = rand() % rows;
+        colors[i] = randomBrightColor(maxval);
     }
+}
 
-    /* Now interpolate points. */
-    for ( row = 0; row < rows; ++row )
-    for ( col = 0; col < cols; ++col )
-        {
-        register long dist1, dist2, newdist, r, g, b;
-        pixel color1, color2;
 
-        /* Find two closest poles. */
-        dist1 = dist2 = 2000000000;
-        for ( i = 0; i < poles; ++i )
-        {
-        newdist = ( col - xs[i] ) * ( col - xs[i] ) +
-              ( row - ys[i] ) * ( row - ys[i] );
-        if ( newdist < dist1 )
-            {
-            dist1 = newdist;
-            color1 = colors[i];
-            }
-        else if ( newdist < dist2 )
-            {
-            dist2 = newdist;
-            color2 = colors[i];
-            }
-        }
 
-        /* And assign interpolated color. */
-        newdist = dist1 + dist2;
-        r = PPM_GETR(color1)*dist2/newdist + PPM_GETR(color2)*dist1/newdist;
-        g = PPM_GETG(color1)*dist2/newdist + PPM_GETG(color2)*dist1/newdist;
-        b = PPM_GETB(color1)*dist2/newdist + PPM_GETB(color2)*dist1/newdist;
-        PPM_ASSIGN( pixels[row][col], r, g, b );
+static void
+assignInterpolatedColor(pixel * const resultP,
+                        pixel   const color1,
+                        double  const dist1,
+                        pixel   const color2,
+                        double  const dist2) {
+    
+    if (dist1 == 0) 
+        /* pixel is a pole */
+        *resultP = color1;
+    else {
+        double const sum = dist1 + dist2;
+
+        pixval const r = (PPM_GETR(color1)*dist2 + PPM_GETR(color2)*dist1)/sum;
+        pixval const g = (PPM_GETG(color1)*dist2 + PPM_GETG(color2)*dist1)/sum;
+        pixval const b = (PPM_GETB(color1)*dist2 + PPM_GETB(color2)*dist1)/sum;
+        
+        PPM_ASSIGN(*resultP, r, g, b);
+    }
+}
+
+
+
+static void
+poles(pixel **     const pixels,
+      unsigned int const cols,
+      unsigned int const rows,
+      pixval       const maxval) {
+
+    unsigned int const poleCt = MAX(2, MIN(MAXPOLES, cols * rows / 30000));
+    
+    int xs[MAXPOLES], ys[MAXPOLES];
+    pixel colors[MAXPOLES];
+    unsigned int row;
+
+    placeAndColorPolesRandomly(xs, ys, colors, cols, rows, maxval, poleCt);
+
+    /* Interpolate points */
+
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+        for (col = 0; col < cols; ++col) {
+            double dist1, dist2;
+            pixel color1, color2;
+            unsigned int i;
+
+            /* Find two closest poles. */
+            dist1 = dist2 = (SQR((double)cols) + SQR((double)rows));
+            for (i = 0; i < poleCt; ++i) {
+                double const newdist =
+                    (double)(col - xs[i]) * (col - xs[i]) +
+                    (double)(row - ys[i]) * (row - ys[i]);
+                if (newdist < dist1) {
+                    dist2  = dist1;
+                    color2 = color1;
+                    dist1  = newdist;
+                    color1 = colors[i];
+                } else if (newdist < dist2) {
+                    dist2  = newdist;
+                    color2 = colors[i];
+                }
+            }
+            assignInterpolatedColor(&pixels[row][col],
+                                    color1, dist1, color2, dist2);
         }
     }
+}
+
+
 
-/* Squig stuff. */
+/*----------------------------------------------------------------------------
+   Squig stuff
+-----------------------------------------------------------------------------*/
 
 #define SQUIGS 5
 #define SQ_POINTS 7
 #define SQ_MAXCIRCLE_POINTS 5000
 
-static int sq_radius, sq_circlecount;
+static int sq_circlecount;
 static pixel sq_colors[SQ_MAXCIRCLE_POINTS];
-static int sq_xoffs[SQ_MAXCIRCLE_POINTS], sq_yoffs[SQ_MAXCIRCLE_POINTS];
+static ppmd_point sq_offs[SQ_MAXCIRCLE_POINTS];
 
-static void
-sq_measurecircle_drawproc(pixel** const pixels, 
-                          int const cols, 
-                          int const rows, 
-                          pixval const maxval, 
-                          int const col, 
-                          int const row, 
-                          const void* const clientdata)
-{
-    sq_xoffs[sq_circlecount] = col;
-    sq_yoffs[sq_circlecount] = row;
-    ++sq_circlecount;
+
+
+static ppmd_point
+vectorSum(ppmd_point const a,
+          ppmd_point const b) {
+
+    return ppmd_makePoint(a.x + b.x, a.y + b.y);
 }
 
+
+
+static ppmd_drawprocp sqMeasureCircleDrawproc;
+
 static void
-sq_rainbowcircle_drawproc(pixel** const pixels, 
-                          int const cols, 
-                          int const rows, 
-                          pixval const maxval, 
-                          int const col, 
-                          int const row, 
-                          const void* const clientdata )
-{
-    int i;
+sqMeasureCircleDrawproc(pixel**      const pixels, 
+                        unsigned int const cols, 
+                        unsigned int const rows, 
+                        pixval       const maxval, 
+                        ppmd_point   const p,
+                        const void * const clientdata) {
+
+    sq_offs[sq_circlecount++] = p;
+}
 
-    for ( i = 0; i < sq_circlecount; ++i )
-    ppmd_point_drawproc(
-        pixels, cols, rows, maxval, col + sq_xoffs[i], row + sq_yoffs[i],
-        &(sq_colors[i]) );
-    }
 
 
+static ppmd_drawprocp sqRainbowCircleDrawproc;
 
 static void
-sq_assign_colors(int     const circlecount,
-                 pixval  const maxval,
-                 pixel * const colors) {
+sqRainbowCircleDrawproc(pixel **     const pixels, 
+                        unsigned int const cols, 
+                        unsigned int const rows, 
+                        pixval       const maxval, 
+                        ppmd_point   const p,
+                        const void * const clientdata) {
 
-    pixel rc1, rc2, rc3;
-    float cco3;
     unsigned int i;
 
-    rc1 = random_bright_color(maxval);
-    rc2 = random_bright_color(maxval);
-    rc3 = random_bright_color(maxval);
-    cco3 = (circlecount - 1) / 3.0;
+    for (i = 0; i < sq_circlecount; ++i)
+        ppmd_point_drawprocp(
+            pixels, cols, rows, maxval, vectorSum(p, sq_offs[i]),
+            &sq_colors[i]);
+}
+
+
+
+static void
+sqAssignColors(unsigned int const circlecount,
+               pixval       const maxval,
+               pixel *      const colors) {
+
+    pixel const rc1 = randomBrightColor(maxval);
+    pixel const rc2 = randomBrightColor(maxval);
+    pixel const rc3 = randomBrightColor(maxval);
+    float const cco3 = (circlecount - 1) / 3.0;
+
+    unsigned int i;
 
     for (i = 0; i < circlecount ; ++i) {
         if (i < cco3) {
@@ -730,336 +954,219 @@ sq_assign_colors(int     const circlecount,
 }
 
 
-#if __STDC__
-static void
-squig( pixel** pixels, int cols, int rows, pixval maxval )
-#else /*__STDC__*/
+
 static void
-squig( pixels, cols, rows, maxval )
-    pixel** pixels;
-    int cols, rows;
-    pixval maxval;
-#endif /*__STDC__*/
-    {
+clearImageToBlack(pixel **     const pixels,
+                  unsigned int const cols,
+                  unsigned int const rows,
+                  pixval       const maxval) {
+
     pixel color;
-    int i, j, xc[SQ_POINTS], yc[SQ_POINTS], x0, y0, x1, y1, x2, y2, x3, y3;
 
-    /* Clear image to black. */
-    PPM_ASSIGN( color, 0, 0, 0 );
+    PPM_ASSIGN(color, 0, 0, 0);
+
     ppmd_filledrectangle(
         pixels, cols, rows, maxval, 0, 0, cols, rows, PPMD_NULLDRAWPROC,
-        &color );
+        &color);
+}
 
-    /* Draw the squigs. */
-    (void) ppmd_setlinetype( PPMD_LINETYPE_NODIAGS );
-    (void) ppmd_setlineclip( 0 );
-    for ( i = SQUIGS; i > 0; --i )
-    {
-    /* Measure circle. */
-    sq_radius = ( cols + rows ) / 2 / ( 25 + i * 2 );
-    sq_circlecount = 0;
-    ppmd_circle(
-        pixels, cols, rows, maxval, 0, 0, sq_radius,
-        sq_measurecircle_drawproc, NULL );
-    sq_assign_colors( sq_circlecount, maxval, sq_colors );
-
-    /* Choose wrap-around point. */
-    switch ( rand() % 4 )
-        {
-        case 0:
-        x1 = rand() % cols;
-        y1 = 0;
-        if ( x1 < cols / 2 )
-        xc[0] = rand() % ( x1 * 2 + 1);
+
+
+static void
+chooseWrapAroundPoint(unsigned int const cols,
+                      unsigned int const rows,
+                      ppmd_point * const pFirstP,
+                      ppmd_point * const pLastP,
+                      ppmd_point * const p0P,
+                      ppmd_point * const p1P,
+                      ppmd_point * const p2P,
+                      ppmd_point * const p3P) {
+                      
+    switch (rand() % 4) {
+    case 0:
+        p1P->x = rand() % cols;
+        p1P->y = 0;
+        if (p1P->x < cols / 2)
+            pFirstP->x = rand() % (p1P->x * 2 + 1);
         else
-        xc[0] = cols - 1 - rand() % ( ( cols - x1 ) * 2 );
-        yc[0] = rand() % rows;
-        x2 = x1;
-        y2 = rows - 1;
-        xc[SQ_POINTS - 1] = 2 * x2 - xc[0];
-        yc[SQ_POINTS - 1] = y2 - yc[0];
-        x0 = xc[SQ_POINTS - 1];
-        y0 = yc[SQ_POINTS - 1] - rows;
-        x3 = xc[0];
-        y3 = yc[0] + rows;
+            pFirstP->x = cols - 1 - rand() % ((cols - p1P->x) * 2);
+        pFirstP->y = rand() % rows;
+        p2P->x = p1P->x;
+        p2P->y = rows - 1;
+        pLastP->x = 2 * p2P->x - pFirstP->x;
+        pLastP->y = p2P->y - pFirstP->y;
+        p0P->x = pLastP->x;
+        p0P->y = pLastP->y - rows;
+        p3P->x = pFirstP->x;
+        p3P->y = pFirstP->y + rows;
         break;
 
-        case 1:
-        x2 = rand() % cols;
-        y2 = 0;
-        if ( x2 < cols / 2 )
-        xc[SQ_POINTS - 1] = rand() % ( x2 * 2 + 1);
+    case 1:
+        p2P->x = rand() % cols;
+        p2P->y = 0;
+        if (p2P->x < cols / 2)
+            pLastP->x = rand() % (p2P->x * 2 + 1);
         else
-        xc[SQ_POINTS - 1] = cols - 1 - rand() % ( ( cols - x2 ) * 2 );
-        yc[SQ_POINTS - 1] = rand() % rows;
-        x1 = x2;
-        y1 = rows - 1;
-        xc[0] = 2 * x1 - xc[SQ_POINTS - 1];
-        yc[0] = y1 - yc[SQ_POINTS - 1];
-        x0 = xc[SQ_POINTS - 1];
-        y0 = yc[SQ_POINTS - 1] + rows;
-        x3 = xc[0];
-        y3 = yc[0] - rows;
+            pLastP->x = cols - 1 - rand() % ((cols - p2P->x) * 2);
+        pLastP->y = rand() % rows;
+        p1P->x = p2P->x;
+        p1P->y = rows - 1;
+        pFirstP->x = 2 * p1P->x - pLastP->x;
+        pFirstP->y = p1P->y - pLastP->y;
+        p0P->x = pLastP->x;
+        p0P->y = pLastP->y + rows;
+        p3P->x = pFirstP->x;
+        p3P->y = pFirstP->y - rows;
         break;
 
-        case 2:
-        x1 = 0;
-        y1 = rand() % rows;
-        xc[0] = rand() % cols;
-        if ( y1 < rows / 2 )
-        yc[0] = rand() % ( y1 * 2 + 1);
+    case 2:
+        p1P->x = 0;
+        p1P->y = rand() % rows;
+        pFirstP->x = rand() % cols;
+        if (p1P->y < rows / 2)
+            pFirstP->y = rand() % (p1P->y * 2 + 1);
         else
-        yc[0] = rows - 1 - rand() % ( ( rows - y1 ) * 2 );
-        x2 = cols - 1;
-        y2 = y1;
-        xc[SQ_POINTS - 1] = x2 - xc[0];
-        yc[SQ_POINTS - 1] = 2 * y2 - yc[0];
-        x0 = xc[SQ_POINTS - 1] - cols;
-        y0 = yc[SQ_POINTS - 1];
-        x3 = xc[0] + cols;
-        y3 = yc[0];
+            pFirstP->y = rows - 1 - rand() % ((rows - p1P->y) * 2);
+        p2P->x = cols - 1;
+        p2P->y = p1P->y;
+        pLastP->x = p2P->x - pFirstP->x;
+        pLastP->y = 2 * p2P->y - pFirstP->y;
+        p0P->x = pLastP->x - cols;
+        p0P->y = pLastP->y;
+        p3P->x = pFirstP->x + cols;
+        p3P->y = pFirstP->y;
         break;
 
-        case 3:
-        x2 = 0;
-        y2 = rand() % rows;
-        xc[SQ_POINTS - 1] = rand() % cols;
-        if ( y2 < rows / 2 )
-        yc[SQ_POINTS - 1] = rand() % ( y2 * 2 + 1);
+    case 3:
+        p2P->x = 0;
+        p2P->y = rand() % rows;
+        pLastP->x = rand() % cols;
+        if (p2P->y < rows / 2)
+            pLastP->y = rand() % (p2P->y * 2 + 1);
         else
-        yc[SQ_POINTS - 1] = rows - 1 - rand() % ( ( rows - y2 ) * 2 );
-        x1 = cols - 1;
-        y1 = y2;
-        xc[0] = x1 - xc[SQ_POINTS - 1];
-        yc[0] = 2 * y1 - yc[SQ_POINTS - 1];
-        x0 = xc[SQ_POINTS - 1] + cols;
-        y0 = yc[SQ_POINTS - 1];
-        x3 = xc[0] - cols;
-        y3 = yc[0];
+            pLastP->y = rows - 1 - rand() % ((rows - p2P->y) * 2);
+        p1P->x = cols - 1;
+        p1P->y = p2P->y;
+        pFirstP->x = p1P->x - pLastP->x;
+        pFirstP->y = 2 * p1P->y - pLastP->y;
+        p0P->x = pLastP->x + cols;
+        p0P->y = pLastP->y;
+        p3P->x = pFirstP->x - cols;
+        p3P->y = pFirstP->y;
         break;
-        }
-
-    for ( j = 1; j < SQ_POINTS - 1; ++j )
-        {
-        xc[j] = ( rand() % ( cols - 2 * sq_radius ) ) + sq_radius;
-        yc[j] = ( rand() % ( rows - 2 * sq_radius ) ) + sq_radius;
-        }
-
-    ppmd_line(
-        pixels, cols, rows, maxval, x0, y0, x1, y1,
-        sq_rainbowcircle_drawproc, NULL );
-    ppmd_polyspline(
-        pixels, cols, rows, maxval, x1, y1, SQ_POINTS, xc, yc, x2, y2,
-        sq_rainbowcircle_drawproc, NULL );
-    ppmd_line(
-        pixels, cols, rows, maxval, x2, y2, x3, y3,
-        sq_rainbowcircle_drawproc, NULL );
     }
-    }
-
+}
 
 
-/* Test pattern.  Just a place to put ppmdraw exercises. */
 
 static void
-test(pixel **     const pixels,
-     unsigned int const cols,
-     unsigned int const rows,
-     pixval       const maxval) {
+squig(pixel **     const pixels,
+      unsigned int const cols,
+      unsigned int const rows,
+      pixval       const maxval) {
 
-    pixel color;
-    struct fillobj * fh;
+    int i;
+    
+    clearImageToBlack(pixels, cols, rows, maxval);
 
-    /* Clear image to black. */
-    PPM_ASSIGN( color, 0, 0, 0 );
-    ppmd_filledrectangle(
-        pixels, cols, rows, maxval, 0, 0, cols, rows, PPMD_NULLDRAWPROC,
-        &color);
+    /* Draw the squigs. */
+    ppmd_setlinetype(PPMD_LINETYPE_NODIAGS);
+    ppmd_setlineclip(0);
+    for (i = SQUIGS; i > 0; --i) {
+        unsigned int const radius = (cols + rows) / 2 / (25 + i * 2);
+
+        ppmd_point c[SQ_POINTS];
+        ppmd_point p0, p1, p2, p3;
+        sq_circlecount = 0;
+        ppmd_circlep(pixels, cols, rows, maxval,
+                     ppmd_makePoint(0, 0), radius,
+                     sqMeasureCircleDrawproc, NULL);
+        sqAssignColors(sq_circlecount, maxval, sq_colors);
+
+        chooseWrapAroundPoint(cols, rows, &c[0], &c[SQ_POINTS-1],
+                              &p0, &p1, &p2, &p3);
 
-    fh = ppmd_fill_create();
-
-    ppmd_line(pixels, cols, rows, maxval, 
-              cols/8, rows/8, cols/2, rows/4, ppmd_fill_drawproc, fh);
-    ppmd_line(pixels, cols, rows, maxval, 
-              cols/2, rows/4, cols-cols/8, rows/8, ppmd_fill_drawproc, fh);
-    ppmd_line(pixels, cols, rows, maxval, 
-              cols-cols/8, rows/8, cols/2, rows/2, ppmd_fill_drawproc, fh);
-    ppmd_spline3(pixels, cols, rows, maxval, 
-                 cols/2, rows/2, cols/2-cols/16, rows/2-rows/10, 
-                 cols/2-cols/8, rows/2, ppmd_fill_drawproc, fh);
-    ppmd_spline3(pixels, cols, rows, maxval, 
-                 cols/2-cols/8, rows/2, cols/4+cols/16, rows/2+rows/10, 
-                 cols/4, rows/2, ppmd_fill_drawproc, fh);
-    ppmd_line(pixels, cols, rows, maxval, 
-              cols/4, rows/2, cols/8, rows/2, ppmd_fill_drawproc, fh);
-    ppmd_line(pixels, cols, rows, maxval, 
-              cols/8, rows/2, cols/8, rows/8, ppmd_fill_drawproc, fh);
-
-    PPM_ASSIGN(color, maxval, maxval, maxval);
-    ppmd_fill(pixels, cols, rows, maxval, fh, PPMD_NULLDRAWPROC, &color);
+        {
+            /* Do the middle points */
+            unsigned int j;
 
-    ppmd_fill_destroy(fh);
+            for (j = 1; j < SQ_POINTS - 1; ++j) {
+                c[j].x = (rand() % (cols - 2 * radius)) + radius;
+                c[j].y = (rand() % (rows - 2 * radius)) + radius;
+            }
+        }
 
+        ppmd_linep(
+            pixels, cols, rows, maxval, p0, p1,
+            sqRainbowCircleDrawproc, NULL);
+        ppmd_polysplinep(
+            pixels, cols, rows, maxval, p1, SQ_POINTS, c, p2,
+            sqRainbowCircleDrawproc, NULL);
+        ppmd_linep(
+            pixels, cols, rows, maxval, p2, p3,
+            sqRainbowCircleDrawproc, NULL);
+    }
 }
 
 
 
 int
-main(int argc, char ** argv) {
-
-    pixel** pixels;
-    int argn, pattern, cols, rows;
-#define PAT_NONE 0
-#define PAT_GINGHAM2 1
-#define PAT_GINGHAM3 2
-#define PAT_MADRAS 3
-#define PAT_TARTAN 4
-#define PAT_POLES 5
-#define PAT_SQUIG 6
-#define PAT_CAMO 7
-#define PAT_ANTICAMO 8
-#define PAT_TEST 9
-    const char* const usage = "-gingham2|-g2|-gingham3|-g3|-madras|-tartan|-poles|-squig|-camo|-anticamo <width> <height>";
-
-
-    ppm_init(&argc, argv);
-
-    argn = 1;
-    pattern = PAT_NONE;
-
-    while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
-    {
-        if ( pm_keymatch( argv[argn], "-gingham2", 9 ) ||
-             pm_keymatch( argv[argn], "-g2", 3 ) )
-        {
-            if ( pattern != PAT_NONE )
-                pm_error( "only one base pattern may be specified" );
-            pattern = PAT_GINGHAM2;
-        }
-        else if ( pm_keymatch( argv[argn], "-gingham3", 9 ) ||
-                  pm_keymatch( argv[argn], "-g3", 3 ) )
-        {
-            if ( pattern != PAT_NONE )
-                pm_error( "only one base pattern may be specified" );
-            pattern = PAT_GINGHAM3;
-        }
-        else if ( pm_keymatch( argv[argn], "-madras", 2 ) )
-        {
-            if ( pattern != PAT_NONE )
-                pm_error( "only one base pattern may be specified" );
-            pattern = PAT_MADRAS;
-        }
-        else if ( pm_keymatch( argv[argn], "-tartan", 2 ) )
-        {
-            if ( pattern != PAT_NONE )
-                pm_error( "only one base pattern may be specified" );
-            pattern = PAT_TARTAN;
-        }
-        else if ( pm_keymatch( argv[argn], "-poles", 2 ) )
-        {
-            if ( pattern != PAT_NONE )
-                pm_error( "only one base pattern may be specified" );
-            pattern = PAT_POLES;
-        }
-        else if ( pm_keymatch( argv[argn], "-squig", 2 ) )
-        {
-            if ( pattern != PAT_NONE )
-                pm_error( "only one base pattern may be specified" );
-            pattern = PAT_SQUIG;
-        }
-        else if ( pm_keymatch( argv[argn], "-camo", 2 ) )
-        {
-            if ( pattern != PAT_NONE )
-                pm_error( "only one base pattern may be specified" );
-            pattern = PAT_CAMO;
-        }
-        else if ( pm_keymatch( argv[argn], "-anticamo", 2 ) )
-        {
-            if ( pattern != PAT_NONE )
-                pm_error( "only one base pattern may be specified" );
-            pattern = PAT_ANTICAMO;
-        }
-        else if ( pm_keymatch( argv[argn], "-test", 3 ) )
-        {
-            if ( pattern != PAT_NONE )
-                pm_error( "only one base pattern may be specified" );
-            pattern = PAT_TEST;
-        }
-        else
-            pm_usage( usage );
-        ++argn;
-    }
-    if ( pattern == PAT_NONE )
-        pm_error( "a base pattern must be specified" );
-
-    if ( argn == argc )
-        pm_usage( usage);
-    if ( sscanf( argv[argn], "%d", &cols ) != 1 )
-        pm_usage( usage );
-    ++argn;
-    if ( argn == argc )
-        pm_usage( usage);
-    if ( sscanf( argv[argn], "%d", &rows ) != 1 )
-        pm_usage( usage );
-    ++argn;
-
-    if ( argn != argc )
-        pm_usage( usage);
-
-    if (cols < 1)
-        pm_error("width must be at least 1");
-    if (rows < 1)
-        pm_error("height must be at least 1");
-
-    srand( (int) ( time( 0 ) ^ getpid( ) ) );
-    pixels = ppm_allocarray( cols, rows );
-
-    switch ( pattern )
-    {
+main(int argc, const char ** argv) {
+
+    struct cmdlineInfo cmdline;
+    pixel ** pixels;
+
+    pm_proginit(&argc, argv);
+    
+    parseCommandLine(argc, argv, &cmdline);
+
+    validateComputableDimensions(cmdline.width, cmdline.height);
+    
+    srand(pm_randseed());
+    pixels = ppm_allocarray(cmdline.width, cmdline.height);
+
+    switch (cmdline.basePattern) {
     case PAT_GINGHAM2:
-        gingham2( pixels, cols, rows, PPM_MAXMAXVAL );
+        gingham2(pixels, cmdline.width, cmdline.height, PPM_MAXMAXVAL);
         break;
 
     case PAT_GINGHAM3:
-        gingham3( pixels, cols, rows, PPM_MAXMAXVAL );
+        gingham3(pixels, cmdline.width, cmdline.height, PPM_MAXMAXVAL);
         break;
 
     case PAT_MADRAS:
-        madras( pixels, cols, rows, PPM_MAXMAXVAL );
+        madras(pixels, cmdline.width, cmdline.height, PPM_MAXMAXVAL);
         break;
 
     case PAT_TARTAN:
-        tartan( pixels, cols, rows, PPM_MAXMAXVAL );
+        tartan(pixels, cmdline.width, cmdline.height, PPM_MAXMAXVAL);
         break;
 
     case PAT_POLES:
-        poles( pixels, cols, rows, PPM_MAXMAXVAL );
+        poles(pixels, cmdline.width, cmdline.height, PPM_MAXMAXVAL);
         break;
 
     case PAT_SQUIG:
-        squig( pixels, cols, rows, PPM_MAXMAXVAL );
+        squig(pixels, cmdline.width, cmdline.height, PPM_MAXMAXVAL);
         break;
 
     case PAT_CAMO:
-        camo( pixels, cols, rows, PPM_MAXMAXVAL, 0 );
+        camo(pixels, cmdline.width, cmdline.height, PPM_MAXMAXVAL, 0);
         break;
 
     case PAT_ANTICAMO:
-        camo( pixels, cols, rows, PPM_MAXMAXVAL, 1 );
-        break;
-
-    case PAT_TEST:
-        test( pixels, cols, rows, PPM_MAXMAXVAL );
+        camo(pixels, cmdline.width, cmdline.height, PPM_MAXMAXVAL, 1);
         break;
 
     default:
-        pm_error( "can't happen!" );
+        pm_error("can't happen!");
     }
 
-    /* All done, write it out. */
-    ppm_writeppm( stdout, pixels, cols, rows, PPM_MAXMAXVAL, 0 );
-    pm_close( stdout );
+    ppm_writeppm(stdout, pixels, cmdline.width, cmdline.height,
+                 PPM_MAXMAXVAL, 0);
+
+    ppm_freearray(pixels, cmdline.height);
 
-    exit( 0 );
+    return 0;
 }
 
diff --git a/generator/ppmrough.c b/generator/ppmrough.c
index f8823173..b21adedf 100644
--- a/generator/ppmrough.c
+++ b/generator/ppmrough.c
@@ -10,10 +10,13 @@
 ** documentation.  This software is provided "as is" without express or
 ** implied warranty.  */
 
+#include <stdlib.h>
 #include <math.h>
 #include <sys/time.h>
-#include "ppm.h"
+
+#include "pm_c_util.h"
 #include "shhopt.h"
+#include "ppm.h"
 
 static pixel** PIX;
 static pixval BG_RED, BG_GREEN, BG_BLUE;