about summary refs log tree commit diff
path: root/converter/pbm
diff options
context:
space:
mode:
Diffstat (limited to 'converter/pbm')
-rw-r--r--converter/pbm/g3topbm.c181
-rw-r--r--converter/pbm/mdatopbm.c267
-rw-r--r--converter/pbm/pbmto4425.c219
-rw-r--r--converter/pbm/pbmtolj.c34
-rw-r--r--converter/pbm/pbmtomda.c217
-rw-r--r--converter/pbm/pbmtoppa/pbmtoppa.c209
-rw-r--r--converter/pbm/pbmtoxbm.c145
-rw-r--r--converter/pbm/pktopbm.c830
-rw-r--r--converter/pbm/thinkjettopbm.l8
-rw-r--r--converter/pbm/ybmtopbm.c5
10 files changed, 1251 insertions, 864 deletions
diff --git a/converter/pbm/g3topbm.c b/converter/pbm/g3topbm.c
index 5db507a3..f9655fce 100644
--- a/converter/pbm/g3topbm.c
+++ b/converter/pbm/g3topbm.c
@@ -21,6 +21,8 @@
 #define _DEFAULT_SOURCE /* New name for SVID & BSD source defines */
 #define _BSD_SOURCE   /* Make nstring.h define strcaseeq() */
 
+#include <assert.h>
+
 #include "pm_c_util.h"
 #include "pbm.h"
 #include "shhopt.h"
@@ -71,10 +73,6 @@ The receiver may be less patient.  It may opt to disconnect if one row
 is not received within 5 seconds.
 */
 
-static G3TableEntry * whash[HASHSIZE];
-static G3TableEntry * bhash[HASHSIZE];
-
-
 struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
@@ -85,6 +83,7 @@ struct CmdlineInfo {
     unsigned int stretch;
     unsigned int stop_error;
     unsigned int expectedLineSize;
+    unsigned int correctlong;
 };
 
 
@@ -120,6 +119,8 @@ parseCommandLine(int argc, const char ** const argv,
             &widthSpec,                0);
     OPTENT3(0, "paper_size",       OPT_STRING, &paperSize,
             &paper_sizeSpec,           0);
+    OPTENT3(0, "correctlong",      OPT_FLAG,  NULL, &cmdlineP->correctlong,
+            0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
@@ -163,6 +164,11 @@ parseCommandLine(int argc, const char ** const argv,
 
 
 
+typedef struct {
+    const G3TableEntry * whash[HASHSIZE];
+    const G3TableEntry * bhash[HASHSIZE];
+} BwHash;
+
 struct BitStream {
 
     FILE * fileP;
@@ -275,16 +281,16 @@ skipToNextLine(struct BitStream * const bitStreamP) {
 
 
 static void
-addtohash(G3TableEntry *     hash[],
-          G3TableEntry       table[],
-          unsigned int const n,
-          int          const a,
-          int          const b) {
+addtohash(const G3TableEntry ** const hash,
+          const G3TableEntry *  const table,
+          unsigned int          const n,
+          int                   const a,
+          int                   const b) {
 
     unsigned int i;
 
     for (i = 0; i < n; ++i) {
-        G3TableEntry * const teP = &table[i*2];
+        const G3TableEntry * const teP = &table[i*2];
         unsigned int const pos =
             ((teP->length + a) * (teP->code + b)) % HASHSIZE;
         if (hash[pos])
@@ -295,38 +301,51 @@ addtohash(G3TableEntry *     hash[],
 
 
 
-static G3TableEntry *
-hashfind(G3TableEntry *       hash[],
-         int            const length,
-         int            const code,
-         int            const a,
-         int            const b) {
+static const G3TableEntry *
+hashfind(const G3TableEntry * const * const hash,
+         unsigned int                 const length,
+         int                          const code,
+         int                          const a,
+         int                          const b) {
 
-    unsigned int pos;
-    G3TableEntry * te;
+    unsigned int         const pos = ((length + a) * (code + b)) % HASHSIZE;
+    const G3TableEntry * const teP = hash[pos];
 
-    pos = ((length + a) * (code + b)) % HASHSIZE;
-    te = hash[pos];
-    return ((te && te->length == length && te->code == code) ? te : NULL);
+    return ((teP && teP->length == length && teP->code == code) ? teP : NULL);
 }
 
 
 
-static void
-buildHashes(G3TableEntry * (*whashP)[HASHSIZE],
-            G3TableEntry * (*bhashP)[HASHSIZE]) {
+static BwHash *
+newBwHash() {
 
-    unsigned int i;
+    BwHash * bwHashP;
 
-    for (i = 0; i < HASHSIZE; ++i)
-        (*whashP)[i] = (*bhashP)[i] = NULL;
+    MALLOCVAR(bwHashP);
 
-    addtohash(*whashP, &g3ttable_table[0], 64, WHASHA, WHASHB);
-    addtohash(*whashP, &g3ttable_mtable[2], 40, WHASHA, WHASHB);
+    if (!bwHashP)
+        pm_error("Unable to allocate memory for hashes");
+    else {
+        unsigned int i;
+        /* Initialize */
+        for (i = 0; i < HASHSIZE; ++i)
+            bwHashP->whash[i] = bwHashP->bhash[i] = NULL;
 
-    addtohash(*bhashP, &g3ttable_table[1], 64, BHASHA, BHASHB);
-    addtohash(*bhashP, &g3ttable_mtable[3], 40, BHASHA, BHASHB);
+        addtohash(bwHashP->whash, &g3ttable_table [0], 64, WHASHA, WHASHB);
+        addtohash(bwHashP->whash, &g3ttable_mtable[2], 40, WHASHA, WHASHB);
 
+        addtohash(bwHashP->bhash, &g3ttable_table [1], 64, BHASHA, BHASHB);
+        addtohash(bwHashP->bhash, &g3ttable_mtable[3], 40, BHASHA, BHASHB);
+    }
+    return bwHashP;
+}
+
+
+
+static void
+freeBwHash(BwHash * const bwHashP) {
+
+    free(bwHashP);
 }
 
 
@@ -342,10 +361,11 @@ makeRowWhite(unsigned char * const packedBitrow,
 
 
 
-static G3TableEntry *
-g3code(unsigned int const curcode,
-       unsigned int const curlen,
-       bit          const color) {
+static const G3TableEntry *
+g3code(unsigned int   const curcode,
+       unsigned int   const curlen,
+       bit            const color,
+       const BwHash * const bwHashP) {
 /*----------------------------------------------------------------------------
    Return the position in the code tables mtable and ttable of the
    G3 code which is the 'curlen' bits long with value 'curcode'.
@@ -353,20 +373,20 @@ g3code(unsigned int const curcode,
    Note that it is the _position_ in the table that determines the meaning
    of the code.  The contents of the table entry do not.
 -----------------------------------------------------------------------------*/
-    G3TableEntry * retval;
+    const G3TableEntry * retval;
 
     switch (color) {
     case PBM_WHITE:
         if (curlen < 4)
             retval = NULL;
         else
-            retval = hashfind(whash, curlen, curcode, WHASHA, WHASHB);
+            retval = hashfind(bwHashP->whash, curlen, curcode, WHASHA, WHASHB);
         break;
     case PBM_BLACK:
         if (curlen < 2)
             retval = NULL;
         else
-            retval = hashfind(bhash, curlen, curcode, BHASHA, BHASHB);
+            retval = hashfind(bwHashP->bhash, curlen, curcode, BHASHA, BHASHB);
         break;
     default:
         pm_error("INTERNAL ERROR: color is not black or white");
@@ -481,6 +501,7 @@ formatBadCodeException(const char ** const exceptionP,
 static void
 readFaxRow(struct BitStream * const bitStreamP,
            unsigned char *    const packedBitrow,
+           BwHash *           const bwHashP,
            unsigned int *     const lineLengthP,
            const char **      const exceptionP,
            const char **      const errorP) {
@@ -561,7 +582,7 @@ readFaxRow(struct BitStream * const bitStreamP,
                     done = TRUE;
                 } else if (curcode != 0) {
                     const G3TableEntry * const teP =
-                        g3code(curcode, curlen, currentColor);
+                        g3code(curcode, curlen, currentColor, bwHashP);
                         /* Address of structure that describes the
                            current G3 code.  Null means 'curcode' isn't
                            a G3 code yet (probably just the beginning of one)
@@ -644,16 +665,21 @@ typedef struct {
         */
     bool warned;
         /* We have warned the user that he has a line length problem */
+
     bool tolerateErrors;
         /* Try to continue when we detect a line size error, as opposed to
            aborting the program.
         */
-} lineSizeAnalyzer;
+    unsigned int lineSizeCt[MAXCOLS+1];
+        /* Histogram of line sizes in image -- lineSizeCt[i] is the number
+           of lines we've seen of size i.
+        */
+} LineSizeAnalyzer;
 
 
 
 static void
-initializeLineSizeAnalyzer(lineSizeAnalyzer * const analyzerP,
+initializeLineSizeAnalyzer(LineSizeAnalyzer * const analyzerP,
                            unsigned int       const expectedLineSize,
                            bool               const tolerateErrors) {
 
@@ -662,12 +688,19 @@ initializeLineSizeAnalyzer(lineSizeAnalyzer * const analyzerP,
 
     analyzerP->maxLineSize = 0;
     analyzerP->warned      = FALSE;
+
+    {
+        unsigned int i;
+
+        for (i = 0; i < MAXCOLS; ++i)
+            analyzerP->lineSizeCt[i] = 0;
+    }
 }
 
 
 
 static void
-analyzeLineSize(lineSizeAnalyzer * const analyzerP,
+analyzeLineSize(LineSizeAnalyzer * const analyzerP,
                 unsigned int       const thisLineSize) {
 
     const char * error;
@@ -700,6 +733,45 @@ analyzeLineSize(lineSizeAnalyzer * const analyzerP,
         pm_strfree(error);
     }
     analyzerP->maxLineSize = MAX(thisLineSize, analyzerP->maxLineSize);
+
+    assert(thisLineSize <= MAXCOLS);
+    ++analyzerP->lineSizeCt[thisLineSize];
+}
+
+
+
+static unsigned int
+imageLineSize(const LineSizeAnalyzer * const lineSizeAnalyzerP,
+              bool                     const mustCorrectLongLine) {
+/*----------------------------------------------------------------------------
+   The width of the fax in pixels, based on the analysis of the image
+   *lineSizeAnalyzerP.
+
+   Zero if the fax contains no lines.
+-----------------------------------------------------------------------------*/
+    unsigned int retval;
+
+    if (mustCorrectLongLine) {
+        /* Assume that long lines are actually concatenation of two
+           lines because the EOL code that was supposed to separate them
+           got lost.
+
+           Assume the most common line length in the image is the correct line
+           length for the image and that other line lengths are due to
+           corruption
+        */
+        unsigned int modeSoFar;
+        unsigned int i;
+
+        for (i = 0, modeSoFar = 0; i <= MAXCOLS; ++i) {
+            if (lineSizeAnalyzerP->lineSizeCt[i] > modeSoFar)
+                modeSoFar = i;
+        }
+        retval = modeSoFar;
+    } else {
+        retval = lineSizeAnalyzerP->maxLineSize;
+    }
+    return retval;
 }
 
 
@@ -717,12 +789,14 @@ static void
 readFax(struct BitStream * const bitStreamP,
         bool               const stretch,
         unsigned int       const expectedLineSize,
-        bool               const tolerateErrors,
+        bool               const mustTolerateErrors,
+        bool               const mustCorrectLongLine,
+        BwHash *           const bwHashP,
         unsigned char ***  const packedBitsP,
         unsigned int *     const colsP,
         unsigned int *     const rowsP) {
 
-    lineSizeAnalyzer lineSizeAnalyzer;
+    LineSizeAnalyzer lineSizeAnalyzer;
     unsigned char ** packedBits;
     const char * error;
     bool eof;
@@ -731,7 +805,7 @@ readFax(struct BitStream * const bitStreamP,
     MALLOCARRAY_NOFAIL(packedBits, MAXROWS);
 
     initializeLineSizeAnalyzer(&lineSizeAnalyzer,
-                               expectedLineSize, tolerateErrors);
+                               expectedLineSize, mustTolerateErrors);
 
     eof = FALSE;
     error = NULL;
@@ -747,10 +821,10 @@ readFax(struct BitStream * const bitStreamP,
             const char * exception;
 
             packedBits[row] = pbm_allocrow_packed(MAXCOLS);
-            readFaxRow(bitStreamP, packedBits[row],
+            readFaxRow(bitStreamP, packedBits[row], bwHashP,
                        &lineSize, &exception, &error);
 
-            handleRowException(exception, error, row, tolerateErrors);
+            handleRowException(exception, error, row, mustTolerateErrors);
 
             if (!error) {
                 if (lineSize == 0) {
@@ -774,7 +848,8 @@ readFax(struct BitStream * const bitStreamP,
         }
     }
     *rowsP        = row;
-    *colsP        = lineSizeAnalyzer.maxLineSize;
+    *colsP        = imageLineSize(&lineSizeAnalyzer, mustCorrectLongLine);
+
     *packedBitsP  = packedBits;
 }
 
@@ -788,6 +863,7 @@ main(int argc, const char * argv[]) {
     struct BitStream bitStream;
     unsigned int rows, cols;
     unsigned char ** packedBits;
+    BwHash * bwHashP;
 
     pm_proginit(&argc, argv);
 
@@ -805,10 +881,10 @@ main(int argc, const char * argv[]) {
     }
     skipToNextLine(&bitStream);
 
-    buildHashes(&whash, &bhash);
+    bwHashP = newBwHash();
 
     readFax(&bitStream, cmdline.stretch, cmdline.expectedLineSize,
-            !cmdline.stop_error,
+            !cmdline.stop_error, !!cmdline.correctlong, bwHashP,
             &packedBits, &cols, &rows);
 
     pm_close(ifP);
@@ -825,5 +901,10 @@ main(int argc, const char * argv[]) {
 
     freeBits(packedBits, rows, cmdline.stretch);
 
+    freeBwHash(bwHashP);
+
     return 0;
 }
+
+
+
diff --git a/converter/pbm/mdatopbm.c b/converter/pbm/mdatopbm.c
index 461b3f80..670ba8c4 100644
--- a/converter/pbm/mdatopbm.c
+++ b/converter/pbm/mdatopbm.c
@@ -1,4 +1,3 @@
-
 /***************************************************************************
 
     MDATOPBM: Convert Microdesign area to portable bitmap
@@ -30,156 +29,188 @@
 
 typedef unsigned char mdbyte;   /* Must be exactly one byte */
 
-static FILE *infile;            /* Input file */
 static mdbyte header[128];      /* MDA file header */
 static bit **data;          /* PBM image */
 static mdbyte *mdrow;           /* MDA row after decompression (MD3 only) */
 static int bInvert = 0;     /* Invert image? */
 static int bScale  = 0;     /* Scale image? */
 static int bAscii  = 0;     /* Output ASCII PBM? */
-static int nInRows, nInCols;        /* Height, width of input (rows x bytes) */
-static int nOutCols, nOutRows;      /* Height, width of output (rows x bytes) */
 
-static mdbyte 
-getbyte(void) {
+static mdbyte
+getbyte(FILE * const ifP) {
     /* Read a byte from the input stream, with error trapping */
     int b;
 
-    b = fgetc(infile);
+    b = fgetc(ifP);
+
+    if (b == EOF)
+        pm_error("Unexpected end of MDA file");
 
-    if (b == EOF) pm_error("Unexpected end of MDA file\n");
-    
     return (mdbyte)b;
 }
 
 
 
-static void 
-render_byte(int *col, int *xp, int *yp, int b) {
+static void
+renderByte(unsigned int   const nInCols,
+           unsigned int   const nOutRows,
+           unsigned int * const colP,
+           unsigned int * const xP,
+           unsigned int * const yP,
+           int            const b) {
+/*----------------------------------------------------------------------------
+  Convert a byte to 8 cells in the destination bitmap
 
-/* Convert a byte to 8 cells in the destination bitmap 
- *
- * *col = source column
- * *xp  = destination column
- * *yp  = destination row
- *  b   = byte to draw
- *
- * Will update *col, *xp and *yp to point to the next bit of the row.
- */
+  As input
 
-    int mask = 0x80;
-    int n;
-    int y3 = *yp;
+    *colP = source column
+    *xP  = destination column
+    *yP  = destination row
+    b    = byte to draw
 
-    if (bScale) y3 *= 2;
+  As output, update *colP, *xP and *yP to point to the next bit of the row.
+-----------------------------------------------------------------------------*/
+    int const y3 =  bScale ? *yP * 2 : *yP;
 
-    if (y3 >= nOutRows) return;
+    if (y3 < nOutRows) {
+        unsigned int n;
+        int mask;
 
-    for (n = 0; n < 8; ++n) {
-        if (bInvert) data[y3][*xp] = (b & mask) ? PBM_BLACK : PBM_WHITE;
-        else         data[y3][*xp] = (b & mask) ? PBM_WHITE : PBM_BLACK;
-        mask = mask >> 1;
-        if (bScale) data[y3+1][*xp] = data[y3][*xp];
-        ++(*xp);
-    }
-    ++(*col);       /* Next byte */
-    if ((*col) >= nInCols) {
-        /* Onto next line? */
-        *col = 0;
-        *xp = 0;
-        ++(*yp);
+        for (n = 0, mask = 0x80; n < 8; ++n) {
+            if (bInvert) data[y3][*xP] = (b & mask) ? PBM_BLACK : PBM_WHITE;
+            else         data[y3][*xP] = (b & mask) ? PBM_WHITE : PBM_BLACK;
+            mask = mask >> 1;
+            if (bScale)
+                data[y3+1][*xP] = data[y3][*xP];
+            ++(*xP);
+        }
+        ++(*colP);       /* Next byte */
+        if ((*colP) >= nInCols) {
+            /* Onto next line? */
+            *colP = 0;
+            *xP = 0;
+            ++(*yP);
+        }
     }
 }
 
 
-static void 
-md2_trans(void) {
-    /* Convert a MicroDesign 2 area to PBM */
-    /* MD2 has RLE encoding that may go over */
 
-    int x1, y1, col;    /* multiple lines. */
+static void
+md2Trans(FILE *       const ifP,
+         unsigned int const nInRows,
+         unsigned int const nInCols,
+         unsigned int const nOutRows,
+         unsigned int const nOutCols) {
+/*----------------------------------------------------------------------------
+   Convert a MicroDesign 2 area to PBM
+
+   MD2 has RLE encoding that may go over
+-----------------------------------------------------------------------------*/
+    unsigned int x1, y1, col;    /* multiple lines. */
     mdbyte b;
-    int c;
 
     x1 = y1 = col = 0;
 
     while (y1 < nInRows) {
-        b = getbyte();
-    
+        b = getbyte(ifP);
+
         if (b == 0 || b == 0xFF) {
             /* RLE sequence */
-            c = getbyte();
-            if (c == 0) c = 256;
-            while (c > 0) { 
-                render_byte(&col, &x1, &y1, b); 
-                --c; 
+            int c;
+            c = getbyte(ifP);
+            if (c == 0)
+                c = 256;
+            while (c > 0) {
+                renderByte(nInCols, nOutRows, &col, &x1, &y1, b);
+                --c;
             }
-        }
-        else 
-            render_byte(&col, &x1, &y1, b);    /* Not RLE */
+        } else
+            /* Not RLE */
+            renderByte(nInCols, nOutRows, &col, &x1, &y1, b);
     }
 }
 
 
 
-static void 
-md3_trans(void) {
-    /* Convert MD3 file. MD3 are encoded as rows, and 
-       there are three types. 
-    */
-    int x1, y1, col;
-    mdbyte b;
-    int c, d, n;
+static void
+md3Trans(FILE *       const ifP,
+         unsigned int const nInRows,
+         unsigned int const nInCols,
+         unsigned int const nOutRows,
+         unsigned int const nOutCols) {
+/*----------------------------------------------------------------------------
+   Convert MD3 file. MD3 are encoded as rows, and there are three types.
+-----------------------------------------------------------------------------*/
+    unsigned int y1;
 
     for (y1 = 0; y1 < nInRows; ++y1) {
-        b = getbyte();   /* Row type */
+        mdbyte b;
+
+        b = getbyte(ifP);   /* Row type */
         switch(b)  {
-        case 0: /* All the same byte */
-            c = getbyte();
-            for (n = 0; n < nInCols; n++) 
-                mdrow[n] = c;
-            break;
-            
+        case 0: {  /* All the same byte */
+            int c;
+            unsigned int i;
+            c = getbyte(ifP);
+            for (i = 0; i < nInCols; ++i)
+                mdrow[i] = c;
+        } break;
+
         case 1:      /* Encoded data */
-        case 2: col = 0; /* Encoded as XOR with previous row */
+        case 2: {     /* Encoded as XOR with previous row */
+            unsigned int col;
+            col = 0;
             while (col < nInCols) {
-                c = getbyte();
+                int c;
+                c = getbyte(ifP);
                 if (c >= 129) {
                     /* RLE sequence */
+                    unsigned int i;
+                    int d;
                     c = 257 - c;
-                    d = getbyte();
-                    for (n = 0; n < c; ++n) {
-                        if (b == 1) 
+                    d = getbyte(ifP);
+                    for (i = 0; i < c; ++i) {
+                        if (b == 1)
                             mdrow[col++] = d;
-                        else 
+                        else
                             mdrow[col++] ^= d;
-                    }   
+                    }
                 } else {
                     /* not RLE sequence */
-                        ++c;
-                        for (n = 0; n < c; ++n) {
-                            d = getbyte();
-                            if (b == 1) 
-                                mdrow[col++] = d;
-                            else
-                                mdrow[col++] ^= d;
-                        }
-                } 
+                    unsigned int i;
+                    ++c;
+                    for (i = 0; i < c; ++i) {
+                        int d;
+                        d = getbyte(ifP);
+                        if (b == 1)
+                            mdrow[col++] = d;
+                        else
+                            mdrow[col++] ^= d;
+                    }
+                }
             }
+        } break;
         }
-        /* Row loaded. Convert it. */
-        x1 = 0; col = 0; 
-        for (n = 0; n < nInCols; ++n) {
-            d  = y1;
-            render_byte(&col, &x1, &d, mdrow[n]);
+        {
+            /* Row loaded. Convert it. */
+            unsigned int x1;
+            unsigned int col;
+            unsigned int i;
+
+            for (i = 0, x1 = 0, col = 0; i < nInCols; ++i) {
+                unsigned int d;
+                d = y1;
+                renderByte(nInCols, nOutRows, &col, &x1, &d, mdrow[i]);
+            }
         }
     }
 }
 
 
 
-static void 
-usage(char *s) {        
+static void
+usage(const char *s) {
     printf("mdatopbm v1.00, Copyright (C) 1999 "
            "John Elliott <jce@seasip.demon.co.uk>\n"
            "This program is redistributable under the terms of "
@@ -197,17 +228,24 @@ usage(char *s) {
 
 
 
-int 
-main(int argc, char **argv) {
+int
+main(int argc, const char **argv) {
+
+    FILE * ifP;
     int n, optstop = 0;
-    char *fname = NULL;
+    const char * fname;
+    unsigned int nInRows, nInCols;
+        /* Height, width of input (rows x bytes) */
+    unsigned int nOutCols, nOutRows;
+        /* Height, width of output (rows x bytes) */
 
-    pbm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     /* Parse options */
 
+    fname = NULL;  /* initial value */
     for (n = 1; n < argc; ++n) {
-        if (argv[n][0] == '-' && !optstop) {   
+        if (argv[n][0] == '-' && !optstop) {
             if (argv[n][1] == 'a' || argv[n][1] == 'A') bAscii = 1;
             if (argv[n][1] == 'd' || argv[n][1] == 'D') bScale = 1;
             if (argv[n][1] == 'i' || argv[n][1] == 'I') bInvert = 1;
@@ -225,47 +263,50 @@ main(int argc, char **argv) {
         }
     }
 
-    if (fname) 
-        infile = pm_openr(fname);
+    if (fname)
+        ifP = pm_openr(fname);
     else
-        infile = stdin;
+        ifP = stdin;
 
     /* Read MDA file header */
 
-    if (fread(header, 1, 128, infile) < 128)
+    if (fread(header, 1, 128, ifP) < 128)
         pm_error("Not a .MDA file\n");
 
-    if (strncmp((char*) header, ".MDA", 4) && 
+    if (strncmp((char*) header, ".MDA", 4) &&
         strncmp((char*) header, ".MDP", 4))
         pm_error("Not a .MDA file\n");
 
     {
         short yy;
-        pm_readlittleshort(infile, &yy); nInRows = yy;
-        pm_readlittleshort(infile, &yy); nInCols = yy;
+        pm_readlittleshort(ifP, &yy); nInRows = yy;
+        pm_readlittleshort(ifP, &yy); nInCols = yy;
     }
-    
+
     nOutCols = 8 * nInCols;
     nOutRows = nInRows;
-    if (bScale) 
+    if (bScale)
         nOutRows *= 2;
 
     data = pbm_allocarray(nOutCols, nOutRows);
-    
+
     MALLOCARRAY_NOFAIL(mdrow, nInCols);
 
-    if (header[21] == '0') 
-        md2_trans();
+    if (header[21] == '0')
+        md2Trans(ifP, nInRows, nInCols, nOutRows, nOutCols);
     else
-        md3_trans();
+        md3Trans(ifP, nInRows, nInCols, nOutRows, nOutCols);
 
-    pbm_writepbm(stdout, data, nInCols*8, nOutRows, bAscii);
+    pbm_writepbm(stdout, data, nOutCols, nOutRows, bAscii);
 
-    if (infile != stdin) 
-        pm_close(infile);
+    if (ifP != stdin)
+        pm_close(ifP);
     fflush(stdout);
     pbm_freearray(data, nOutRows);
     free(mdrow);
 
     return 0;
 }
+
+
+
diff --git a/converter/pbm/pbmto4425.c b/converter/pbm/pbmto4425.c
index 1d97ac6a..f18b2e5a 100644
--- a/converter/pbm/pbmto4425.c
+++ b/converter/pbm/pbmto4425.c
@@ -1,178 +1,155 @@
+#include <assert.h>
 #include <string.h>
 
 #include "nstring.h"
+#include "mallocvar.h"
 #include "pbm.h"
 
-static char bit_table[2][3] = {
-{1, 4, 0x10},
-{2, 8, 0x40}
+static char const bit_table[2][3] = {
+    {1, 4, 0x10},
+    {2, 8, 0x40}
 };
 
-static int vmap_width;
-static int vmap_height;
+static unsigned int const vmapWidth  = 132;
+static unsigned int const vmapHeight = 23;
 
-static int xres;
-static int yres;
-
-static char *vmap;
 
 
 static void
-init_map()
-{
-    int x, y;
+initMap(char * const vmap) {
 
+    unsigned int col;
 
-    for(x = 0; x < vmap_width; ++x)
-    {
-        for(y = 0; y < vmap_height; ++y)
-        {
-            vmap[y*(vmap_width) + x] = 0x20;
-        }
+    for (col = 0; col < vmapWidth; ++col) {
+        unsigned int row;
+
+        for (row = 0; row < vmapHeight; ++row)
+            vmap[row * vmapWidth + col] = ' ';
     }
 }
 
 
 
 static void
-set_vmap(x, y)
-    int x, y;
-{
-    int ix, iy;
+setVmap(char *       const vmap,
+        unsigned int const x,
+        unsigned int const y) {
+
+    unsigned int const ix = x/2;
+    unsigned int const iy = y/3;
 
-    ix = x/2;
-    iy = y/3;
+    assert(ix < vmapWidth);
+    assert(iy < vmapHeight);
 
-    vmap[iy*(vmap_width) + ix] |= bit_table[x % 2][y % 3];
+    vmap[iy * vmapWidth + ix] |= bit_table[x % 2][y % 3];
 }
 
 
 
 static void
-fill_map(pbmfp)
-    FILE *pbmfp;
-{
-    bit **pbm_image;
+fillMap(FILE * const pbmFileP,
+        char * const vmap) {
+
+    unsigned int const xres = vmapWidth  * 2;
+    unsigned int const yres = vmapHeight * 3;
+
+    bit ** pbmImage;
     int cols;
     int rows;
-    int x;
-    int y;
-
-    pbm_image = pbm_readpbm(pbmfp, &cols, &rows);
-    for(y = 0; y < rows && y < yres; ++y)
-    {
-        for(x = 0; x < cols && x < xres; ++x)
-        {
-            if(pbm_image[y][x] == PBM_WHITE)
-            {
-                set_vmap(x, y);
-            }
+    unsigned int row;
+
+    pbmImage = pbm_readpbm(pbmFileP, &cols, &rows);
+
+    for (row = 0; row < rows && row < yres; ++row) {
+        unsigned int col;
+
+        for (col = 0; col < cols && col < xres; ++col) {
+            if (pbmImage[row][col] == PBM_WHITE)
+                setVmap(vmap, col, row);
         }
     }
 }
 
 
+
 static void
-print_map()
-{
-    int x, y;
-    int last_byte;
-
-#ifdef BUFFERED
-    char *iobuf;
-    iobuf = (char *)malloc(BUFSIZ);
-    if(iobuf == NULL)
-    {
-        pm_message( "Can't allocate space for I/O buffer.  "
-                    "Using unbuffered I/O...\n" );
-        setbuf(stdout, NULL);
-    }
-    else
-    {
-        setbuf(stdout, iobuf);
-    }
-#endif
-
-    fputs("\033[H\033[J", stdout);	/* clear screen */
-    fputs("\033[?3h", stdout);	/* 132 column mode */
-    fputs("\033)}\016", stdout);	/* mosaic mode */
-
-    for(y = 0; y < vmap_height; ++y)
-    {
-        for(last_byte = vmap_width - 1;
-            last_byte >= 0
-                && vmap[y * vmap_width + last_byte] == 0x20;
-            --last_byte)
+printMap(char * const vmap,
+         FILE * const ofP) {
+
+    unsigned int row;
+
+    fputs("\033[H\033[J", ofP);  /* clear screen */
+    fputs("\033[?3h",     ofP);  /* 132 column mode */
+    fputs("\033)}\016",   ofP);  /* mosaic mode */
+
+    for (row = 0; row < vmapHeight; ++row) {
+        unsigned int endCol;
+            /* Column number just past the non-space data in the row;
+               (i.e. spaces on the right are padding; not data
+            */
+        unsigned int col;
+
+        for (endCol = vmapWidth;
+             endCol > 0 && vmap[row * vmapWidth + (endCol-1)] == ' ';
+             --endCol)
             ;
 
-        for(x = 0; x <= last_byte; ++x)
-        {
-            fputc(vmap[y*(vmap_width) + x], stdout);
-        }
-        fputc('\n', stdout);
+        for (col = 0; col < endCol; ++col)
+            fputc(vmap[row * vmapWidth + col], ofP);
+
+        fputc('\n', ofP);
     }
 
-    fputs("\033(B\017", stdout);
+    fputs("\033(B\017", ofP);
 }
 
 
 
 int
-main(int argc, char * argv[]) {
-    int argn;
-    const char *pbmfile;
-    FILE *pbmfp;
-    const char *usage="[pbmfile]";
-
-    pbm_init( &argc, argv );
-    for(argn = 1;
-        argn < argc && argv[argn][0] == '-' && strlen(argv[argn]) > 1;
-        ++argn)
-    {
-        pm_usage(usage);
-    }
+main(int argc, const char ** argv) {
 
-    if(argn >= argc)
-    {
-        pbmfile = "-";
-    }
-    else if(argc - argn != 1)
-    {
-        pm_usage(usage);
-    }
-    else
-    {
-        pbmfile = argv[argn];
-    }
+    unsigned int argn;
+    const char * inputFileNm;
+    FILE * ifP;
+
+    char * vmap;  /* malloced */
+
+    pm_proginit(&argc, argv);
 
-    if(streq(pbmfile, "-"))
-    {
-        pbmfp = stdin;
+    for (argn = 1;
+         argn < argc && argv[argn][0] == '-' && strlen(argv[argn]) > 1;
+         ++argn) {
+        pm_error("Unrecognized option '%s'", argv[argn]);
     }
-    else
-    {
-        pbmfp = pm_openr( argv[argn] );
+
+    if (argn >= argc) {
+        inputFileNm = "-";
+    } else if(argc - argn != 1) {
+        pm_error("Too many arguments.  At most one argument is allowed: "
+                 "Name of the input file");
+    } else {
+        inputFileNm = argv[argn];
     }
 
-    vmap_width = 132;
-    vmap_height = 23;
+    ifP = pm_openr(inputFileNm);
+
+    assert(vmapWidth < UINT_MAX/vmapHeight);
+
+    MALLOCARRAY(vmap, vmapWidth * vmapHeight);
+    if (!vmap)
+        pm_error("Cannot allocate memory for %u x %u pixels",
+                 vmapWidth, vmapHeight);
 
-    xres = vmap_width * 2;
-    yres = vmap_height * 3;
+    initMap(vmap);
+    fillMap(ifP, vmap);
+    printMap(vmap, stdout);
 
-    vmap = malloc(vmap_width * vmap_height * sizeof(char));
-    if(vmap == NULL)
-	{
-        pm_error( "Cannot allocate memory" );
-	}
+    free(vmap);
 
-    init_map();
-    fill_map(pbmfp);
-    print_map();
     /* If the program failed, it previously aborted with nonzero completion
        code, via various function calls.
     */
-    return 0; 
+    return 0;
 }
 
 
diff --git a/converter/pbm/pbmtolj.c b/converter/pbm/pbmtolj.c
index 3cd76703..1936544f 100644
--- a/converter/pbm/pbmtolj.c
+++ b/converter/pbm/pbmtolj.c
@@ -27,12 +27,14 @@
 ** implied warranty.
 */
 
+#include <stdbool.h>
+#include <assert.h>
+#include <string.h>
+
 #include "pm_c_util.h"
 #include "pbm.h"
 #include "shhopt.h"
 #include "mallocvar.h"
-#include <string.h>
-#include <assert.h>
 
 static char *rowBuffer, *prevRowBuffer, *packBuffer, *deltaBuffer;
 static int rowBufferSize, rowBufferIndex, prevRowBufferIndex;
@@ -43,7 +45,7 @@ static int item, bitsperitem, bitshift;
 
 
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -58,8 +60,8 @@ struct cmdlineInfo {
 
 
 static void
-parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo * const cmdlineP) {
+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.
@@ -91,10 +93,10 @@ parseCommandLine(int argc, char ** argv,
             &compressSpec, 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 */
+    opt.short_allowed = false;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = false;  /* We may have 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 (argc-1 == 0)
@@ -144,7 +146,7 @@ freeBuffers(void) {
 
 
 static void
-putinit(struct cmdlineInfo const cmdline) {
+putinit(struct CmdlineInfo const cmdline) {
     if (!cmdline.noreset) {
         /* Printer reset. */
         printf("\033E");
@@ -352,9 +354,9 @@ findRightmostBlackCol(const bit *    const bitrow,
     for (i = cols - 1; i >= 0 && bitrow[i] == PBM_WHITE; --i);
 
     if (i < 0)
-        *allWhiteP = TRUE;
+        *allWhiteP = true;
     else {
-        *allWhiteP = FALSE;
+        *allWhiteP = false;
         *blackColP = i;
     }
 }
@@ -495,7 +497,7 @@ printRow(void) {
 
 static void
 doPage(FILE *             const ifP,
-       struct cmdlineInfo const cmdline) {
+       struct CmdlineInfo const cmdline) {
 
     bit * bitrow;
     int rows, cols, format, row;
@@ -541,19 +543,19 @@ doPage(FILE *             const ifP,
 
 
 int
-main(int argc, char * argv[]) {
+main(int argc, const char ** argv) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     FILE * ifP;
     int eof;
 
-    pbm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
     ifP = pm_openr(cmdline.inputFilename);
 
-    eof = FALSE;
+    eof = false;
     while (!eof) {
         doPage(ifP, cmdline);
         pbm_nextimage(ifP, &eof);
diff --git a/converter/pbm/pbmtomda.c b/converter/pbm/pbmtomda.c
index 3ad51499..a39cf1a7 100644
--- a/converter/pbm/pbmtomda.c
+++ b/converter/pbm/pbmtomda.c
@@ -1,7 +1,7 @@
 
 /***************************************************************************
 
-    PBMTOMDA: Convert portable bitmap to Microdesign area
+    PBMTOMDA: Convert PBM to Microdesign area
     Copyright (C) 1999,2004 John Elliott <jce@seasip.demon.co.uk>
 
     This program is free software; you can redistribute it and/or modify
@@ -20,31 +20,80 @@
 
 ******************************************************************************/
 
+#include <stdbool.h>
+#include <assert.h>
 #include <stdio.h>
 #include <string.h>
 
 #include "pbm.h"
 #include "mallocvar.h"
+#include "shhopt.h"
+
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char * inputFileNm;
+    unsigned int dscale;
+    unsigned int invert;
+};
+
+
+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 as as the argv array.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;
+        /* Instructions to pm_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,   "dscale", OPT_FLAG,  NULL, &cmdlineP->dscale,   0);
+    OPTENT3(0,   "invert", OPT_FLAG,  NULL, &cmdlineP->invert,   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 (argc-1 < 1)
+        cmdlineP->inputFileNm = "-";
+    else if (argc-1 == 1)
+        cmdlineP->inputFileNm = argv[1];
+    else
+        pm_error("Program takes at most one argument:  input file name");
+
+    free(option_def);
+}
+
+
 
-/* I'm being somewhat conservative in the PBM -> MDA translation. I output 
+/* I'm being somewhat conservative in the PBM -> MDA translation. I output
  * only the MD2 format and don't allow RLE over the ends of lines.
  */
 
-typedef unsigned char mdbyte;
-
-static FILE *infile;
-static mdbyte header[128];
-static int bInvert = 0;
-static int bScale  = 0;
+typedef unsigned char Mdbyte;
 
 /* Encode 8 pixels as a byte */
 
-static mdbyte 
-encode(bit ** const bits, int const row, int const col)
-{
+static Mdbyte
+encode(bit ** const bits,
+       int    const row,
+       int    const col) {
+
     int n;
     int mask;
-    mdbyte b;
+    Mdbyte b;
 
     mask = 0x80;   /* initial value */
     b = 0;  /* initial value */
@@ -56,131 +105,109 @@ encode(bit ** const bits, int const row, int const col)
     return b;
 }
 
-/* Translate a pbm to MD2 format, one row at a time */
 
-static void 
-do_translation(bit ** const bits, 
-               int    const nOutCols, 
-               int    const nOutRows,
-               int    const nInRows)
-{
-    int row;
-    mdbyte *mdrow;  /* malloc'ed */
+static void
+doTranslation(bit **       const bits,
+              unsigned int const nOutCols,
+              unsigned int const nOutRows,
+              unsigned int const nInRows,
+              bool         const mustInvert,
+              bool         const mustScale) {
+/*----------------------------------------------------------------------------
+  Translate a pbm to MD2 format, one row at a time
+-----------------------------------------------------------------------------*/
+    unsigned int const step = mustScale ? 2 : 1;
 
-    int const step = bScale ? 2 : 1;
+    unsigned int row;
+    Mdbyte * mdrow;  /* malloc'ed */
 
     MALLOCARRAY(mdrow, nOutCols);
 
     if (mdrow == NULL)
-        pm_error("Not enough memory for conversion.");
+        pm_error("Unable to allocate memory for %u columns", nOutCols);
 
-    for (row = 0; row < nOutRows; row+=step)
-    {
-        int col;
-        int x1;
+    for (row = 0; row < nOutRows; row += step) {
+        unsigned int col;
 
         /* Encode image into non-compressed bitmap */
         for (col = 0; col < nOutCols; ++col) {
-            mdbyte b;
+            Mdbyte b;
 
             if (row < nInRows)
-                b = encode(bits, row, col*8);
+                b = encode(bits, row, col * 8);
             else
                 b = 0xff;  /* All black */
 
-            mdrow[col] = bInvert ? b : ~b;
+            mdrow[col] = mustInvert ? b : ~b;
         }
 
         /* Encoded. Now RLE it */
-        for (col = 0; col < nOutCols; )
-        {
-            mdbyte const b = mdrow[col];
+        for (col = 0; col < nOutCols; ) {
+            Mdbyte const b = mdrow[col];
 
-            if (b != 0xFF && b != 0) /* Normal byte */
-            {
+            if (b != 0xFF && b != 0) {
+                /* Normal byte */
                 putchar(b);
                 ++col;
-            }
-            else    /* RLE a run of 0s or 0xFFs */
-            {
-                for (x1 = col; x1 < nOutCols; x1++)
-                {
+            } else {
+                /* RLE a run of 0s or 0xFFs */
+
+                unsigned int x1;
+
+                for (x1 = col; x1 < nOutCols; ++x1) {
                     if (mdrow[x1] != b) break;
+                    assert(x1 >= col);
                     if (x1 - col > 256) break;
                 }
+                assert(x1 >= col);
                 x1 -= col;    /* x1 = no. of repeats */
                 if (x1 == 256) x1 = 0;
                 putchar(b);
                 putchar(x1);
-                col += x1;        
-            }   
+                col += x1;
+            }
         }
     }
     free(mdrow);
 }
 
 
-static void usage(char *s)
-{        
-    printf("pbmtomda v1.01, Copyright (C) 1999,2004 John Elliott <jce@seasip.demon.co.uk>\n"
-         "This program is redistributable under the terms of the GNU General Public\n"
-                 "License, version 2 or later.\n\n"
-                 "Usage: %s [ -d ] [ -i ] [ -- ] [ infile ]\n\n"
-                 "-d: Halve height (to compensate for the PCW aspect ratio)\n"
-                 "-i: Invert colors\n"
-                 "--: No more options (use if filename begins with a dash)\n",
-        s);
 
-    exit(0);
-}
+int
+main(int argc, const char ** argv) {
 
-int main(int argc, char **argv)
-{
-    int nOutRowsUnrounded;  /* Before rounding up to multiple of 4 */
-    int nOutCols, nOutRows;
+    const char * const headerValue = ".MDAMicroDesignPCWv1.00\r\npbm2mda\r\n";
+
+    struct CmdlineInfo cmdline;
+    FILE * ifP;
+    unsigned int nOutRowsUnrounded;  /* Before rounding up to multiple of 4 */
+    unsigned int nOutCols, nOutRows;
     int nInCols, nInRows;
-    bit **bits;
+    bit ** bits;
+    Mdbyte header[128];
     int rc;
 
-    int n, optstop = 0;
-    char *fname = NULL;
+    pm_proginit(&argc, argv);
 
-    pbm_init(&argc, argv);
+    parseCommandLine(argc, argv, &cmdline);
 
     /* Output v2-format MDA images. Simulate MDA header...
-     * 2004-01-11: Hmm. Apparently some (but not all) MDA-reading 
-     * programs insist on the program identifier being exactly 
+     * 2004-01-11: Hmm. Apparently some (but not all) MDA-reading
+     * programs insist on the program identifier being exactly
      * 'MicroDesignPCW'. The spec does not make this clear. */
-    strcpy((char*) header, ".MDAMicroDesignPCWv1.00\r\npbm2mda\r\n");
-
-    for (n = 1; n < argc; n++)
-    {
-        if (argv[n][0] == '-' && !optstop)
-        {   
-            if (argv[n][1] == 'd' || argv[n][1] == 'D') bScale = 1;
-            if (argv[n][1] == 'i' || argv[n][1] == 'I') bInvert = 1;
-            if (argv[n][1] == 'h' || argv[n][1] == 'H') usage(argv[0]);
-            if (argv[n][1] == '-' && argv[n][2] == 0 && !fname)     /* "--" */
-            {
-                optstop = 1;
-            }
-            if (argv[n][1] == '-' && (argv[n][2] == 'h' || argv[n][2] == 'H')) usage(argv[0]);
-        }
-        else if (argv[n][0] && !fname)  /* Filename */
-        {
-            fname = argv[n];
-        }
-    }
+    memcpy(header + 0, headerValue, strlen(headerValue));
+    memset(header + strlen(headerValue),
+           0x00,
+           sizeof(header)-strlen(headerValue));
 
-    if (fname) infile = pm_openr(fname);
-    else       infile = stdin;
+    ifP = pm_openr(cmdline.inputFileNm);
 
-    bits = pbm_readpbm(infile, &nInCols, &nInRows);
-    
-    nOutRowsUnrounded = bScale ? nInRows/2 : nInRows;
+    bits = pbm_readpbm(ifP, &nInCols, &nInRows);
+
+    nOutRowsUnrounded = cmdline.dscale ? nInRows/2 : nInRows;
 
     nOutRows = ((nOutRowsUnrounded + 3) / 4) * 4;
-        /* MDA wants rows a multiple of 4 */   
+        /* MDA wants rows a multiple of 4 */
     nOutCols = nInCols / 8;
 
     rc = fwrite(header, 1, 128, stdout);
@@ -191,11 +218,15 @@ int main(int argc, char **argv)
     pm_writelittleshort(stdout, nOutRows);
     pm_writelittleshort(stdout, nOutCols);
 
-    do_translation(bits, nOutCols, nOutRows, nInRows);
+    doTranslation(bits, nOutCols, nOutRows, nInRows,
+                  !!cmdline.invert, !!cmdline.dscale);
 
-    pm_close(infile);
+    pm_close(ifP);
     fflush(stdout);
     pbm_freearray(bits, nInRows);
-    
+
     return 0;
 }
+
+
+
diff --git a/converter/pbm/pbmtoppa/pbmtoppa.c b/converter/pbm/pbmtoppa/pbmtoppa.c
index ff4a599e..47e64ecc 100644
--- a/converter/pbm/pbmtoppa/pbmtoppa.c
+++ b/converter/pbm/pbmtoppa/pbmtoppa.c
@@ -14,6 +14,8 @@
 #include <unistd.h>
 
 #include "pbm.h"
+#include "nstring.h"
+
 #include "ppa.h"
 #include "ppapbm.h"
 #include "cutswath.h"
@@ -40,8 +42,8 @@ int Pwidth;     /* width in bytes */
 
 ppa_stat printer;
 
-static int 
-print_pbm(FILE * const in) {
+static int
+printPbm(FILE * const ifP) {
 
     char line[1024];
     pbm_stat pbm;
@@ -51,8 +53,8 @@ print_pbm(FILE * const in) {
 
     ppa_init_job(&printer);
 
-    while(make_pbm_stat(&pbm, in)) {
-        if (pbm.width != Width || pbm.height != Height) 
+    while(make_pbm_stat(&pbm, ifP)) {
+        if (pbm.width != Width || pbm.height != Height)
             pm_error("print_pbm(): Input image is not the size "
                     "of a page for Page %d.  "
                     "The input is %dW x %dH, "
@@ -123,7 +125,7 @@ print_pbm(FILE * const in) {
 
         /* eat any remaining whitespace */
         if(pbm.version==P1)
-            fgets (line, 1024, in);
+            fgets (line, 1024, ifP);
 
         ++numpages;
     }
@@ -141,11 +143,13 @@ print_pbm(FILE * const in) {
 
 
 
-static void 
-set_printer_specific_defaults()
-{
-    switch(printer.version)
-    {
+static void
+setPrinterSpecificDefaults() {
+
+    switch(printer.version) {
+    case HP710:
+        pm_error("Don't know how to drive HP 710");
+        break;
     case HP720:
         printer.marg_diff     = HP720_MARG_DIFF;
         printer.bufsize       = HP720_BUFSIZE;
@@ -179,14 +183,12 @@ set_printer_specific_defaults()
         printer.right_margin  = HP1000_RIGHT_MARGIN;
         printer.bottom_margin = HP1000_BOTTOM_MARGIN;
         break;
-    default:
-        pm_error("set_printer_defaults(): unknown printer version");
     }
 }
 
 
 
-static void 
+static void
 show_usage(const char* const prog)
 {
     printf("usage: %s [ options ] [ <infile> [ <outfile> ] ]\n\n",prog);
@@ -220,9 +222,9 @@ show_usage(const char* const prog)
 
 
 
-static void 
-parm_version(char* arg)
-{
+static void
+parmVersion(char * const arg) {
+
     if(!strcasecmp(arg,"hp720") || !strcmp(arg,"720"))
         printer.version=HP720;
     else if(!strcasecmp(arg,"hp820") || !strcmp(arg,"820"))
@@ -231,39 +233,39 @@ parm_version(char* arg)
         printer.version=HP1000;
     else
         pm_error("parm_version(): unknown printer version '%s'",arg);
-    set_printer_specific_defaults();
+    setPrinterSpecificDefaults();
 }
 
 
 
-static void 
-parm_iversion(int arg)
-{
+static void
+parmIversion(int const arg) {
+
     switch(arg)
     {
     case 720:
-        printer.version=HP720;
+        printer.version = HP720;
         break;
     case 820:
-        printer.version=HP820;
+        printer.version = HP820;
         break;
     case 1000:
-        printer.version=HP1000;
+        printer.version = HP1000;
         break;
     default:
-        pm_error("parm_iversion(): unknown printer version '%d'", arg);
+        pm_error("parmIversion(): unknown printer version '%d'", arg);
     }
-    set_printer_specific_defaults();
+    setPrinterSpecificDefaults();
 }
 
 
 
-static void 
-dump_config()
-{
+static void
+dumpConfig() {
+
     printf("version:  ");
-    switch(printer.version)
-    {
+
+    switch(printer.version) {
     case HP710:  printf("HP710\n");  break;
     case HP720:  printf("HP720\n");  break;
     case HP820:  printf("HP820\n");  break;
@@ -278,90 +280,88 @@ dump_config()
 
 
 
-static void 
-read_config_file(const char* const fname)
-{
-    FILE* cfgfile=fopen(fname,"r");
-    char line[1024],key[14],buf[10];
-    int len,value,lineno=1;
+static void
+readConfigFile(const char * const fname) {
+
+    FILE * cfgFileP;
+    char line[1024];
+    char key[14];
+    char buf[10];
+    int len;
+    int value;
+    int lineno;
 
-    if(!cfgfile)
+    cfgFileP = fopen(fname, "r");
+
+    lineno = 1;  /* initial value */
+
+    if (!cfgFileP)
         pm_error("read_config_file(): couldn't open file '%s'", fname);
 
-    while(fgets(line,1024,cfgfile))
-    {
-        if(strchr(line,'#'))
-            *strchr(line,'#')=0;
-        switch(sscanf(line,"%13s%9s",key,buf))
-        {
+    while (fgets(line, 1024, cfgFileP)) {
+        if (strchr(line, '#'))
+            *strchr(line, '#')=0;
+        switch(sscanf(line, "%13s%9s", key, buf)) {
         case 2:
-            value=atoi(buf);
-            len=strlen(key);
-            if(!strncmp(key,"version",len))
-                parm_iversion(value);
-            else if(!strncmp(key,"xoffset",len))
-                printer.x_offset=value;
-            else if(!strncmp(key,"yoffset",len))
-                printer.y_offset=value;
-            else if(!strncmp(key,"topmargin",len))
-                printer.top_margin=value;
-            else if(!strncmp(key,"leftmargin",len))
-                printer.left_margin=value;
-            else if(!strncmp(key,"rightmargin",len))
-                printer.right_margin=value;
-            else if(!strncmp(key,"bottommargin",len))
-                printer.bottom_margin=value;
-            else if(!strncmp(key,"papersize",len))
-            {
-                if(!strcmp(buf,"us"))
-                {
-                    Width = USWIDTH;
+            value = atoi(buf);
+            len   = strlen(key);
+            if (strneq(key, "version",           len))
+                parmIversion(value);
+            else if (strneq(key, "xoffset",      len))
+                printer.x_offset = value;
+            else if (strneq(key, "yoffset",      len))
+                printer.y_offset = value;
+            else if(strneq(key,  "topmargin",    len))
+                printer.top_margin = value;
+            else if(strneq(key,  "leftmargin",   len))
+                printer.left_margin = value;
+            else if(strneq(key,  "rightmargin",  len))
+                printer.right_margin = value;
+            else if(strneq(key,  "bottommargin", len))
+                printer.bottom_margin = value;
+            else if(strneq(key,  "papersize"   , len)) {
+                if(streq(buf, "us")) {
+                    Width  = USWIDTH;
                     Height = USHEIGHT;
-                }
-                else if(!strcmp(buf,"a4"))
-                {
-                    Width = A4WIDTH;
+                } else if (streq(buf, "a4")) {
+                    Width  = A4WIDTH;
                     Height = A4HEIGHT;
-                }
-                else
+                } else
                     pm_error("read_config_file(): unknown paper size %s", buf);
-            }
-            else if(!strcmp(key,"dump"))
-                dump_config();
-            else 
+            } else if(!strcmp(key,"dump"))
+                dumpConfig();
+            else
                 pm_error("read_config_file(): unrecognized parameter '%s' "
                          "(line %d)", key, lineno);
         case EOF:
-        case 0: 
+        case 0:
             break;
         default:
             pm_error("read_config_file(): error parsing config file "
                      "(line %d)", lineno);
         }
-        lineno++;
+        ++lineno;
     }
 
-    if(feof(cfgfile))
-    {
-        fclose(cfgfile);
-        return;
-    }
-
-    pm_error("read_config_file(): error parsing config file");
+    if (feof(cfgFileP)) {
+        fclose(cfgFileP);
+    } else
+        pm_error("read_config_file(): error parsing config file");
 }
 
 
 
-const char* const defaultcfgfile="/etc/pbmtoppa.conf";
+const char * const defaultCfgFileNm = "/etc/pbmtoppa.conf";
 
 
 
-int 
+int
 main(int argc, char *argv[]) {
 
     int argn;
     int got_in=0, got_out=0, do_continue=1;
-    FILE *in=stdin, *out=stdout;
+    FILE * ifP;
+    FILE * ofP;
     struct stat tmpstat;
 
     pbm_init(&argc, argv);
@@ -374,12 +374,15 @@ main(int argc, char *argv[]) {
     printer.right_margin  = DEFAULT_RIGHT_MARGIN;
     printer.bottom_margin = DEFAULT_BOTTOM_MARGIN;
     printer.DPI           = DEFAULT_DPI;
-    Width = USWIDTH;
+    Width  = USWIDTH;
     Height = USHEIGHT;
-    set_printer_specific_defaults();
+    setPrinterSpecificDefaults();
+
+    if (!stat(defaultCfgFileNm, &tmpstat))
+        readConfigFile(defaultCfgFileNm);
 
-    if(!stat(defaultcfgfile,&tmpstat))
-        read_config_file(defaultcfgfile);
+    ifP = stdin;  /* initial value */
+    ofP = stdout;  /* initial value */
 
     for(argn=1; argn<argc; argn++)
     {
@@ -389,12 +392,12 @@ main(int argc, char *argv[]) {
             return 0;
         }
         else if(!strcmp(argv[argn],"-d"))
-            dump_config();
+            dumpConfig();
         else if(argn+1<argc)
         {
             do_continue=1;
             if(!strcmp(argv[argn],"-v"))
-                parm_version(argv[++argn]);
+                parmVersion(argv[++argn]);
             else if(!strcmp(argv[argn],"-x"))
                 printer.x_offset+=atoi(argv[++argn]);
             else if(!strcmp(argv[argn],"-y"))
@@ -426,7 +429,7 @@ main(int argc, char *argv[]) {
                     pm_error("unknown paper size %s",argv[argn]);
             }
             else if(!strcmp(argv[argn],"-f"))
-                read_config_file(argv[++argn]);
+                readConfigFile(argv[++argn]);
             else do_continue=0;
             if(do_continue) continue;
         }
@@ -434,18 +437,18 @@ main(int argc, char *argv[]) {
         if(!got_in)
         {
             if (strcmp (argv[argn], "-") == 0)
-                in = stdin;
-            else if ((in = fopen (argv[argn], "rb")) == NULL)
-                pm_error("main(): couldn't open file '%s'", 
+                ifP = stdin;
+            else if ((ifP = fopen (argv[argn], "rb")) == NULL)
+                pm_error("main(): couldn't open file '%s'",
                          argv[argn]);
             got_in=1;
         }
         else if(!got_out)
         {
             if (strcmp (argv[argn], "-") == 0)
-                out = stdout;
-            else if ((out = fopen (argv[argn], "wb")) == NULL)
-                pm_error("main(): couldn't open file '%s'", 
+                ofP = stdout;
+            else if ((ofP = fopen (argv[argn], "wb")) == NULL)
+                pm_error("main(): couldn't open file '%s'",
                          argv[argn]);
             got_out=1;
         }
@@ -453,9 +456,11 @@ main(int argc, char *argv[]) {
             pm_error("main(): unrecognized parameter '%s'", argv[argn]);
     }
 
-    Pwidth=(Width+7)/8;
-    printer.fptr=out;
+    Pwidth = (Width+7)/8;
+    printer.fptr = ofP;
 
-    return print_pbm (in);
+    return printPbm(ifP);
 }
 
+
+
diff --git a/converter/pbm/pbmtoxbm.c b/converter/pbm/pbmtoxbm.c
index 1a003189..4bd33dd8 100644
--- a/converter/pbm/pbmtoxbm.c
+++ b/converter/pbm/pbmtoxbm.c
@@ -10,10 +10,10 @@
 ** implied warranty.
 */
 
-/* 2006.10 (afu)   
+/* 2006.10 (afu)
    Changed bitrow from plain to raw, read function from pbm_readpbmrow() to
    pbm_readpbmrow_packed().  Retired bitwise transformation functions.
- 
+
    Output function putitem rewritten to handle both X10 and X11.
 
    Added -name option.  There is no check for the string thus given.
@@ -35,7 +35,7 @@
 #include "nstring.h"
 
 
-enum xbmVersion { X10, X11 };
+enum XbmVersion { X10, X11 };
 
 struct CmdlineInfo {
     /* All the information the user supplied in the command line,
@@ -43,16 +43,16 @@ struct CmdlineInfo {
     */
     const char *    inputFileName;
     const char *    name;
-    enum xbmVersion xbmVersion;
+    enum XbmVersion xbmVersion;
 };
 
 static void
-parseCommandLine(int                 argc, 
+parseCommandLine(int                 argc,
                  const char **       argv,
                  struct CmdlineInfo *cmdlineP ) {
 /*----------------------------------------------------------------------------
    Parse program command line described in Unix standard form by argc
-   and argv.  Return the information in the options as *cmdlineP.  
+   and argv.  Return the information in the options as *cmdlineP.
 
    If command line is internally inconsistent (invalid options, etc.),
    issue error message to stderr and abort program.
@@ -96,19 +96,19 @@ parseCommandLine(int                 argc,
                 pm_error("Image name '%s' contains invalid character (%c).",
                          cmdlineP->name, cmdlineP->name[i]);
     }
-    
+
     if (x10 && x11)
         pm_error("You can't specify both -x10 and -x11");
     else if (x10)
         cmdlineP->xbmVersion = X10;
-    else 
+    else
         cmdlineP->xbmVersion = X11;
-        
-    if (argc-1 < 1) 
+
+    if (argc-1 < 1)
         cmdlineP->inputFileName = "-";
     else {
         cmdlineP->inputFileName = argv[1];
-        
+
         if (argc-1 > 1)
             pm_error("Program takes zero or one argument (filename).  You "
                      "specified %u", argc-1);
@@ -141,22 +141,22 @@ generateName(char          const filenameArg[],
         /* indices into the input and output buffers */
 
         /* Start just after the rightmost slash, or at beginning if no slash */
-        if (strrchr(filenameArg, '/') == 0) 
+        if (strrchr(filenameArg, '/') == 0)
             argIndex = 0;
         else argIndex = strrchr(filenameArg, '/') - filenameArg + 1;
 
-        if (filenameArg[argIndex] == '\0') 
+        if (filenameArg[argIndex] == '\0')
             *nameP = strdup("noname");
         else {
             char * name;
             nameIndex = 0;  /* Start at beginning of name buffer */
 
             name = malloc(strlen(filenameArg));
-    
-            while (filenameArg[argIndex] != '\0' 
+
+            while (filenameArg[argIndex] != '\0'
                    && filenameArg[argIndex] != '.') {
                 const char filenameChar = filenameArg[argIndex++];
-                name[nameIndex++] = 
+                name[nameIndex++] =
                     ISALNUM(filenameChar) ? filenameChar : '_';
             }
             name[nameIndex] = '\0';
@@ -167,37 +167,46 @@ generateName(char          const filenameArg[],
 
 
 
-static unsigned short int itemBuff[22];
-static int itemCnt;    /* takes values 0 to 15 (x11) or 21 (x10) */
-static enum xbmVersion itemVersion;
+typedef struct {
+    unsigned short int buff[22];
+    int cnt;    /* takes values 0 to 15 (x11) or 21 (x10) */
+    enum XbmVersion version;
+} ItemWriter;
+
+static ItemWriter itemWriter;
 
 
 
 static void
 putitemX10(unsigned char const item) {
 
-    if (itemCnt == 22) {
+    if (itemWriter.cnt == 22) {
         /* Buffer is full.  Write out one line. */
         int rc;
         rc = printf(" 0x%02x%02x,0x%02x%02x,0x%02x%02x,0x%02x%02x,"
                     "0x%02x%02x,0x%02x%02x,0x%02x%02x,0x%02x%02x,"
                     "0x%02x%02x,0x%02x%02x,0x%02x%02x,\n",
-                    itemBuff[ 1], itemBuff[ 0], itemBuff[ 3], itemBuff[ 2],
-                    itemBuff[ 5], itemBuff[ 4], itemBuff[ 7], itemBuff[ 6],
-                    itemBuff[ 9], itemBuff[ 8], itemBuff[11], itemBuff[10],
-                    itemBuff[13], itemBuff[12], itemBuff[15], itemBuff[14],
-                    itemBuff[17], itemBuff[16], itemBuff[19], itemBuff[18],
-                    itemBuff[21], itemBuff[20]
+                    itemWriter.buff[ 1], itemWriter.buff[ 0],
+                    itemWriter.buff[ 3], itemWriter.buff[ 2],
+                    itemWriter.buff[ 5], itemWriter.buff[ 4],
+                    itemWriter.buff[ 7], itemWriter.buff[ 6],
+                    itemWriter.buff[ 9], itemWriter.buff[ 8],
+                    itemWriter.buff[11], itemWriter.buff[10],
+                    itemWriter.buff[13], itemWriter.buff[12],
+                    itemWriter.buff[15], itemWriter.buff[14],
+                    itemWriter.buff[17], itemWriter.buff[16],
+                    itemWriter.buff[19], itemWriter.buff[18],
+                    itemWriter.buff[21], itemWriter.buff[20]
             );
 
-        if (rc < 0)        
+        if (rc < 0)
             pm_error("Error writing X10 bitmap raster item.  "
                      "printf() failed with errno %d (%s)",
                      errno, strerror(errno));
-        
-        itemCnt = 0;
+
+        itemWriter.cnt = 0;
     }
-    itemBuff[itemCnt++] = bitreverse[item];
+    itemWriter.buff[itemWriter.cnt++] = bitreverse[item];
 }
 
 
@@ -205,26 +214,30 @@ putitemX10(unsigned char const item) {
 static void
 putitemX11(unsigned char const item) {
 
-    if (itemCnt == 15 ) {
+    if (itemWriter.cnt == 15 ) {
         /* Buffer is full.  Write out one line. */
         int rc;
         rc = printf(" 0x%02x,0x%02x,0x%02x,0x%02x,"
                     "0x%02x,0x%02x,0x%02x,0x%02x,"
                     "0x%02x,0x%02x,0x%02x,0x%02x,"
                     "0x%02x,0x%02x,0x%02x,\n",
-                    itemBuff[0], itemBuff[1], itemBuff[2], itemBuff[3],
-                    itemBuff[4], itemBuff[5], itemBuff[6], itemBuff[7],
-                    itemBuff[8], itemBuff[9], itemBuff[10],itemBuff[11],
-                    itemBuff[12],itemBuff[13],itemBuff[14]
+                    itemWriter.buff[ 0], itemWriter.buff[ 1],
+                    itemWriter.buff[ 2], itemWriter.buff[ 3],
+                    itemWriter.buff[ 4], itemWriter.buff[ 5],
+                    itemWriter.buff[ 6], itemWriter.buff[ 7],
+                    itemWriter.buff[ 8], itemWriter.buff[ 9],
+                    itemWriter.buff[10], itemWriter.buff[11],
+                    itemWriter.buff[12], itemWriter.buff[13],
+                    itemWriter.buff[14]
             );
-        if (rc < 0)        
+        if (rc < 0)
             pm_error("Error writing X11 bitmap raster item.  "
                      "printf() failed with errno %d (%s)",
                      errno, strerror(errno));
-        
-        itemCnt = 0;
+
+        itemWriter.cnt = 0;
     }
-    itemBuff[itemCnt++] = bitreverse[item];
+    itemWriter.buff[itemWriter.cnt++] = bitreverse[item];
 }
 
 
@@ -232,7 +245,7 @@ putitemX11(unsigned char const item) {
 static void
 putitem(unsigned char const item) {
 
-    switch (itemVersion) {
+    switch (itemWriter.version) {
     case X10: putitemX10(item); break;
     case X11: putitemX11(item); break;
     }
@@ -245,19 +258,19 @@ puttermX10(void) {
 
     unsigned int i;
 
-    assert(itemCnt % 2 == 0);
+    assert(itemWriter.cnt % 2 == 0);
 
-    for (i = 0; i < itemCnt; i += 2) {
+    for (i = 0; i < itemWriter.cnt; i += 2) {
         int rc;
 
-        assert(i + 1 < itemCnt);
+        assert(i + 1 < itemWriter.cnt);
 
         rc = printf("%s0x%02x%02x%s",
                     (i == 0) ? " " : "",
-                    itemBuff[i+1],
-                    itemBuff[i], 
-                    (i + 2 >= itemCnt) ? "" : ",");
-        if (rc < 0)        
+                    itemWriter.buff[i+1],
+                    itemWriter.buff[i],
+                    (i + 2 >= itemWriter.cnt) ? "" : ",");
+        if (rc < 0)
             pm_error("Error writing Item %u at end of X10 bitmap raster.  "
                      "printf() failed with errno %d (%s)",
                      i, errno, strerror(errno));
@@ -271,15 +284,15 @@ puttermX11(void) {
 
     unsigned int i;
 
-    for (i = 0; i < itemCnt; ++i) {
+    for (i = 0; i < itemWriter.cnt; ++i) {
         int rc;
 
         rc = printf("%s0x%02x%s",
                     (i == 0)  ? " " : "",
-                    itemBuff[i],
-                    (i + 1 >= itemCnt) ? "" : ",");
+                    itemWriter.buff[i],
+                    (i + 1 >= itemWriter.cnt) ? "" : ",");
 
-        if (rc < 0)        
+        if (rc < 0)
             pm_error("Error writing Item %u at end of X11 bitmap raster.  "
                      "printf() failed with errno %d (%s)",
                      i, errno, strerror(errno));
@@ -289,10 +302,10 @@ puttermX11(void) {
 
 
 static void
-putinit(enum xbmVersion const xbmVersion) {
+putinit(enum XbmVersion const xbmVersion) {
 
-    itemCnt = 0;
-    itemVersion = xbmVersion;
+    itemWriter.cnt = 0;
+    itemWriter.version = xbmVersion;
 }
 
 
@@ -300,7 +313,7 @@ putinit(enum xbmVersion const xbmVersion) {
 static void
 putterm(void) {
 
-    switch (itemVersion) {
+    switch (itemWriter.version) {
     case X10: puttermX10(); break;
     case X11: puttermX11(); break;
     }
@@ -310,7 +323,7 @@ putterm(void) {
 
         rc = printf("};\n");
 
-        if (rc < 0)        
+        if (rc < 0)
             pm_error("Error writing end of X11 bitmap raster.  "
                      "printf() failed with errno %d (%s)",
                      errno, strerror(errno));
@@ -320,7 +333,7 @@ putterm(void) {
 
 
 static void
-writeXbmHeader(enum xbmVersion const xbmVersion,
+writeXbmHeader(enum XbmVersion const xbmVersion,
                const char *    const name,
                unsigned int    const width,
                unsigned int    const height,
@@ -341,11 +354,11 @@ convertRaster(FILE *          const ifP,
               unsigned int    const rows,
               int             const format,
               FILE *          const ofP,
-              enum xbmVersion const xbmVersion) {
-              
-    unsigned int const bitsPerUnit = xbmVersion == X10 ? 16 : 8;   
+              enum XbmVersion const xbmVersion) {
+
+    unsigned int const bitsPerUnit = xbmVersion == X10 ? 16 : 8;
     unsigned int const padright = ROUNDUP(cols, bitsPerUnit) - cols;
-        /* Amount of padding to round cols up to the nearest multiple of 
+        /* Amount of padding to round cols up to the nearest multiple of
            8 (if x11) or 16 (if x10).
         */
     unsigned int const bitrowBytes = (cols + padright) / 8;
@@ -360,7 +373,7 @@ convertRaster(FILE *          const ifP,
     putinit(xbmVersion);
 
     bitrow = pbm_allocrow_packed(cols + padright);
-    
+
     for (row = 0; row < rows; ++row) {
         unsigned int i;
 
@@ -386,7 +399,7 @@ int
 main(int           argc,
      const char ** argv) {
 
-    struct CmdlineInfo cmdline; 
+    struct CmdlineInfo cmdline;
     FILE * ifP;
     int rows, cols, format;
     const char * name;
@@ -394,15 +407,15 @@ main(int           argc,
     pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
-    if (cmdline.name == NULL) 
+    if (cmdline.name == NULL)
         generateName(cmdline.inputFileName, &name);
     else
         name = strdup(cmdline.name);
 
     ifP = pm_openr(cmdline.inputFileName);
-    
+
     pbm_readpbminit(ifP, &cols, &rows, &format);
-    
+
     writeXbmHeader(cmdline.xbmVersion, name, cols, rows, stdout);
 
     convertRaster(ifP, cols, rows, format, stdout, cmdline.xbmVersion);
diff --git a/converter/pbm/pktopbm.c b/converter/pbm/pktopbm.c
index 712f339f..49e15c49 100644
--- a/converter/pbm/pktopbm.c
+++ b/converter/pbm/pktopbm.c
@@ -7,159 +7,279 @@
      * fix bitmap y placement of dynamically packed char
      * skip char early if no output file allocated
      - added debug output
-  
+
   compile with: cc -lpbm -o pktopbm pktopbm.c
   */
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <string.h>
 
 #include "pm_c_util.h"
 #include "nstring.h"
+#include "mallocvar.h"
+#include "shhopt.h"
 #include "pbm.h"
 
 #define NAMELENGTH 80
 #define MAXROWWIDTH 3200
 #define MAXPKCHAR 256
 
-typedef int integer ;
-typedef unsigned char quarterword ;
-typedef char boolean ;
-typedef quarterword eightbits ;
-
-static FILE *pkfile ;
-static char pkname[NAMELENGTH+1] ;
-static integer pktopbm_pkloc = 0;
-static char *filename[MAXPKCHAR] ;
-static bit **bitmap = NULL ;
-static integer dynf ;
-static eightbits inputbyte ;
-static eightbits bitweight ;
-static integer repeatcount ;
-static integer flagbyte ;
-static integer debug=0;
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char * inputFileNm;
+    unsigned int outputFileCt;
+        /* The number of output files */
+    const char * outputFileNm[MAXPKCHAR];
+        /* The output file name, in order */
+    unsigned int character;
+    unsigned int xSpec;
+    unsigned int x;
+    unsigned int ySpec;
+    unsigned int y;
+    unsigned int debug;
+};
+
 
-#define dprintf(s,d) if (debug) printf(s,d)
-#define dprintf0(s) if (debug) printf(s)
 
-/* add a suffix to a filename in an allocated space */
 static void
-pktopbm_add_suffix(char *       const name, 
-                   const char * const suffix) {
-
-    char * const slash = strrchr(name, '/');
-    char * const dot   = strrchr(name, '.');
-    
-    if ((dot && slash ? dot < slash : !dot) && !streq(name, "-"))
-        strcat(name, suffix);
+parseCommandLine(int argc, const char ** argv,
+                 struct CmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   Note that the file spec strings we return are stored in the storage that
+   was passed to us as the argv array.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;
+        /* Instructions to pm_optParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+    unsigned int characterSpec;
+    unsigned int firstOutputArgNm;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "character",   OPT_UINT, &cmdlineP->character,
+            &characterSpec, 0);
+    OPTENT3(0, "x",   OPT_UINT, &cmdlineP->x,
+            &cmdlineP->xSpec, 0);
+    OPTENT3(0, "X",   OPT_UINT, &cmdlineP->x,
+            &cmdlineP->xSpec, 0);
+    OPTENT3(0, "y",   OPT_UINT, &cmdlineP->y,
+            &cmdlineP->ySpec, 0);
+    OPTENT3(0, "Y",   OPT_UINT, &cmdlineP->y,
+            &cmdlineP->ySpec, 0);
+    OPTENT3(0, "debug",   OPT_UINT, NULL,
+            &cmdlineP->debug, 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 */
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (characterSpec) {
+        if (cmdlineP->character >= MAXPKCHAR)
+            pm_error("Character number (-character) must be in range 0 to %u",
+                     MAXPKCHAR-1);
+    } else
+        cmdlineP->character = 0;
+
+    if (argc-1 < 1) {
+        cmdlineP->inputFileNm = "-";
+        firstOutputArgNm = 1;
+    } else {
+        cmdlineP->inputFileNm = argv[1];
+        firstOutputArgNm = 2;
+    }
+
+    cmdlineP->outputFileCt = 0;  /* initial value */
+    {
+        unsigned int argn;
+        bool stdoutUsed;
+        for (argn = firstOutputArgNm, stdoutUsed = false;
+             argn < argc;
+             ++argn) {
+            if (cmdlineP->outputFileCt >= MAXPKCHAR)
+                pm_error("You may not specify more than %u output files.",
+                         MAXPKCHAR);
+            cmdlineP->outputFileNm[cmdlineP->outputFileCt++] = argv[argn];
+            if (streq(argv[argn], "-")) {
+                if (stdoutUsed)
+                    pm_error("You cannot specify Standard Output ('-') "
+                             "for more than one output file");
+                stdoutUsed = true;
+            }
+        }
+    }
+    if (cmdlineP->outputFileCt < 1)
+        cmdlineP->outputFileNm[cmdlineP->outputFileCt++] = "-";
+
+    if (cmdlineP->character + cmdlineP->outputFileCt >= MAXPKCHAR)
+        pm_error("Number of output files (%u) "
+                 "plus -character value (%u) exceeds "
+                 "the maximum number of characters is a PK font file (%u)",
+                 cmdlineP->character, cmdlineP->outputFileCt, MAXPKCHAR);
 }
 
 
 
-/* get a byte from the PK file */
-static eightbits 
-pktopbm_pkbyte(void) {
-   pktopbm_pkloc++ ;
-   return(getc(pkfile)) ;
+typedef unsigned char eightbits ;
+
+static FILE * ifP;
+static unsigned int pkLoc;
+static const char * fileName[MAXPKCHAR];
+static int dynf ;
+static eightbits inputByte ;
+static eightbits bitWeight ;
+static int repeatCount ;
+static int flagByte ;
+static int debug = 0;
+
+#define dprintf(s,d) if (debug) printf(s,d)
+#define dprintf0(s) if (debug) printf(s)
+
+static eightbits
+pkByte() {
+/*----------------------------------------------------------------------------
+  Get a byte from the PK file
+-----------------------------------------------------------------------------*/
+    ++pkLoc;
+
+    return getc(ifP);
 }
 
 
 
-/* get a 16-bit half word from the PK file */
-static integer 
-get16(void) {
-   integer const a = pktopbm_pkbyte() ;
-   return((a<<8) + pktopbm_pkbyte()) ;
+static int
+get16() {
+/*----------------------------------------------------------------------------
+  Get a 16-bit half word from the PK file
+-----------------------------------------------------------------------------*/
+    int const a = pkByte() ;
+
+    return (a<<8) + pkByte();
 }
 
 
 
-/* get a 32-bit word from the PK file */
-static integer get32(void) {
-    integer a;
-    a = get16() ;
-    if (a > 32767) a -= 65536 ;
-    return((a<<16) + get16()) ;
+static int
+get32() {
+/*----------------------------------------------------------------------------
+  Get a 32-bit word from the PK file
+-----------------------------------------------------------------------------*/
+    int a;
+
+    a = get16();  /* initial value */
+
+    if (a > 32767)
+        a -= 65536;
+
+    return (a << 16) + get16();
 }
 
 
 
-/* get a nibble from current input byte, or new byte if no current byte */
-static integer 
-getnyb(void) {
+static int
+getNybble() {
+/*----------------------------------------------------------------------------
+  Get a nibble from current input byte, or new byte if no current byte
+-----------------------------------------------------------------------------*/
     eightbits temp;
-    if (bitweight == 0) {
-        inputbyte = pktopbm_pkbyte() ;
-        bitweight = 16 ;
+
+    if (bitWeight == 0) {
+        inputByte = pkByte() ;
+        bitWeight = 16 ;
     }
-    temp = inputbyte / bitweight ;
-    inputbyte -= temp * bitweight ;
-    bitweight >>= 4 ;
-    return(temp) ;
+    temp = inputByte / bitWeight ;
+    inputByte -= temp * bitWeight ;
+    bitWeight >>= 4 ;
+
+    return temp;
 }
 
 
 
-/* get a bit from the current input byte, or a new byte if no current byte */
 static bool
-getbit(void) {
+getBit() {
+/*----------------------------------------------------------------------------
+  Get a bit from the current input byte, or a new byte if no current byte
+-----------------------------------------------------------------------------*/
     bool temp ;
-    bitweight >>= 1 ;
-    if (bitweight == 0) {
-        inputbyte = pktopbm_pkbyte() ;
-        bitweight = 128 ;
+
+    bitWeight >>= 1 ;
+    if (bitWeight == 0) {
+        inputByte = pkByte();
+        bitWeight = 128 ;
     }
-    temp = (inputbyte >= bitweight) ;
-    if (temp) inputbyte -= bitweight ;
-    return(temp) ;
+    temp = (inputByte >= bitWeight);
+    if (temp)
+        inputByte -= bitWeight;
+
+    return temp;
 }
 
 
 
-/* unpack a dynamically packed number. dynf is dynamic packing threshold  */
-static integer 
-pkpackednum(void) {
-    integer i, j ;
-    i = getnyb() ;
+static int
+pkPackedNum() {
+/*----------------------------------------------------------------------------
+  Unpack a dynamically packed number. dynf is dynamic packing threshold
+-----------------------------------------------------------------------------*/
+    int i, j ;
+
+    i = getNybble() ;
+
     if (i == 0) {           /* large run count, >= 3 nibbles */
         do {
-            j = getnyb() ;          /* count extra nibbles */
+            j = getNybble() ;          /* count extra nibbles */
             i++ ;
         } while (j == 0) ;
         while (i > 0) {
-            j = (j<<4) + getnyb() ; /* add extra nibbles */
+            j = (j<<4) + getNybble() ; /* add extra nibbles */
             i-- ;
         }
         return (j - 15 +((13 - dynf)<<4) + dynf) ;
     } else if (i <= dynf) return (i) ;  /* number > 0 and <= dynf */
-    else if (i < 14) return (((i - dynf - 1)<<4) + getnyb() + dynf + 1) ;
+    else if (i < 14) return (((i - dynf - 1)<<4) + getNybble() + dynf + 1) ;
     else {
-        if (i == 14) repeatcount = pkpackednum() ;  /* get repeat count */
-        else repeatcount = 1 ;      /* value 15 indicates repeat count 1 */
-        return(pkpackednum()) ;
+        if (i == 14)
+            repeatCount = pkPackedNum() ;  /* get repeat count */
+        else
+            repeatCount = 1 ;      /* value 15 indicates repeat count 1 */
+
+        return pkPackedNum();
     }
 }
 
 
 
-/* skip specials in PK files, inserted by Metafont or some other program */
 static void
-skipspecials(void) {
-    integer i, j;
+skipSpecials() {
+/*----------------------------------------------------------------------------
+  Skip specials in PK files, inserted by Metafont or some other program
+-----------------------------------------------------------------------------*/
     do {
-        flagbyte = pktopbm_pkbyte() ;
-        if (flagbyte >= 240)
-            switch(flagbyte) {
+        flagByte = pkByte() ;
+        if (flagByte >= 240)
+            switch(flagByte) {
             case 240:           /* specials of size 1-4 bytes */
             case 241:
             case 242:
-            case 243:
+            case 243: {
+                int i, j;
+
                 i = 0 ;
-                for (j = 240 ; j <= flagbyte ; ++j) 
-                    i = (i<<8) + pktopbm_pkbyte() ;
-                for (j = 1 ; j <= i ; ++j) 
-                    pktopbm_pkbyte() ;  /* ignore special */
-                break ;
+                for (j = 240 ; j <= flagByte ; ++j)
+                    i = (i<<8) + pkByte() ;
+                for (j = 1 ; j <= i ; ++j)
+                    pkByte() ;  /* ignore special */
+            } break ;
             case 244:           /* no-op, parameters to specials */
                 get32() ;
             case 245:           /* start of postamble */
@@ -174,272 +294,378 @@ skipspecials(void) {
             case 253:
             case 254:
             case 255:
-                pm_error("unexpected flag byte %d", flagbyte) ;
+                pm_error("unexpected flag byte %d", flagByte) ;
             }
-    } while (!(flagbyte < 240 || flagbyte == 245)) ;
+    } while (!(flagByte < 240 || flagByte == 245)) ;
 }
 
 
 
-/* ignore character packet */
 static void
-ignorechar(integer const car, 
-           integer const endofpacket) {
+ignoreChar(int          const car,
+           unsigned int const endOfPacket) {
+/*----------------------------------------------------------------------------
+   ignore character packet
+-----------------------------------------------------------------------------*/
+   while (pkLoc != endOfPacket)
+       pkByte();
 
-   while (pktopbm_pkloc != endofpacket) pktopbm_pkbyte() ;
    if (car < 0 || car >= MAXPKCHAR)
       pm_message("Character %d out of range", car) ;
-   skipspecials() ;
+
+   skipSpecials() ;
 }
 
 
 
-int
-main(int argc, char *argv[]) {
-    integer x;
-    integer endofpacket ;
-    boolean turnon ;
-    integer i, j;
-    integer car ;
-    integer bmx=0, bmy=0;
-    integer set_bmx=0, set_bmy=0;
-    bit row[MAXROWWIDTH+1] ;
-    const char * const usage = 
-        "pkfile[.pk] [-d] [[-x width] [-y height] [-c num] pbmfile]...";
-   
-    pbm_init(&argc, argv);
-    for (i = 0 ; i < MAXPKCHAR ; i ++) filename[i] = NULL ;
-
-    pm_message("This is PKtoPBM, version 2.5") ;
-
-    if (--argc < 1) pm_usage(usage) ;
-
-    ++argv;
-    if(strlen(*argv) + 4 > NAMELENGTH)
-        pm_error("pkname is too long");
-    strcpy(pkname, *argv) ;
-    pktopbm_add_suffix(pkname, ".pk") ;
-
-    car = 0 ;
-    /* urg: use getopt */
-    while (++argv, --argc) {
-        if (argv[0][0] == '-' && argv[0][1])
-            switch (argv[0][1]) {
-            case 'X':
-            case 'x':
-                if (argv[0][2]) bmx = atoi(*argv+2) ;
-                else if (++argv, --argc) set_bmx = atoi(*argv) ;
-                else pm_usage(usage) ;
-                continue ;
-            case 'Y':
-            case 'y':
-                if (argv[0][2]) bmy = atoi(*argv+2) ;
-                else if (++argv, --argc) set_bmy = atoi(*argv) ;
-                else pm_usage(usage) ;
-                continue ;
-            case 'C':
-            case 'c':
-                if (argv[0][2]) car = atoi(*argv+2) ;
-                else if (++argv, --argc) car = atoi(*argv) ;
-                else pm_usage(usage) ;
-                break ;
-            case 'd':
-                debug=1;
-                break ;
-            default:
-                pm_usage(usage) ;
-            } else if (car < 0 || car >= MAXPKCHAR) {
-                pm_error("character must be in range 0 to %d (-c)", 
-                         MAXPKCHAR-1) ;
-            } else filename[car++] = *argv ;
-    }
+static void
+readHeader() {
+/*----------------------------------------------------------------------------
+   Read the header of the input file.
+
+   Surprisingly, nothing in the header is useful to this program, so we're
+   just reading past it and doing some validation.
 
-    pkfile = pm_openr(pkname);
-    if (pktopbm_pkbyte() != 247)
+   We read through the first flag byte and update the global variable
+   'flagByte'.
+-----------------------------------------------------------------------------*/
+    unsigned int commentSz;
+    unsigned int i;
+
+    if (pkByte() != 247)
         pm_error("bad PK file (pre command missing)") ;
-    if (pktopbm_pkbyte() != 89)
+
+    if (pkByte() != 89)
         pm_error("wrong version of packed file") ;
-    j = pktopbm_pkbyte() ;              /* get header comment size */
-    for (i = 1 ; i <= j ; i ++) pktopbm_pkbyte() ;  /* ignore header comment */
+
+    commentSz = pkByte() ;              /* get header comment size */
+
+    for (i = 1 ; i <= commentSz ; ++i)
+        pkByte() ;  /* ignore header comment */
+
     get32() ;                   /* ignore designsize */
     get32() ;                   /* ignore checksum */
     if (get32() != get32())         /* h & v pixels per point */
         pm_message("Warning: aspect ratio not 1:1") ;
-    skipspecials() ;
-    while (flagbyte != 245) {           /* not at postamble */
-        integer cheight, cwidth ;
-        integer xoffs=0, yoffs=0;
-        FILE *ofp;
-
-        bmx=set_bmx;
-        bmy=set_bmy;
-        dynf = (flagbyte>>4) ;          /* get dynamic packing value */
-        flagbyte &= 15 ;
-        turnon = (flagbyte >= 8) ;      /* black or white initially? */
-        if (turnon) flagbyte &= 7 ;     /* long or short form */
-        if (flagbyte == 7) {            /* long form preamble */
-            integer packetlength = get32() ;    /* character packet length */
-            car = get32() ;         /* character number */
-            endofpacket = packetlength + pktopbm_pkloc;
-                /* calculate end of packet */
-            if ((car >= MAXPKCHAR) || !filename[car]) {
-                ignorechar(car, endofpacket);
-                continue;
-            }
-            dprintf0 ("flagbyte7\n");
-            dprintf ("car: %d\n", car);
-            get32() ;               /* ignore tfmwidth */
-            x=get32() ;             /* ignore horiz escapement */
-            x=get32() ;             /* ignore vert escapement */
-            dprintf ("horiz esc %d\n", x);
-            dprintf ("vert esc %d\n", x);
-            cwidth = get32() ;          /* bounding box width */
-            cheight = get32() ;         /* bounding box height */
-            dprintf ("cwidth %d\n", cwidth);
-            dprintf ("cheight %d\n", cheight);
-            if (cwidth < 0 || cheight < 0 || 
-                cwidth > 65535 || cheight > 65535) {
-                ignorechar(car, endofpacket);
-                continue;
-            }
-            xoffs= get32() ;              /* horiz offset */
-            yoffs= get32() ;              /* vert offset */
-            dprintf ("xoffs %d\n", xoffs);
-            dprintf ("yoffs %d\n", yoffs);
-        } else if (flagbyte > 3) {      /* extended short form */
-            integer packetlength = ((flagbyte - 4)<<16) + get16() ;
-            /* packet length */
-            car = pktopbm_pkbyte() ;            /* char number */
-            endofpacket = packetlength + pktopbm_pkloc ; 
-                /* calculate end of packet */
-            if ((car >= MAXPKCHAR) || !filename[car]) {
-                ignorechar(car, endofpacket);
-                continue;
-            }
-            dprintf0 ("flagbyte>3\n");
-            dprintf ("car: %d\n", car);
-            pktopbm_pkbyte() ;              /* ignore tfmwidth (3 bytes) */
-            get16() ;               /* ignore tfmwidth (3 bytes) */
-            get16() ;               /* ignore horiz escapement */
-            cwidth = get16() ;          /* bounding box width */
-            cheight = get16() ;         /* bounding box height */
-            dprintf ("cwidth %d\n", cwidth);
-            dprintf ("cheight %d\n", cheight);
-            xoffs=get16();                         /* horiz offset */
-            if (xoffs >= 32768)
-                xoffs-= 65536;
-            yoffs=get16();                         /* vert offset */
-            if (yoffs >= 32768)
-                yoffs-= 65536;
-            dprintf ("xoffs %d\n", xoffs);
-            dprintf ("yoffs %d\n", yoffs);
-        } else {                    /* short form preamble */
-            integer packetlength = (flagbyte<<8) + pktopbm_pkbyte() ;
-            /* packet length */
-            car = pktopbm_pkbyte() ;            /* char number */
-            endofpacket = packetlength + pktopbm_pkloc ;    
-                /* calculate end of packet */
-            if ((car >= MAXPKCHAR) || !filename[car]) {
-                ignorechar(car, endofpacket);
-                continue;
-            }
-            dprintf0 ("flagbyte<=3\n");
-            dprintf ("car: %d\n", car);
-            pktopbm_pkbyte() ;          /* ignore tfmwidth (3 bytes) */
-            get16() ;               /* ignore tfmwidth (3 bytes) */
-            x = pktopbm_pkbyte() ;  /* ignore horiz escapement */
-            dprintf ("horiz esc %d\n", x);
-            cwidth = pktopbm_pkbyte() ;            /* bounding box width */
-            cheight = pktopbm_pkbyte() ;           /* bounding box height */
-            dprintf ("cwidth %d\n", cwidth);
-            dprintf ("cheight %d\n", cheight);
-            xoffs=pktopbm_pkbyte ();               /* horiz offset */
-            if (xoffs >= 128)
-                xoffs-=256;
-            yoffs=pktopbm_pkbyte ();               /* vert offset */
-            if (yoffs >= 128)
-                yoffs-=256;
+
+    skipSpecials();
+}
+
+
+
+static void
+readCharacterHeader(int *          const carP,
+                    unsigned int * const endOfPacketP,
+                    bool *         const mustIgnoreP,
+                    int *          const cheightP,
+                    int *          const cwidthP,
+                    int *          const xoffsP,
+                    int *          const yoffsP,
+                    bool *         const turnonP) {
+
+    int packetLength;
+        /* character packet length field value */
+    int cheight, cwidth;
+        /* bounding box height, width field values */
+    int xoffs=0, yoffs=0;
+    bool turnon ;
+    int x;
+
+    dynf = (flagByte >> 4);          /* get dynamic packing value */
+    flagByte &= 15;
+    turnon = (flagByte >= 8) ;      /* black or white initially? */
+    if (turnon)
+        flagByte &= 7;     /* long or short form */
+
+    if (flagByte == 7) {            /* long form preamble */
+        packetLength  = get32();
+        *carP         = get32();         /* character number */
+
+        dprintf0("flagByte7\n");
+        dprintf("car: %d\n", *carP);
+        get32();               /* ignore tfmwidth */
+        x=get32();             /* ignore horiz escapement */
+        dprintf("horiz esc %d\n", x);
+        x=get32();             /* ignore vert escapement */
+        dprintf("vert esc %d\n", x);
+        cwidth = get32();          /* bounding box width */
+        cheight = get32();         /* bounding box height */
+        dprintf("cwidth %d\n", cwidth);
+        dprintf("cheight %d\n", cheight);
+        if (cwidth < 0 || cheight < 0 ||
+            cwidth > 65535 || cheight > 65535) {
+            *mustIgnoreP = true;
+        } else {
+            *mustIgnoreP = false;
+            xoffs = get32() ;              /* horiz offset */
+            yoffs = get32() ;              /* vert offset */
             dprintf ("xoffs %d\n", xoffs);
             dprintf ("yoffs %d\n", yoffs);
         }
-        if (filename[car]) {
-            if (!bmx) bmx= cwidth;
-            if (!bmy) bmy= cheight;
-            bitmap = pbm_allocarray(bmx, bmy) ;
-            if (bitmap == NULL)
-                pm_error("out of memory allocating bitmap") ;
-        } else {
-            ignorechar(car, endofpacket);
-            continue;
+    } else if (flagByte > 3) {      /* extended short form */
+        packetLength = ((flagByte - 4)<<16) + get16() ;
+
+        *carP = pkByte() ;            /* char number */
+
+        *mustIgnoreP = false;
+
+        dprintf0("flagByte>3\n");
+        dprintf("car: %d\n", *carP);
+        pkByte();              /* ignore tfmwidth (3 bytes) */
+        get16();               /* ignore tfmwidth (3 bytes) */
+        get16();               /* ignore horiz escapement */
+        cwidth = get16();          /* bounding box width */
+        cheight = get16();         /* bounding box height */
+        dprintf("cwidth %d\n", cwidth);
+        dprintf("cheight %d\n", cheight);
+        xoffs = get16();                         /* horiz offset */
+        if (xoffs >= 32768)
+            xoffs -= 65536;
+        yoffs = get16();                         /* vert offset */
+        if (yoffs >= 32768)
+            yoffs -= 65536;
+        dprintf("xoffs %d\n", xoffs);
+        dprintf("yoffs %d\n", yoffs);
+    } else {                    /* short form preamble */
+        packetLength  = (flagByte << 8) + pkByte();
+        *carP         = pkByte();            /* char number */
+
+        *mustIgnoreP = false;
+
+        dprintf0("flagByte<=3\n");
+        dprintf("car: %d\n", *carP);
+        pkByte();          /* ignore tfmwidth (3 bytes) */
+        get16();               /* ignore tfmwidth (3 bytes) */
+        x = pkByte() ;  /* ignore horiz escapement */
+        dprintf("horiz esc %d\n", x);
+        cwidth = pkByte();            /* bounding box width */
+        cheight = pkByte() ;           /* bounding box height */
+        dprintf("cwidth %d\n", cwidth);
+        dprintf("cheight %d\n", cheight);
+        xoffs = pkByte();               /* horiz offset */
+        if (xoffs >= 128)
+            xoffs -=256;
+        yoffs = pkByte();               /* vert offset */
+        if (yoffs >= 128)
+            yoffs -= 256;
+        dprintf("xoffs %d\n", xoffs);
+        dprintf("yoffs %d\n", yoffs);
+    }
+    if (packetLength < 0)
+        pm_error("Invalid character header - negative packet length");
+    if (packetLength > UINT_MAX - pkLoc)
+        pm_error("Invalid character header - excessive packet lenght");
+
+    *endOfPacketP = packetLength + pkLoc;
+
+    *cheightP = cheight;
+    *cwidthP  = cwidth;
+    *xoffsP   = xoffs;
+    *yoffsP   = yoffs;
+    *turnonP  = turnon;
+}
+
+
+
+static void
+readOneCharacter(bool           const bmxOverrideSpec,
+                 int            const bmxOverride,
+                 bool           const bmyOverrideSpec,
+                 int            const bmyOverride,
+                 unsigned int * const carP,
+                 bool *         const mustIgnoreP,
+                 bit ***        const bitmapP,
+                 unsigned int * const bmxP,
+                 unsigned int * const bmyP) {
+
+    int car;
+    unsigned int endOfPacket;
+    bool mustIgnore;
+    int cheight, cwidth;
+    int xoffs, yoffs;
+    bool turnon;
+    bit row[MAXROWWIDTH+1];
+
+    readCharacterHeader(&car, &endOfPacket, &mustIgnore,
+                        &cheight, &cwidth, &xoffs, &yoffs, &turnon);
+
+    *carP = car;
+
+    if (mustIgnore || !fileName[car]) {
+        /* Ignore this character in the font */
+        ignoreChar(car, endOfPacket);
+        *mustIgnoreP = true;
+    } else {
+        bit ** bitmap;
+        unsigned int i;
+
+        int const bmx = bmxOverrideSpec ? bmxOverride : cwidth;
+        int const bmy = bmyOverrideSpec ? bmyOverride : cheight;
+
+        *mustIgnoreP = false;
+
+        bitmap = pbm_allocarray(bmx, bmy);
+
+        bitWeight = 0 ;
+        for (i = 0 ; i < bmy ; ++i) {
+            /* make it blank */
+            unsigned int j;
+
+            for (j = 0 ; j < bmx ; ++j)
+                bitmap[i][j] = PBM_WHITE;
         }
-        bitweight = 0 ;
-        for (i = 0 ; i < bmy ; i ++)           /* make it blank */
-            for (j = 0 ; j < bmx ; j ++)
-                bitmap[i][j]= PBM_WHITE;
         if (dynf == 14) {               /* bitmapped character */
-            dprintf ("bmy: %d\n ", bmy);
-            dprintf ("y: %d\n ", bmy-yoffs-1);
-            for (i = 0 ; i < cheight ; i ++) {
-                int yi= i+(bmy-yoffs-1);
-                for (j = 0 ; j < cwidth ; j ++) {
-                    int xj= j-xoffs;
-                    if (getbit() && 0<=xj && xj<bmx && 0<=yi && yi<bmy)
+            dprintf("bmy: %d\n ", bmy);
+            dprintf("y: %d\n ", bmy - yoffs - 1);
+            for (i = 0 ; i < cheight ; ++i) {
+                unsigned int const yi = i + (bmy - yoffs - 1);
+                unsigned int j;
+                for (j = 0 ; j < cwidth ; ++j) {
+                    unsigned int const xj = j - xoffs;
+                    if (getBit() && 0 <= xj && xj < bmx && 0 <= yi && yi < bmy)
                         bitmap[yi][xj] = PBM_BLACK ;
                 }
             }
         } else {                    /* dynamically packed char */
-            integer rowsleft = cheight ;
-            integer hbit = cwidth ;
-            integer rp = 0;
-            repeatcount = 0 ;
-            dprintf ("bmy: %d\n ", bmy);
-            dprintf ("y: %d\n", cheight-rowsleft+(bmy-2*yoffs-1));
+            int rowsleft = cheight ;
+            int hbit = cwidth ;
+            int rp = 0;
+            repeatCount = 0 ;
+            dprintf("bmy: %d\n ", bmy);
+            dprintf("y: %d\n", cheight-rowsleft+(bmy-2*yoffs-1));
             while (rowsleft > 0) {
-                integer count = pkpackednum() ; /* get current color count */
+                int count = pkPackedNum() ; /* get current color count */
                 while (count > 0) {
                     if (count < hbit) {     /* doesn't extend past row */
                         hbit -= count ;
                         while (count--)
                             row[rp++] = turnon ? PBM_BLACK : PBM_WHITE;
                     } else {                /* reaches end of row */
-                        count -= hbit ;
+                        count -= hbit;
                         while (hbit--)
                             row[rp++] = turnon ? PBM_BLACK : PBM_WHITE;
-                        for (i = 0; i <= repeatcount; i++) {  /* fill row */
-                            int yi= i+cheight-rowsleft-1;
-                            if (0<=yi && yi < bmy)
+                        for (i = 0; i <= repeatCount; i++) {  /* fill row */
+                            unsigned int const yi = i + cheight - rowsleft - 1;
+                            if (0 <= yi && yi < bmy) {
+                                unsigned int j;
                                 for (j = 0; j < cwidth; j++) {
-                                    int xj= j-xoffs;
-                                    if (0<=xj && xj<bmx)
+                                    unsigned int const xj= j - xoffs;
+                                    if (0 <= xj && xj < bmx)
                                         bitmap[yi][xj] = row[j] ;
                                 }
+                            }
                         }
-                        rowsleft -= repeatcount + 1;
-                        repeatcount = rp = 0 ;
-                        hbit = cwidth ;
+                        rowsleft -= repeatCount + 1;
+                        repeatCount = rp = 0;
+                        hbit = cwidth;
                     }
                 }
-                turnon = !turnon ;
+                turnon = !turnon;
             }
             if (rowsleft != 0 || hbit != cwidth)
                 pm_error("bad pk file (more bits than required)") ;
         }
-        if (endofpacket != pktopbm_pkloc)
+        if (endOfPacket != pkLoc)
             pm_error("bad pk file (bad packet length)") ;
-
-        ofp = pm_openw(filename[car]);
-        filename[car] = NULL;
-        pbm_writepbm(ofp, bitmap, bmx, bmy, 0) ;
-        pbm_freearray(bitmap, bmy) ;
-        pm_close(ofp) ;
-        skipspecials() ;
+        *bitmapP = bitmap;
+        *bmxP    = bmx;
+        *bmyP    = bmy;
     }
-    while (! feof(pkfile)) pktopbm_pkbyte() ;       /* skip trailing junk */
-    pm_close(pkfile);
-    for (car = 0; car < MAXPKCHAR; car++)
-        if (filename[car])
+}
+
+
+
+static void
+generatePbmFile(const char * const fileNm,
+                bit **       const bitmap,
+                unsigned int const cols,
+                unsigned int const rows) {
+
+    FILE * ofP;
+
+    ofP = pm_openw(fileNm);
+
+    pbm_writepbm(ofP, bitmap, cols, rows, 0);
+
+    pm_close(ofP);
+}
+
+
+
+static void
+warnMissingCodePoint() {
+
+    unsigned int car;
+
+    for (car = 0; car < MAXPKCHAR; ++car) {
+        if (fileName[car])
             pm_message("Warning: No character in position %d (file %s).",
-                       car, filename[car]) ;
-    pm_message("%d bytes read from packed file.", pktopbm_pkloc-1) ;
+                       car, fileName[car]) ;
+    }
+}
+
+
+
+int
+main(int argc, const char ** argv) {
+
+    struct CmdlineInfo cmdline;
+    unsigned int i;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    debug = cmdline.debug;
+
+    for (i = 0; i < cmdline.character; ++i)
+        fileName[i] = NULL;
+    for (i = 0; i < cmdline.outputFileCt; ++i)
+        fileName[cmdline.character + i] = cmdline.outputFileNm[i];
+    for (i = cmdline.character + cmdline.outputFileCt;
+         i < MAXPKCHAR;
+         ++i)
+        fileName[i] = NULL;
+
+    ifP = pm_openr(cmdline.inputFileNm);
+
+    pkLoc = 0;
+
+    readHeader();
+
+    while (flagByte != 245) {  /* not at postamble */
+
+        unsigned int car;
+        bool mustIgnore;
+        bit ** bitmap;
+        unsigned int cols, rows;
+
+        readOneCharacter(!!cmdline.xSpec, cmdline.x,
+                         !!cmdline.ySpec, cmdline.y,
+                         &car, &mustIgnore, &bitmap, &cols, &rows);
+
+        if (!mustIgnore) {
+            generatePbmFile(fileName[car], bitmap, cols, rows);
+
+            pbm_freearray(bitmap, rows) ;
+        }
+
+        fileName[car] = NULL;
+
+        skipSpecials();
+    }
+
+    while (!feof(ifP))
+        pkByte() ;       /* skip trailing junk */
+
+    pm_close(ifP);
+
+    warnMissingCodePoint();
+
+    pm_message("%u bytes read from packed file.", pkLoc);
+
     return 0;
 }
+
+
+
diff --git a/converter/pbm/thinkjettopbm.l b/converter/pbm/thinkjettopbm.l
index 5de4f2bb..c55a0085 100644
--- a/converter/pbm/thinkjettopbm.l
+++ b/converter/pbm/thinkjettopbm.l
@@ -38,6 +38,7 @@
 #include <errno.h>
 #include <unistd.h>
 #include "pm_c_util.h"
+#include "mallocvar.h"
 #include "pbm.h"
 #include "shhopt.h"
 
@@ -114,8 +115,10 @@ DIG             [0-9]
 <RASTERMODE>\033\*b{DIG}+W  {
                             int l;
                             if (rowCount >= rowCapacity) {
+                                if (rowCapacity > INT_MAX-100)
+                                    pm_error("Too many rows to count");
                                 rowCapacity += 100;
-                                rows = realloc (rows, rowCapacity * sizeof *rows);
+                                REALLOCARRAY(rows, rowCapacity);
                                 if (rows == NULL)
                                     pm_error ("Out of memory.");
                             }
@@ -223,6 +226,9 @@ yywrap (void)
 
     debug ("Got %d rows, %d columns\n", rowCount, maxRowLength);
 
+    if (maxRowLength > INT_MAX/8)
+        pm_error("A row has an uncomputably large number of columns: %d",
+                 maxRowLength);
     /*
      * Quite simple since ThinkJet bit arrangement matches PBM
      */
diff --git a/converter/pbm/ybmtopbm.c b/converter/pbm/ybmtopbm.c
index 36f2dee7..78eb79f2 100644
--- a/converter/pbm/ybmtopbm.c
+++ b/converter/pbm/ybmtopbm.c
@@ -10,6 +10,8 @@
 ** implied warranty.
 */
 
+#include <limits.h>
+
 #include "pm.h"
 #include "pbm.h"
 #include "bitreverse.h"
@@ -80,6 +82,9 @@ main(int argc, const char * argv[]) {
     getinit(ifP, &cols, &rows, &depth);
     if (depth != 1)
         pm_error("YBM file has depth of %u, must be 1", (unsigned int) depth);
+    if (cols > INT_MAX - 15)
+        pm_error("YBM file has uncomputably large width %d", cols);
+
 
     pbm_writepbminit(stdout, cols, rows, 0);