about summary refs log tree commit diff
path: root/generator
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2013-06-29 19:19:47 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2013-06-29 19:19:47 +0000
commit380588e187c12000ac8082cb2a20a905d3c422a5 (patch)
tree296b1324b7a9360646a34ae836b8eb486b7feede /generator
parentf8b633c2be1231a0c194214271caa456dc669ecb (diff)
downloadnetpbm-mirror-380588e187c12000ac8082cb2a20a905d3c422a5.tar.gz
netpbm-mirror-380588e187c12000ac8082cb2a20a905d3c422a5.tar.xz
netpbm-mirror-380588e187c12000ac8082cb2a20a905d3c422a5.zip
Release 10.63.00
git-svn-id: http://svn.code.sf.net/p/netpbm/code/advanced@1968 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'generator')
-rw-r--r--generator/pamgauss.c2
-rw-r--r--generator/pamgradient.c8
-rw-r--r--generator/pamseq.c2
-rw-r--r--generator/pgmnoise.c97
-rw-r--r--generator/ppmcie.c114
-rw-r--r--generator/ppmforge.c413
-rwxr-xr-xgenerator/ppmrainbow26
7 files changed, 369 insertions, 293 deletions
diff --git a/generator/pamgauss.c b/generator/pamgauss.c
index b6afdb7e..0e1661e6 100644
--- a/generator/pamgauss.c
+++ b/generator/pamgauss.c
@@ -9,8 +9,6 @@
 #include "mallocvar.h"
 #include "pam.h"
 
-#define true (1)
-#define false (0)
 
 
 struct cmdlineInfo {
diff --git a/generator/pamgradient.c b/generator/pamgradient.c
index 6546e334..57e78288 100644
--- a/generator/pamgradient.c
+++ b/generator/pamgradient.c
@@ -18,7 +18,7 @@ struct cmdlineInfo {
 };
 
 static void
-parseCommandLine(int argc, char **argv,
+parseCommandLine(int argc, const char **argv,
                  struct cmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
   Convert program invocation arguments (argc,argv) into a format the 
@@ -45,7 +45,7 @@ parseCommandLine(int argc, char **argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (!maxvalSpec)
@@ -153,7 +153,7 @@ createEdge(const struct pam * const pamP,
 
 
 int
-main(int argc, char *argv[]) {
+main(int argc, const char *argv[]) {
 
     struct cmdlineInfo cmdline;
     struct pam pam;
@@ -162,7 +162,7 @@ main(int argc, char *argv[]) {
     tuple * rightEdge;
     unsigned int row;
     
-    pnm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
diff --git a/generator/pamseq.c b/generator/pamseq.c
index b1ed0c79..1af5252a 100644
--- a/generator/pamseq.c
+++ b/generator/pamseq.c
@@ -7,8 +7,6 @@
 #include "pam.h"
 #include "shhopt.h"
 
-#define true (1)
-#define false (0)
 
 
 struct cmdlineInfo {
diff --git a/generator/pgmnoise.c b/generator/pgmnoise.c
index bf73ea48..442edc59 100644
--- a/generator/pgmnoise.c
+++ b/generator/pgmnoise.c
@@ -7,6 +7,8 @@
 #include "mallocvar.h"
 #include "shhopt.h"
 #include "pgm.h"
+#include <assert.h>
+
 
 
 struct cmdlineInfo {
@@ -15,13 +17,13 @@ struct cmdlineInfo {
     */
     unsigned int width;
     unsigned int height;
+    unsigned int maxval;
     unsigned int randomseed;
     unsigned int randomseedSpec;
 };
 
 
 
-
 static void
 parseCommandLine(int argc, const char ** const argv,
                  struct cmdlineInfo * const cmdlineP) {
@@ -34,12 +36,15 @@ parseCommandLine(int argc, const char ** const argv,
          */
     optStruct3 opt;
     unsigned int option_def_index;
+    unsigned int maxvalSpec;
 
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENT3 */
     OPTENT3(0,   "randomseed",   OPT_UINT,    &cmdlineP->randomseed,
             &cmdlineP->randomseedSpec,      0);
+    OPTENT3(0,   "maxval",       OPT_UINT,    &cmdlineP->maxval,
+            &maxvalSpec,                    0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
@@ -47,6 +52,16 @@ parseCommandLine(int argc, const char ** const argv,
 
     pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+    free(option_def);
+
+    if (maxvalSpec) {
+        if (cmdlineP->maxval > PGM_OVERALLMAXVAL)
+            pm_error("Maxval too large: %u.  Maximu is %u", 
+                     cmdlineP->maxval, PGM_OVERALLMAXVAL);
+        else if (cmdlineP->maxval == 0)
+            pm_error("Maxval must not be zero");
+    } else
+        cmdlineP->maxval = PGM_MAXMAXVAL;
 
     if (argc-1 != 2)
         pm_error("Wrong number of arguments: %u.  "
@@ -66,30 +81,95 @@ parseCommandLine(int argc, const char ** const argv,
         else
             cmdlineP->height = height;
     }
-    free(option_def);
 }
 
 
 
+static unsigned int
+randPool(unsigned int const digits) {
+/*----------------------------------------------------------------------------
+  Draw 'digits' bits from pool of random bits.  If the number of random bits
+  in pool is insufficient, call rand() and add 31 bits to it.
+  
+  'digits' must be at most 16.
+
+  We assume that each call to rand() generates 31 bits, or RAND_MAX ==
+  2147483647.
+  
+  The underlying logic is flexible and endian-free.  The above conditions
+  can be relaxed.
+-----------------------------------------------------------------------------*/
+    static unsigned long int hold=0;  /* entropy pool */
+    static unsigned int len=0;        /* number of valid bits in pool */
+
+    unsigned int const mask = (1 << digits) - 1;
+
+    unsigned int retval;
+
+    assert(RAND_MAX == 2147483647 && digits <= 16);
+
+    retval = hold;  /* initial value */
+
+    if (len > digits) { /* Enough bits in hold to satisfy request */
+        hold >>= digits;
+        len   -= digits;
+    } else {              /* Load another 31 bits into hold */
+        hold    = rand(); 
+        retval |= (hold << len);
+        hold >>=  (digits - len);
+        len = 31 - digits + len;
+    }
+    return (retval & mask);
+}
+
+
 
 static void
-pgmnoise(FILE * const ofP,
+pgmnoise(FILE *       const ofP,
          unsigned int const cols,
          unsigned int const rows,
          gray         const maxval) {
 
+    bool const usingPool = !(RAND_MAX==2147483647 && (maxval & (maxval+1)));
+    unsigned int const bitLen = pm_maxvaltobits(maxval);
+
     unsigned int row;
     gray * destrow;
 
+    /* If maxval is 2^n-1, we draw exactly n bits from the pool.
+       Otherwise call rand() and determine gray value by modulo.
+
+       In the latter case, there is a miniscule skew toward 0 (=black)
+       because smaller numbers are produced more frequently by modulo.
+       Thus we employ the pool method only when it is certain that no
+       skew will ensue.
+
+       To illustrate the point, consider converting the outcome of one
+       roll of a fair, six-sided die to 5 values (0 to 4) by N % 5.  The
+       probability for values 1, 2, 3, 4 are 1/6, but 0 alone is 2/6.
+       Average is 10/6 or 1.6667, compared to 2.0 from an ideal
+       generator which produces exactly 5 values.  With two dice
+       average improves to 70/36 or 1.9444.
+
+       The more (distinct) dice we roll, or the more binary digits we
+       draw, the smaller the skew.
+    */
+
     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);
-
+        if (usingPool) {
+            unsigned int col;
+            for (col = 0; col < cols; ++col)
+                destrow[col] = randPool(bitLen);
+        } 
+        else { 
+            unsigned int col;
+            for (col = 0; col < cols; ++col)
+                destrow[col] = rand() % (maxval + 1); 
+        }
         pgm_writepgmrow(ofP, destrow, cols, maxval, 0);
     }
 
@@ -110,8 +190,7 @@ main(int          argc,
 
     srand(cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed());
 
-    pgmnoise(stdout, cmdline.width, cmdline.height, PGM_MAXMAXVAL);
+    pgmnoise(stdout, cmdline.width, cmdline.height, cmdline.maxval);
 
     return 0;
 }
-
diff --git a/generator/ppmcie.c b/generator/ppmcie.c
index 69af5732..717ed13b 100644
--- a/generator/ppmcie.c
+++ b/generator/ppmcie.c
@@ -35,10 +35,8 @@
 #include "nstring.h"
 
 #define CLAMP(v, l, h)  ((v) < (l) ? (l) : (v) > (h) ? (h) : (v))
-#define TRUE    1
-#define FALSE   0
 
-#define Maxval  255                   /* Maxval to use in generated pixmaps */
+pixval const cieMaxval = 255;  /* Maxval to use in generated pixmaps */
 
 /* A  color  system is defined by the CIE x and y  coordinates of its
    three primary illuminants and the x and y coordinates of the  white
@@ -522,12 +520,12 @@ makeAllBlack(pixel **     const pixels,
 
 static void
 drawTongueOutline(pixel ** const pixels,
-                  int    const pixcols,
-                  int    const pixrows,
-                  pixval const maxval,
-                  bool   const upvp,
-                  int    const xBias,
-                  int    const yBias) {
+                  int      const pixcols,
+                  int      const pixrows,
+                  pixval   const maxval,
+                  bool     const upvp,
+                  int      const xBias,
+                  int      const yBias) {
 
     int const pxcols = pixcols - xBias;
     int const pxrows = pixrows - yBias;
@@ -546,7 +544,7 @@ drawTongueOutline(pixel ** const pixels,
                                        &icx, &icy);
         
         if (wavelength > 380)
-            ppmd_line(pixels, pixcols, pixrows, Maxval,
+            ppmd_line(pixels, pixcols, pixrows, maxval,
                       B(lx, ly), B(icx, icy),
                       PPMD_NULLDRAWPROC, (char *) &rgbcolor);
         else {
@@ -585,12 +583,12 @@ findTongue(pixel ** const pixels,
          ++i);
 
     if (i >= pxcols)
-        *presentP = FALSE;
+        *presentP = false;
     else {
         int j;
         int const leftEdge = i;
 
-        *presentP = TRUE;
+        *presentP = true;
         
         for (j = pxcols - 1;
              j >= leftEdge && PPM_GETR(Bixels(row, j)) == 0;
@@ -652,16 +650,16 @@ fillInTongue(pixel **                   const pixels,
 
                 xyz_to_rgb(cs, cx, cy, cz, &jr, &jg, &jb);
 
-                mx = Maxval;
+                mx = maxval;
         
                 /* Check whether the requested color  is  within  the
                    gamut  achievable with the given color system.  If
                    not, draw it in a reduced  intensity,  interpolated
                    by desaturation to the closest within-gamut color. */
         
-                if (constrain_rgb(&jr, &jg, &jb)) {
-                    mx = highlightGamut ? Maxval : ((Maxval + 1) * 3) / 4;
-                }
+                if (constrain_rgb(&jr, &jg, &jb))
+                    mx = highlightGamut ? maxval : ((maxval + 1) * 3) / 4;
+
                 /* Scale to max(rgb) = 1. */
                 jmax = MAX(jr, MAX(jg, jb));
                 if (jmax > 0) {
@@ -959,14 +957,14 @@ plotBlackBodyCurve(pixel **                   const pixels,
         }
 
         if (t > 1000) {
-            ppmd_line(pixels, pixcols, pixrows, Maxval,
+            ppmd_line(pixels, pixcols, pixrows, maxval,
                       B(lx, ly), B(xb, yb), PPMD_NULLDRAWPROC,
                       (char *) &rgbcolor);
 
             /* Draw tick mark every 1000 kelvins */
 
             if ((((int) t) % 1000) == 0) {
-                ppmd_line(pixels, pixcols, pixrows, Maxval,
+                ppmd_line(pixels, pixcols, pixrows, maxval,
                           B(lx, ly - Sz(2)), B(lx, ly + Sz(2)),
                           PPMD_NULLDRAWPROC, (char *) &rgbcolor);
 
@@ -978,7 +976,7 @@ plotBlackBodyCurve(pixel **                   const pixels,
                     char bb[20];
 
                     sprintf(bb, "%g", t);
-                    ppmd_text(pixels, pixcols, pixrows, Maxval,
+                    ppmd_text(pixels, pixcols, pixrows, maxval,
                               B(lx - Sz(12), ly - Sz(4)), Sz(6), 0, bb,
                               PPMD_NULLDRAWPROC, (char *) &rgbcolor);
                 }
@@ -1057,7 +1055,7 @@ plotMonochromeWavelengths(
             PPM_ASSIGN(rgbcolor, maxval, maxval, maxval);
             tx = icx + ((x < 520) ? Sz(-2) : ((x >= 535) ? Sz(2) : 0));
             ty = icy + ((x < 520) ? 0 : ((x >= 535) ? Sz(-1) : Sz(-2))); 
-            ppmd_line(pixels, pixcols, pixrows, Maxval,
+            ppmd_line(pixels, pixcols, pixrows, maxval,
                       B(icx, icy), B(tx, ty),
                       PPMD_NULLDRAWPROC, (char *) &rgbcolor);
 
@@ -1089,13 +1087,13 @@ plotMonochromeWavelengths(
             }
             /* gamma correct from linear rgb to nonlinear rgb. */
             gamma_correct_rgb(cs, &jr, &jg, &jb);
-            r = Maxval * jr;
-            g = Maxval * jg;
-            b = Maxval * jb;
+            r = maxval * jr;
+            g = maxval * jg;
+            b = maxval * jb;
             PPM_ASSIGN(rgbcolor, (pixval) r, (pixval) g, (pixval) b);
 
             sprintf(wl, "%d", x);
-            ppmd_text(pixels, pixcols, pixrows, Maxval,
+            ppmd_text(pixels, pixcols, pixrows, maxval,
                       B(icx + bx, icy + by), Sz(6), 0, wl,
                       PPMD_NULLDRAWPROC, (char *) &rgbcolor);
         }
@@ -1127,7 +1125,7 @@ writeLabel(pixel **                   const pixels,
                 cs->xBlue, cs->yBlue, cs->xWhite, cs->yWhite);
     sysdesc[sizeof(sysdesc)-1] = '\0';  /* for robustness */
 
-    ppmd_text(pixels, pixcols, pixrows, Maxval,
+    ppmd_text(pixels, pixcols, pixrows, maxval,
               pixcols / 3, Sz(24), Sz(12), 0, sysdesc,
               PPMD_NULLDRAWPROC, (char *) &rgbcolor);
 }
@@ -1135,8 +1133,8 @@ writeLabel(pixel **                   const pixels,
 
 
 int
-main(int argc,
-     char * argv[]) {
+main(int          argc,
+     const char * argv[]) {
 
     int argn;
     const char * const usage = "[-[no]black] [-[no]wpoint] [-[no]label] [-no[axes]] [-full]\n\
@@ -1146,24 +1144,24 @@ main(int argc,
 [-size <s>] [-xsize|-width <x>] [-ysize|-height <y>]";
     const struct colorSystem *cs;
 
-    int widspec = FALSE, hgtspec = FALSE;
+    bool widspec = false, hgtspec = false;
     unsigned int xBias, yBias;
-    int upvp = FALSE;             /* xy or u'v' color coordinates? */
-    int showWhite = TRUE;             /* Show white point ? */
-    int showBlack = TRUE;             /* Show black body curve ? */
-    int fullChart = FALSE;            /* Fill entire tongue ? */
-    int showLabel = TRUE;             /* Show labels ? */
-    int showAxes = TRUE;              /* Plot axes ? */
-
-    ppm_init(&argc, argv);
+    bool upvp = false;             /* xy or u'v' color coordinates? */
+    bool showWhite = true;         /* Show white point ? */
+    bool showBlack = true;         /* Show black body curve ? */
+    bool fullChart = false;        /* Fill entire tongue ? */
+    bool showLabel = true;         /* Show labels ? */
+    bool showAxes = true;          /* Plot axes ? */
+
+    pm_proginit(&argc, argv);
     argn = 1;
 
     cs = &Rec709system;  /* default */
     while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') {
         if (pm_keymatch(argv[argn], "-xy", 2)) {
-            upvp = FALSE;
+            upvp = false;
         } else if (pm_keymatch(argv[argn], "-upvp", 1)) {
-            upvp = TRUE;
+            upvp = true;
         } else if (pm_keymatch(argv[argn], "-xsize", 1) ||
                    pm_keymatch(argv[argn], "-width", 2)) {
             if (widspec) {
@@ -1172,7 +1170,7 @@ main(int argc,
             argn++;
             if ((argn == argc) || (sscanf(argv[argn], "%d", &sxsize) != 1))
                 pm_usage(usage);
-            widspec = TRUE;
+            widspec = true;
         } else if (pm_keymatch(argv[argn], "-ysize", 1) ||
                    pm_keymatch(argv[argn], "-height", 2)) {
             if (hgtspec) {
@@ -1181,7 +1179,7 @@ main(int argc,
             argn++;
             if ((argn == argc) || (sscanf(argv[argn], "%d", &sysize) != 1))
                 pm_usage(usage);
-            hgtspec = TRUE;
+            hgtspec = true;
         } else if (pm_keymatch(argv[argn], "-size", 2)) {
             if (hgtspec || widspec) {
                 pm_error("already specified a size/height/ysize");
@@ -1190,7 +1188,7 @@ main(int argc,
             if ((argn == argc) || (sscanf(argv[argn], "%d", &sysize) != 1))
                 pm_usage(usage);
             sxsize = sysize;
-            hgtspec = widspec = TRUE;
+            hgtspec = widspec = true;
         } else if (pm_keymatch(argv[argn], "-rec709", 1)) {
             cs = &Rec709system;
         } else if (pm_keymatch(argv[argn], "-ntsc", 1)) {
@@ -1204,23 +1202,23 @@ main(int argc,
         } else if (pm_keymatch(argv[argn], "-cie", 1)) {
             cs = &CIEsystem;                 
         } else if (pm_keymatch(argv[argn], "-black", 3)) {
-            showBlack = TRUE;         /* Show black body curve */
+            showBlack = true;         /* Show black body curve */
         } else if (pm_keymatch(argv[argn], "-wpoint", 2)) {
-            showWhite = TRUE;         /* Show white point of color system */
+            showWhite = true;         /* Show white point of color system */
         } else if (pm_keymatch(argv[argn], "-noblack", 3)) {
-            showBlack = FALSE;        /* Don't show black body curve */
+            showBlack = false;        /* Don't show black body curve */
         } else if (pm_keymatch(argv[argn], "-nowpoint", 3)) {
-            showWhite = FALSE;        /* Don't show white point of system */
+            showWhite = false;        /* Don't show white point of system */
         } else if (pm_keymatch(argv[argn], "-label", 1)) {
-            showLabel = TRUE;         /* Show labels. */
+            showLabel = true;         /* Show labels. */
         } else if (pm_keymatch(argv[argn], "-nolabel", 3)) {
-            showLabel = FALSE;        /* Don't show labels */
+            showLabel = false;        /* Don't show labels */
         } else if (pm_keymatch(argv[argn], "-axes", 1)) {
-            showAxes = TRUE;          /* Show axes. */
+            showAxes = true;          /* Show axes. */
         } else if (pm_keymatch(argv[argn], "-noaxes", 3)) {
-            showAxes = FALSE;         /* Don't show axes */
+            showAxes = false;         /* Don't show axes */
         } else if (pm_keymatch(argv[argn], "-full", 1)) {
-            fullChart = TRUE;         /* Fill whole tongue full-intensity */
+            fullChart = true;         /* Fill whole tongue full-intensity */
         } else if (pm_keymatch(argv[argn], "-gamma", 2)) {
             cs = &Customsystem;
             argn++;
@@ -1289,32 +1287,32 @@ main(int argc,
 
     makeAllBlack(pixels, pixcols, pixrows);
 
-    drawTongueOutline(pixels, pixcols, pixrows, Maxval, upvp, xBias, yBias);
+    drawTongueOutline(pixels, pixcols, pixrows, cieMaxval, upvp, xBias, yBias);
 
-    fillInTongue(pixels, pixcols, pixrows, Maxval, cs, upvp, xBias, yBias,
+    fillInTongue(pixels, pixcols, pixrows, cieMaxval, cs, upvp, xBias, yBias,
                  fullChart);
 
     if (showAxes)
-        drawAxes(pixels, pixcols, pixrows, Maxval, upvp, xBias, yBias);
+        drawAxes(pixels, pixcols, pixrows, cieMaxval, upvp, xBias, yBias);
 
     if (showWhite)
-        plotWhitePoint(pixels, pixcols, pixrows, Maxval,
+        plotWhitePoint(pixels, pixcols, pixrows, cieMaxval,
                        cs, upvp, xBias, yBias);
 
     if (showBlack)
-        plotBlackBodyCurve(pixels, pixcols, pixrows, Maxval,
+        plotBlackBodyCurve(pixels, pixcols, pixrows, cieMaxval,
                            upvp, xBias, yBias);
 
     /* Plot wavelengths around periphery of the tongue. */
 
     if (showAxes)
-        plotMonochromeWavelengths(pixels, pixcols, pixrows, Maxval,
+        plotMonochromeWavelengths(pixels, pixcols, pixrows, cieMaxval,
                                   cs, upvp, xBias, yBias);
 
     if (showLabel)
-        writeLabel(pixels, pixcols, pixrows, Maxval, cs);
+        writeLabel(pixels, pixcols, pixrows, cieMaxval, cs);
 
-    ppm_writeppm(stdout, pixels, pixcols, pixrows, Maxval, FALSE);
+    ppm_writeppm(stdout, pixels, pixcols, pixrows, cieMaxval, 0);
 
     return 0;
 }
diff --git a/generator/ppmforge.c b/generator/ppmforge.c
index 189e930c..8ea86429 100644
--- a/generator/ppmforge.c
+++ b/generator/ppmforge.c
@@ -39,6 +39,7 @@
 #include "pm_c_util.h"
 #include "ppm.h"
 #include "mallocvar.h"
+#include "shhopt.h"
 
 static double const hugeVal = 1e50;
 
@@ -74,12 +75,6 @@ static double arand, gaussadd, gaussfac; /* Gaussian random parameters */
 static double fracdim;            /* Fractal dimension */
 static double powscale;           /* Power law scaling exponent */
 static int meshsize = 256;        /* FFT mesh size */
-static unsigned int seedarg;        /* Seed specified by user */
-static bool seedspec = FALSE;      /* Did the user specify a seed ? */
-static bool clouds = FALSE;        /* Just generate clouds */
-static bool stars = FALSE;         /* Just generate stars */
-static int screenxsize = 256;         /* Screen X size */
-static int screenysize = 256;         /* Screen Y size */
 static double inclangle, hourangle;   /* Star position relative to planet */
 static bool inclspec = FALSE;      /* No inclination specified yet */
 static bool hourspec = FALSE;      /* No hour specified yet */
@@ -88,6 +83,166 @@ static double glaciers;           /* Glacier level */
 static int starfraction;          /* Star fraction */
 static int starcolor;            /* Star color saturation */
 
+
+struct CmdlineInfo {
+    unsigned int clouds;
+    unsigned int night;
+    float        dimension;
+    float        hourAngle;
+    unsigned int hourSpec;
+    float        inclAngle;
+    unsigned int inclinationSpec;
+    unsigned int meshSize;
+    unsigned int meshSpec;
+    float        power;
+    float        glaciers;
+    float        ice;
+    int          saturation;
+    unsigned int seed;
+    int          stars;
+    unsigned int starsSpec;
+    unsigned int width;
+    unsigned int height;
+};
+
+
+
+static void
+parseCommandLine(int argc, const char **argv,
+                 struct CmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+  Convert program invocation arguments (argc,argv) into a format the 
+  program can use easily, struct cmdlineInfo.  Validate arguments along
+  the way and exit program with message if invalid.
+
+  Note that some string information we return as *cmdlineP is in the storage 
+  argv[] points to.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;
+        /* Instructions to OptParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+
+    unsigned int dimensionSpec, seedSpec,
+        meshSpec, powerSpec, glaciersSpec, iceSpec, saturationSpec,
+        starsSpec, widthSpec, heightSpec;
+    float hour;
+    float inclination;
+    unsigned int mesh;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;
+    OPTENT3(0, "clouds",      OPT_FLAG, NULL, &cmdlineP->clouds, 0);
+    OPTENT3(0, "night",       OPT_FLAG, NULL, &cmdlineP->night, 0);
+    OPTENT3(0, "dimension",   OPT_FLOAT, &cmdlineP->dimension,
+            &dimensionSpec, 0);
+    OPTENT3(0, "hour",        OPT_FLOAT, &hour,
+            &cmdlineP->hourSpec, 0);
+    OPTENT3(0, "inclination", OPT_FLOAT, &inclination,
+            &cmdlineP->inclinationSpec, 0);
+    OPTENT3(0, "tilt",        OPT_FLOAT, &inclination,
+            &cmdlineP->inclinationSpec, 0);
+    OPTENT3(0, "mesh",        OPT_UINT, &mesh,
+            &meshSpec, 0);
+    OPTENT3(0, "power",       OPT_FLOAT, &cmdlineP->power,
+            &powerSpec, 0);
+    OPTENT3(0, "glaciers",    OPT_FLOAT, &cmdlineP->glaciers,
+            &glaciersSpec, 0);
+    OPTENT3(0, "ice",         OPT_FLOAT, &cmdlineP->ice,
+            &iceSpec, 0);
+    OPTENT3(0, "saturation",  OPT_INT,   &cmdlineP->saturation,
+            &saturationSpec, 0);
+    OPTENT3(0, "seed",        OPT_UINT,  &cmdlineP->seed,
+            &seedSpec, 0);
+    OPTENT3(0, "stars",       OPT_INT,   &cmdlineP->stars,
+            &starsSpec, 0);
+    OPTENT3(0, "width",       OPT_UINT,  &cmdlineP->width,
+            &widthSpec, 0);
+    OPTENT3(0, "xsize",       OPT_UINT,  &cmdlineP->width,
+            &widthSpec, 0);
+    OPTENT3(0, "height",      OPT_UINT,  &cmdlineP->height,
+            &heightSpec, 0);
+    OPTENT3(0, "ysize",       OPT_UINT,  &cmdlineP->height,
+            &heightSpec, 0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (dimensionSpec) {
+        if (cmdlineP->dimension <= 0.0)
+            pm_error("-dimension must be greater than zero.  "
+                     "You specified %f", cmdlineP->dimension);
+    } else
+        cmdlineP->dimension = cmdlineP->clouds ? 2.15 : 2.4;
+
+    if (cmdlineP->hourSpec)
+        cmdlineP->hourAngle = (M_PI / 12.0) * (hour + 12.0);
+
+    if (cmdlineP->inclinationSpec)
+        cmdlineP->inclAngle = (M_PI / 180.0) * inclination;
+
+    if (meshSpec) {
+        unsigned int i;
+        if (mesh < 2)
+            pm_error("-mesh value must be at least 2.  "
+                     "You specified %u", mesh);
+        /* Force FFT mesh to the next larger power of 2. */
+        for (i = 2; i < mesh; i <<= 1);
+        cmdlineP->meshSize = i;
+    } else
+        cmdlineP->meshSize = 256;
+
+    if (powerSpec) {
+        if (cmdlineP->power <= 0.0)
+            pm_error("-power must be greater than zero.  "
+                     "You specified %f", cmdlineP->power);
+    } else
+        cmdlineP->power = cmdlineP->clouds ? 0.75 : 1.2;
+
+    if (iceSpec) {
+        if (cmdlineP->ice <= 0.0)
+            pm_error("-ice must be greater than zero.  "
+                     "You specified %f", cmdlineP->ice);
+    } else
+        cmdlineP->ice = 0.4;
+
+    if (glaciersSpec) {
+        if (cmdlineP->glaciers <= 0.0)
+            pm_error("-glaciers must be greater than 0.  "
+                     "You specified %f", cmdlineP->glaciers);
+    } else
+        cmdlineP->glaciers = 0.75;
+
+    if (!starsSpec)
+        cmdlineP->stars = 100;
+
+    if (!saturationSpec)
+        cmdlineP->saturation = 125;
+
+    if (!seedSpec)
+        cmdlineP->seed = pm_randseed();
+
+    if (!widthSpec)
+        cmdlineP->width = 256;
+
+    if (!heightSpec)
+        cmdlineP->height = 256;
+
+    if (argc-1 > 0)
+        pm_error("There are no non-option arguments.  "
+                 "You specified %u", argc-1);
+
+    free(option_def);
+}
+
+
 /*  FOURN  --  Multi-dimensional fast Fourier transform
 
     Called with arguments:
@@ -274,19 +429,6 @@ static void spectralsynth(x, n, h)
 }
 
 
-static unsigned int
-initseed(void) {
-    /*  Generate initial random seed.  */
-
-    unsigned int i;
-
-    srand(pm_randseed());
-    for (i = 0; i < 7; ++i)
-        rand();
-    return rand();
-}
-
-
 
 /*  TEMPRGB  --  Calculate the relative R, G, and B components  for  a
          black  body  emitting  light  at a given temperature.
@@ -417,7 +559,8 @@ makeCp(float *      const a,
 
 
 static void
-createPlanetStuff(float *          const a,
+createPlanetStuff(bool             const clouds,
+                  float *          const a,
                   unsigned int     const n,
                   double **        const uP,
                   double **        const u1P,
@@ -456,7 +599,9 @@ createPlanetStuff(float *          const a,
             "        -inclination %.0f -hour %d -ice %.2f -glaciers %.2f",
             (siang * (180.0 / M_PI)),
             (int) (((shang * (12.0 / M_PI)) + 12 +
-                    (flipped ? 12 : 0)) + 0.5) % 24, icelevel, glaciers);
+                    (flipped ? 12 : 0)) + 0.5) % 24,
+            icelevel,
+            glaciers);
         pm_message("        -stars %d -saturation %d.",
                    starfraction, starcolor);
     }
@@ -531,9 +676,9 @@ generateCloudRow(pixel *         const pixels,
 
     /* Render the FFT output as clouds. */
 
-    unsigned int j;
+    unsigned int col;
 
-    for (j = 0; j < cols; j++) {
+    for (col = 0; col < cols; ++col) {
         double r;
         pixval w;
         
@@ -542,15 +687,15 @@ generateCloudRow(pixel *         const pixels,
            referenced below does not exist.
         */
         if (t1 > 0.0)
-            r += t1 * u1[j] * cp[byf + bxf[j]] +
-                t1 * u[j]  * cp[byf + bxc[j]];
+            r += t1 * u1[col] * cp[byf + bxf[col]] +
+                t1 * u[col]  * cp[byf + bxc[col]];
         if (t > 0.0)
-            r += t * u1[j] * cp[byc + bxf[j]] +
-                t * u[j]  * cp[byc + bxc[j]];
+            r += t * u1[col] * cp[byc + bxf[col]] +
+                t * u[col]  * cp[byc + bxc[col]];
         
         w = (r > 127.0) ? (maxval * ((r - 127.0) / 128.0)) : 0;
         
-        PPM_ASSIGN(*(pixels + j), w, w, maxval);
+        PPM_ASSIGN(pixels[col], w, w, maxval);
     }
 }
 
@@ -819,7 +964,7 @@ genplanet(bool         const stars,
         pm_message("%s: -seed %d -dimension %.2f -power %.2f -mesh %d",
                    clouds ? "clouds" : "planet",
                    rseed, fracdim, powscale, meshsize);
-        createPlanetStuff(a, n, &u, &u1, &bxf, &bxc, &cp, &sunvec, 
+        createPlanetStuff(clouds, a, n, &u, &u1, &bxf, &bxc, &cp, &sunvec, 
                           cols, maxval);
     }
 
@@ -940,19 +1085,14 @@ static bool
 planet(unsigned int const cols,
        unsigned int const rows,
        bool         const stars,
-       bool         const clouds) {
+       bool         const clouds,
+       unsigned int const rseed) {
 /*----------------------------------------------------------------------------
    Make a planet.
 -----------------------------------------------------------------------------*/
     float * a;
     bool error;
-    unsigned int rseed;        /* Current random seed */
-    
-    if (seedspec)
-        rseed = seedarg;
-    else 
-        rseed = initseed();
-    
+
     initgauss(rseed);
     
     if (stars) {
@@ -981,200 +1121,39 @@ planet(unsigned int const cols,
 
 
 
-
 int 
-main(int argc, char ** argv) {
+main(int argc, const char ** argv) {
 
+    struct CmdlineInfo cmdline;
     bool success;
-    int i;
-    const char * const usage = "\n\
-[-width|-xsize <x>] [-height|-ysize <y>] [-mesh <n>]\n\
-[-clouds] [-dimension <f>] [-power <f>] [-seed <n>]\n\
-[-hour <f>] [-inclination|-tilt <f>] [-ice <f>] [-glaciers <f>]\n\
-[-night] [-stars <n>] [-saturation <n>]";
-    bool dimspec = FALSE, meshspec = FALSE, powerspec = FALSE,
-        widspec = FALSE, hgtspec = FALSE, icespec = FALSE,
-        glacspec = FALSE, starspec = FALSE, starcspec = FALSE;
-
-    int cols, rows;     /* Dimensions of our output image */
-
-    ppm_init(&argc, argv);
-    i = 1;
-    
-    while ((i < argc) && (argv[i][0] == '-') && (argv[i][1] != '\0')) {
-
-        if (pm_keymatch(argv[i], "-clouds", 2)) {
-            clouds = TRUE;
-        } else if (pm_keymatch(argv[i], "-night", 2)) {
-            stars = TRUE;
-        } else if (pm_keymatch(argv[i], "-dimension", 2)) {
-            if (dimspec) {
-                pm_error("already specified a dimension");
-            }
-            i++;
-            if ((i == argc) || (sscanf(argv[i], "%lf", &fracdim)  != 1))
-                pm_usage(usage);
-            if (fracdim <= 0.0) {
-                pm_error("fractal dimension must be greater than 0");
-            }
-            dimspec = TRUE;
-        } else if (pm_keymatch(argv[i], "-hour", 3)) {
-            if (hourspec) {
-                pm_error("already specified an hour");
-            }
-            i++;
-            if ((i == argc) || (sscanf(argv[i], "%lf", &hourangle) != 1))
-                pm_usage(usage);
-            hourangle = (M_PI / 12.0) * (hourangle + 12.0);
-            hourspec = TRUE;
-        } else if (pm_keymatch(argv[i], "-inclination", 3) ||
-                   pm_keymatch(argv[i], "-tilt", 2)) {
-            if (inclspec) {
-                pm_error("already specified an inclination/tilt");
-            }
-            i++;
-            if ((i == argc) || (sscanf(argv[i], "%lf", &inclangle) != 1))
-                pm_usage(usage);
-            inclangle = (M_PI / 180.0) * inclangle;
-            inclspec = TRUE;
-        } else if (pm_keymatch(argv[i], "-mesh", 2)) {
-            unsigned int j;
 
-            if (meshspec) {
-                pm_error("already specified a mesh size");
-            }
-            i++;
-            if ((i == argc) || (sscanf(argv[i], "%d", &meshsize) != 1))
-                pm_usage(usage);
+    unsigned int cols, rows;     /* Dimensions of our output image */
 
-            if (meshsize < 2)
-                pm_error("mesh must be at least 2");
+    pm_proginit(&argc, argv);
 
-            /* Force FFT mesh to the next larger power of 2. */
+    parseCommandLine(argc, argv, &cmdline);
 
-            for (j = meshsize; (j & 1) == 0; j >>= 1) ;
-
-            if (j != 1) {
-                for (j = 2; j < meshsize; j <<= 1) ;
-                meshsize = j;
-            }
-            meshspec = TRUE;
-        } else if (pm_keymatch(argv[i], "-power", 2)) {
-            if (powerspec) {
-                pm_error("already specified a power factor");
-            }
-            i++;
-            if ((i == argc) || (sscanf(argv[i], "%lf", &powscale) != 1))
-                pm_usage(usage);
-            if (powscale <= 0.0) {
-                pm_error("power factor must be greater than 0");
-            }
-            powerspec = TRUE;
-        } else if (pm_keymatch(argv[i], "-ice", 3)) {
-            if (icespec) {
-                pm_error("already specified ice cap level");
-            }
-            i++;
-            if ((i == argc) || (sscanf(argv[i], "%lf", &icelevel) != 1))
-                pm_usage(usage);
-            if (icelevel <= 0.0) {
-                pm_error("ice cap level must be greater than 0");
-            }
-            icespec = TRUE;
-        } else if (pm_keymatch(argv[i], "-glaciers", 2)) {
-            if (glacspec) {
-                pm_error("already specified glacier level");
-            }
-            i++;
-            if ((i == argc) || (sscanf(argv[i], "%lf", &glaciers) != 1))
-                pm_usage(usage);
-            if (glaciers <= 0.0) {
-                pm_error("glacier level must be greater than 0");
-            }
-            glacspec = TRUE;
-        } else if (pm_keymatch(argv[i], "-stars", 3)) {
-            if (starspec) {
-                pm_error("already specified a star fraction");
-            }
-            i++;
-            if ((i == argc) || (sscanf(argv[i], "%d", &starfraction) != 1))
-                pm_usage(usage);
-            starspec = TRUE;
-        } else if (pm_keymatch(argv[i], "-saturation", 3)) {
-            if (starcspec) {
-                pm_error("already specified a star color saturation");
-            }
-            i++;
-            if ((i == argc) || (sscanf(argv[i], "%d", &starcolor) != 1))
-                pm_usage(usage);
-            starcspec = TRUE;
-        } else if (pm_keymatch(argv[i], "-seed", 3)) {
-            if (seedspec) {
-                pm_error("already specified a random seed");
-            }
-            i++;
-            if ((i == argc) || (sscanf(argv[i], "%u", &seedarg) != 1))
-                pm_usage(usage);
-            seedspec = TRUE;
-        } else if (pm_keymatch(argv[i], "-xsize", 2) ||
-                   pm_keymatch(argv[i], "-width", 2)) {
-            if (widspec) {
-                pm_error("already specified a width/xsize");
-            }
-            i++;
-            if ((i == argc) || (sscanf(argv[i], "%d", &screenxsize) != 1))
-                pm_usage(usage);
-            widspec = TRUE;
-        } else if (pm_keymatch(argv[i], "-ysize", 2) ||
-                   pm_keymatch(argv[i], "-height", 3)) {
-            if (hgtspec) {
-                pm_error("already specified a height/ysize");
-            }
-            i++;
-            if ((i == argc) || (sscanf(argv[i], "%d", &screenysize) != 1))
-                pm_usage(usage);
-            hgtspec = TRUE;
-        } else {
-            pm_usage(usage);
-        }
-        i++;
-    }
-
-
-    /* Set defaults when explicit specifications were not given.
-
-       The  default  fractal  dimension  and  power  scale depend upon
-       whether we are generating a planet or clouds. 
-    */
-    
-    if (!dimspec) {
-        fracdim = clouds ? 2.15 : 2.4;
-    }
-    if (!powerspec) {
-        powscale = clouds ? 0.75 : 1.2;
-    }
-    if (!icespec) {
-        icelevel = 0.4;
-    }
-    if (!glacspec) {
-        glaciers = 0.75;
-    }
-    if (!starspec) {
-        starfraction = 100;
-    }
-    if (!starcspec) {
-        starcolor = 125;
-    }
+    fracdim      = cmdline.dimension;
+    hourspec     = cmdline.hourSpec;
+    hourangle    = cmdline.hourAngle;
+    inclspec     = cmdline.inclinationSpec;
+    inclangle    = cmdline.inclAngle;
+    meshsize     = cmdline.meshSize;
+    powscale     = cmdline.power;
+    icelevel     = cmdline.ice;
+    glaciers     = cmdline.glaciers;
+    starfraction = cmdline.stars;
+    starcolor    = cmdline.saturation;
 
     /* Force  screen to be at least  as wide as it is high.  Long,
        skinny screens  cause  crashes  because  picture  width  is
        calculated based on height.  
     */
 
-    cols = (MAX(screenysize, screenxsize) + 1) & (~1);
-    rows = screenysize;
+    cols = (MAX(cmdline.height, cmdline.width) + 1) & (~1);
+    rows = cmdline.height;
 
-    success = planet(cols, rows, stars, clouds);
+    success = planet(cols, rows, cmdline.night, cmdline.clouds, cmdline.seed);
 
     exit(success ? 0 : 1);
 }
diff --git a/generator/ppmrainbow b/generator/ppmrainbow
index 96e304ac..c0568d9b 100755
--- a/generator/ppmrainbow
+++ b/generator/ppmrainbow
@@ -1,4 +1,28 @@
-#!/usr/bin/perl -wl
+#!/bin/sh
+
+##############################################################################
+# This is essentially a Perl program.  We exec the Perl interpreter specifying
+# this same file as the Perl program and use the -x option to cause the Perl
+# interpreter to skip down to the Perl code.  The reason we do this instead of
+# just making /usr/bin/perl the script interpreter (instead of /bin/sh) is
+# that the user may have multiple Perl interpreters and the one he wants to
+# use is properly located in the PATH.  The user's choice of Perl interpreter
+# may be crucial, such as when the user also has a PERL5LIB environment
+# variable and it selects modules that work with only a certain main
+# interpreter program.
+#
+# An alternative some people use is to have /usr/bin/env as the script
+# interpreter.  We don't do that because we think the existence and
+# compatibility of /bin/sh is more reliable.
+#
+# Note that we aren't concerned about efficiency because the user who needs
+# high efficiency can use directly the programs that this program invokes.
+#
+##############################################################################
+
+exec perl -w -x -S -- "$0" "$@"
+
+#!/usr/bin/perl
 use strict;
 use Getopt::Long;