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/Makefile17
-rw-r--r--converter/pbm/atktopbm.c425
-rw-r--r--converter/pbm/brushtopbm.c174
-rw-r--r--converter/pbm/cistopbm.c180
-rw-r--r--converter/pbm/cmuwm.h17
-rw-r--r--converter/pbm/cmuwmtopbm.c21
-rw-r--r--converter/pbm/escp2topbm.c384
-rw-r--r--converter/pbm/g3topbm.c93
-rw-r--r--converter/pbm/icontopbm.c159
-rw-r--r--converter/pbm/macp.h18
-rw-r--r--converter/pbm/macptopbm.c426
-rw-r--r--converter/pbm/pbmto10x.c117
-rw-r--r--converter/pbm/pbmtoascii.c324
-rw-r--r--converter/pbm/pbmtoatk.c69
-rw-r--r--converter/pbm/pbmtocis.c170
-rw-r--r--converter/pbm/pbmtocmuwm.c8
-rw-r--r--converter/pbm/pbmtoepsi.c128
-rw-r--r--converter/pbm/pbmtoepson.c61
-rw-r--r--converter/pbm/pbmtoescp2.c260
-rw-r--r--converter/pbm/pbmtog3.c8
-rw-r--r--converter/pbm/pbmtog3.test23
-rw-r--r--converter/pbm/pbmtogem.c252
-rw-r--r--converter/pbm/pbmtoibm23xx.c2
-rw-r--r--converter/pbm/pbmtolj.c6
-rw-r--r--converter/pbm/pbmtomacp.c655
-rw-r--r--converter/pbm/pbmtomatrixorbital.c35
-rw-r--r--converter/pbm/pbmtomgr.c6
-rw-r--r--converter/pbm/pbmtonokia.c17
-rw-r--r--converter/pbm/pbmtopi3.c164
-rw-r--r--converter/pbm/pbmtopk.c30
-rw-r--r--converter/pbm/pbmtoppa/Makefile17
-rw-r--r--converter/pbm/pbmtopsg3.c4
-rw-r--r--converter/pbm/pbmtoptx.c135
-rw-r--r--converter/pbm/pbmtosunicon.c (renamed from converter/pbm/pbmtoicon.c)87
-rw-r--r--converter/pbm/pbmtoxbm.c65
-rw-r--r--converter/pbm/pbmtoybm.c143
-rw-r--r--converter/pbm/pbmtozinc.c242
-rw-r--r--converter/pbm/pi3topbm.c224
-rw-r--r--converter/pbm/thinkjettopbm.l15
-rw-r--r--converter/pbm/xbmtopbm.c10
-rw-r--r--converter/pbm/ybmtopbm.c161
41 files changed, 3203 insertions, 2149 deletions
diff --git a/converter/pbm/Makefile b/converter/pbm/Makefile
index c859b105..602cb156 100644
--- a/converter/pbm/Makefile
+++ b/converter/pbm/Makefile
@@ -7,12 +7,13 @@ VPATH=.:$(SRCDIR)/$(SUBDIR)
 
 include $(BUILDDIR)/config.mk
 
-PORTBINARIES =	atktopbm brushtopbm cmuwmtopbm ddbugtopbm g3topbm escp2topbm \
-		icontopbm macptopbm mdatopbm mgrtopbm mrftopbm \
+PORTBINARIES =	atktopbm brushtopbm cistopbm cmuwmtopbm \
+		ddbugtopbm g3topbm escp2topbm \
+		macptopbm mdatopbm mgrtopbm mrftopbm \
 		pbmto10x pbmto4425 pbmtoascii pbmtoatk \
-		pbmtobbnbg pbmtocmuwm pbmtodjvurle \
+		pbmtobbnbg pbmtocis pbmtocmuwm pbmtodjvurle \
 		pbmtoepsi pbmtoepson pbmtoescp2 \
-		pbmtog3 pbmtogem pbmtogo pbmtoibm23xx pbmtoicon pbmtolj \
+		pbmtog3 pbmtogem pbmtogo pbmtoibm23xx pbmtosunicon pbmtolj \
 		pbmtoln03 pbmtolps \
 		pbmtomacp pbmtomatrixorbital pbmtomda pbmtomgr pbmtomrf \
 		pbmtonokia \
@@ -72,6 +73,14 @@ thinkjettopbm.c:%.c:%.c1 $(SRCDIR)/lib/util/lexheader
 	  grep -v "^[[:space:]]*int yywrap(void);" \
 	  >$@
 
+install.bin: install.bin.local
+.PHONY: install.bin.local
+install.bin.local: $(PKGDIR)/bin
+# Remember that $(SYMLINK) might just be a copy command.
+# In December 2010 (Actually January 2011), pbmtosunicon replaced pbmtoicon
+	cd $(PKGDIR)/bin ; \
+	$(SYMLINK) pbmtosunicon$(EXE) pbmtoicon$(EXE)
+
 thisdirclean: localclean
 .PHONY: localclean
 localclean:
diff --git a/converter/pbm/atktopbm.c b/converter/pbm/atktopbm.c
index 62664999..807e4f4a 100644
--- a/converter/pbm/atktopbm.c
+++ b/converter/pbm/atktopbm.c
@@ -61,17 +61,24 @@
 */
 
 /* macros to generate case entries for switch statement */
-#define case1(v) case v
-#define case4(v) case v: case (v)+1: case (v)+2: case(v)+3
-#define case6(v) case4(v): case ((v)+4): case ((v)+5)
-#define case8(v) case4(v): case4((v)+4)
+#define CASE1(v) case v
+#define CASE4(v) case v: case (v)+1: case (v)+2: case(v)+3
+#define CASE6(v) CASE4(v): case ((v)+4): case ((v)+5)
+#define CASE8(v) CASE4(v): CASE4((v)+4)
+
+
 
 static long
-ReadRow(FILE * const file, unsigned char * const row, long const length) {
+ReadRow(FILE *          const file,
+        unsigned char * const row,
+        long            const length) {
 /*----------------------------------------------------------------------------
   'file' is where to get them from.
   'row' is where to put bytes.
   'length' is how many bytes in row must be filled.
+  
+  Return the delimiter that marks the end of the row, or EOF if EOF marks
+  the end of the row, or NUL in some cases.
 -----------------------------------------------------------------------------*/
     /* Each input character is processed by the central loop.  There are 
     ** some input codes which require two or three characters for
@@ -80,18 +87,23 @@ ReadRow(FILE * const file, unsigned char * const row, long const length) {
     ** to the Ready state whenever a character unacceptable to the
     ** current state is read.
     */
-    enum stateCode {
-        Ready,      /* any input code is allowed */
-        HexDigitPending,    /* have seen the first of a hex digit pair */
-        RepeatPending,  /* repeat code has been seen:
-                   must be followed by two hex digits */
-        RepeatAndDigit};    /* have seen repeat code and its first
-                   following digit */
-    enum stateCode InputState;  /* current state */
-    register int c;     /* the current input character */
-    register long repeatcount = 0;  /* current repeat value */
-    register long hexval;   /* current hex value */
-    long pendinghex = 0;    /* the first of a pair of hex characters */
+    enum StateCode {
+        Ready,
+            /* any input code is allowed */
+        HexDigitPending,
+            /* have seen the first of a hex digit pair */
+        RepeatPending,
+            /* repeat code has been seen: must be followed by two hex digits
+             */
+        RepeatAndDigit
+            /* have seen repeat code and its first following digit */
+    };
+    
+    enum StateCode InputState;  /* current state */
+    int c;     /* the current input character */
+    long repeatcount;  /* current repeat value */
+    long hexval;   /* current hex value */
+    long pendinghex;    /* the first of a pair of hex characters */
     int lengthRemaining;
     unsigned char * cursor;
     
@@ -101,262 +113,239 @@ ReadRow(FILE * const file, unsigned char * const row, long const length) {
     ** zero, we ungetc the byte.
     */
 
-    lengthRemaining = length;
-    cursor = row;
+    repeatcount = 0;  /* initial value */
+    pendinghex = 0;  /* initial value */
+
+    lengthRemaining = length;  /* initial value */
+    cursor = row;  /* initial value */
+    InputState = Ready;  /* initial value */
 
-    InputState = Ready;
     while ((c=getc(file)) != EOF) switch (c) {
 
-    case8(0x0):
-    case8(0x8):
-    case8(0x10):
-    case8(0x18):
-    case1(' '):
-        /* control characters and space are legal and ignored */
-        break;
-    case1(0x40):    /* '@' */
-    case1(0x5B):    /* '[' */
-    case4(0x5D):    /*  ']'  '^'  '_'  '`' */
-    case4(0x7D):    /* '}'  '~'  DEL  0x80 */
-    default:        /* all above 0x80 */
-        /* error code:  Ignored at present.  Reset InputState. */
-        InputState = Ready;
-        break;
-
-    case1(0x7B):    /* '{' */
-    case1(0x5C):    /* '\\' */
-        /* illegal end of line:  exit anyway */
-        ungetc(c, file);    /* retain terminator in stream */
-        /* DROP THROUGH */
-    case1(0x7C):    /* '|' */
-        /* legal end of row: may have to pad  */
-        while (lengthRemaining-- > 0)
-            *cursor++ = WHITEBYTE;
-        return c;
+        CASE8(0x0):
+        CASE8(0x8):
+        CASE8(0x10):
+        CASE8(0x18):
+        CASE1(' '):
+            /* control characters and space are legal and ignored */
+            break;
+        CASE1(0x40):    /* '@' */
+        CASE1(0x5B):    /* '[' */
+        CASE4(0x5D):    /*  ']'  '^'  '_'  '`' */
+        CASE4(0x7D):    /* '}'  '~'  DEL  0x80 */
+        default:        /* all above 0x80 */
+            /* error code:  Ignored at present.  Reset InputState. */
+            InputState = Ready;
+            break;
+
+        CASE1(0x7B):    /* '{' */
+        CASE1(0x5C):    /* '\\' */
+            /* illegal end of line:  exit anyway */
+            ungetc(c, file);    /* retain terminator in stream */
+            /* DROP THROUGH */
+        CASE1(0x7C):    /* '|' */
+            /* legal end of row: may have to pad  */
+            while (lengthRemaining-- > 0)
+                *cursor++ = WHITEBYTE;
+            return c;
     
-    case1(0x21):
-    case6(0x22):
-    case8(0x28):
-        /* punctuation characters: repeat byte given by two
-        ** succeeding hex chars
-        */
-        if (lengthRemaining <= 0) {
-            ungetc(c, file);
-            return('\0');
-        }
-        repeatcount = c - OTHERZERO;
-        InputState = RepeatPending;
-        break;
-
-    case8(0x30):
-    case8(0x38):
-        /* digit (or following punctuation)  -  hex digit */
-        hexval = c - 0x30;
-        goto hexdigit;
-    case6(0x41):
-        /* A ... F    -  hex digit */
-        hexval = c - (0x41 - 0xA);
-        goto hexdigit;
-    case6(0x61):
-        /* a ... f  - hex digit */
-        hexval = c - (0x61 - 0xA);
-        goto hexdigit;
-
-    case8(0x67):
-    case8(0x6F):
-    case4(0x77):
-        /* g ... z   -   multiple WHITE bytes */
-        if (lengthRemaining <= 0) {
-            ungetc(c, file);
-            return('\0');
-        }
-        repeatcount = c - WHITEZERO;
-        hexval = WHITEBYTE;
-        goto store;
-    case8(0x47):
-    case8(0x4F):
-    case4(0x57):
-        /* G ... Z   -   multiple BLACK bytes */
-        if (lengthRemaining <= 0) {
-            ungetc(c, file);
-            return('\0');
-        }
-        repeatcount = c - BLACKZERO;
-        hexval = BLACKBYTE;
-        goto store;
-
-hexdigit:
-        /* process a hex digit.  Use InputState to determine
-            what to do with it. */
-        if (lengthRemaining <= 0) {
-            ungetc(c, file);
-            return('\0');
-        }
-        switch(InputState) {
-        case Ready:
-            InputState = HexDigitPending;
-            pendinghex = hexval << 4;
+        CASE1(0x21):
+        CASE6(0x22):
+        CASE8(0x28):
+            /* punctuation characters: repeat byte given by two
+            ** succeeding hex chars
+            */
+            if (lengthRemaining <= 0) {
+                ungetc(c, file);
+                return('\0');
+            }
+            repeatcount = c - OTHERZERO;
+            InputState = RepeatPending;
             break;
-        case HexDigitPending:
-            hexval |= pendinghex;
-            repeatcount = 1;
+
+        CASE8(0x30):
+        CASE8(0x38):
+            /* digit (or following punctuation)  -  hex digit */
+            hexval = c - 0x30;
+            goto hexdigit;
+        CASE6(0x41):
+            /* A ... F    -  hex digit */
+            hexval = c - (0x41 - 0xA);
+            goto hexdigit;
+        CASE6(0x61):
+            /* a ... f  - hex digit */
+            hexval = c - (0x61 - 0xA);
+            goto hexdigit;
+
+        CASE8(0x67):
+        CASE8(0x6F):
+        CASE4(0x77):
+            /* g ... z   -   multiple WHITE bytes */
+            if (lengthRemaining <= 0) {
+                ungetc(c, file);
+                return('\0');
+            }
+            repeatcount = c - WHITEZERO;
+            hexval = WHITEBYTE;
             goto store;
-        case RepeatPending:
-            InputState = RepeatAndDigit;
-            pendinghex = hexval << 4;
-            break;
-        case RepeatAndDigit:
-            hexval |= pendinghex;
+        CASE8(0x47):
+        CASE8(0x4F):
+        CASE4(0x57):
+            /* G ... Z   -   multiple BLACK bytes */
+            if (lengthRemaining <= 0) {
+                ungetc(c, file);
+                return('\0');
+            }
+            repeatcount = c - BLACKZERO;
+            hexval = BLACKBYTE;
             goto store;
-        }
-        break;
-
-store:
-        /* generate byte(s) into the output row 
-            Use repeatcount, depending on state.  */
-        if (lengthRemaining < repeatcount) 
-            /* reduce repeat count if it would exceed
-                available space */
-            repeatcount = lengthRemaining;
-        lengthRemaining -= repeatcount;  /* do this before repeatcount-- */
-        while (repeatcount-- > 0)
+
+        hexdigit:
+            /* process a hex digit.  Use InputState to determine
+               what to do with it. */
+            if (lengthRemaining <= 0) {
+                ungetc(c, file);
+                return('\0');
+            }
+            switch(InputState) {
+            case Ready:
+                InputState = HexDigitPending;
+                pendinghex = hexval << 4;
+                break;
+            case HexDigitPending:
+                hexval |= pendinghex;
+                repeatcount = 1;
+                goto store;
+            case RepeatPending:
+                InputState = RepeatAndDigit;
+                pendinghex = hexval << 4;
+                break;
+            case RepeatAndDigit:
+                hexval |= pendinghex;
+                goto store;
+            }
+            break;
+
+        store:
+            /* generate byte(s) into the output row 
+               Use repeatcount, depending on state.  */
+            if (lengthRemaining < repeatcount) 
+                /* reduce repeat count if it would exceed
+                   available space */
+                repeatcount = lengthRemaining;
+            lengthRemaining -= repeatcount;  /* do this before repeatcount-- */
+            while (repeatcount-- > 0)
                 *cursor++ = hexval;
-        InputState = Ready;
-        break;
+            InputState = Ready;
+            break;
 
-    } /* end of while( - )switch( - ) */
+        } /* end of while( - )switch( - ) */
     return EOF;
 }
 
 
 
-#undef case1
-#undef case4
-#undef case6
-#undef case8
+#undef CASE1
+#undef CASE4
+#undef CASE6
+#undef CASE8
 
 
 
 static void
-ReadATKRaster(FILE * const file, 
-              int * const rwidth, 
-              int * const rheight, 
-              unsigned char ** const destaddrP) {
+ReadATKRaster(FILE * const ifP) {
 
-    int row, rowlen;  /* count rows;  byte length of row */
+    int row;  /* count rows;  byte length of row */
     int version;
     char keyword[6];
     int discardid;
     int objectid;     /* id read for the incoming pixel image */
     long tc;            /* temp */
     int width, height;      /* dimensions of image */
+    bit * bitrow;
 
-    if (fscanf(file, "\\begindata{raster,%d", &discardid) != 1
-                || getc(file) != '}' || getc(file) != '\n')
-      pm_error ("input file not Andrew raster object");
+    if (fscanf(ifP, "\\begindata{raster,%d", &discardid) != 1
+        || getc(ifP) != '}' || getc(ifP) != '\n')
+        pm_error ("input file not Andrew raster object");
 
-    fscanf(file, " %d ", &version);
+    fscanf(ifP, " %d ", &version);
     if (version < 2) 
-      pm_error ("version too old to parse");
+        pm_error ("version too old to parse");
 
     {
         unsigned int options;
         long xscale, yscale;
         long xoffset, yoffset, subwidth, subheight;
         /* ignore all these features: */
-        fscanf(file, " %u %ld %ld %ld %ld %ld %ld",  
+        fscanf(ifP, " %u %ld %ld %ld %ld %ld %ld",  
                &options, &xscale, &yscale, &xoffset, 
                &yoffset, &subwidth, &subheight);
     }
     /* scan to end of line in case this is actually something beyond V2 */
-    while (((tc=getc(file)) != '\n') && (tc != '\\') && (tc != EOF)) {}
+    while (((tc=getc(ifP)) != '\n') && (tc != '\\') && (tc != EOF)) {}
 
     /* read the keyword */
-    fscanf(file, " %5s", keyword);
+    fscanf(ifP, " %5s", keyword);
     if (!streq(keyword, "bits"))
-      pm_error ("keyword is not 'bits'!");
+        pm_error ("keyword is not 'bits'!");
 
-    fscanf(file, " %d %d %d ", &objectid, &width, &height);
+    fscanf(ifP, " %d %d %d ", &objectid, &width, &height);
 
     if (width < 1 || height < 1 || width > 1000000 || height > 1000000) 
-      pm_error ("bad width or height");
-
-    *rwidth = width;
-    *rheight = height;
-    rowlen = (width + 7) / 8;
-    MALLOCARRAY(*destaddrP, height * rowlen);
-    if (destaddrP == NULL)
-        pm_error("Unable to allocate %u bytes for the input image.",
-                 height * rowlen);
-    for (row = 0;   row < height;   row++)
-      {
-        long c;
-
-        c = ReadRow(file, *destaddrP + (row * rowlen), rowlen);
-        if (c != '|')
-          {
-        if (c == EOF)
-          pm_error ("premature EOF");
-        else
-          pm_error ("bad format");
-        break;
-          }
-      }
-    while (! feof(file) && getc(file) != '\\') {};  /* scan for \enddata */
-    if (fscanf(file, "enddata{raster,%d", &discardid) != 1
-        || getc(file) != '}' || getc(file) != '\n')
-      pm_error ("missing end-of-object marker");
-}
+        pm_error("bad width or height");
 
+    pbm_writepbminit(stdout, width, height, 0);
+    bitrow = pbm_allocrow_packed(width);
 
+    for (row = 0;   row < height; ++row) {
+        unsigned int const rowlen = (width + 7) / 8;
+        long const nextChar = ReadRow(ifP, bitrow, rowlen);
 
-int
-main(int argc, char **argv) {
+        switch (nextChar) {
+        case '|': 
+            pbm_writepbmrow_packed(stdout, bitrow, width, 0);
+            break;
+        case EOF:
+            pm_error("premature EOF");
+            break;
+        default:
+            pm_error("bad format");
+        }
+    }
 
-    FILE *ifp;
-    register bit *bitrow, *bP;
-    int rows, cols, row, col, charcount;
-    unsigned char *data, mask;
+    pbm_freerow_packed(bitrow);
 
+    while (! feof(ifP) && getc(ifP) != '\\') {};  /* scan for \enddata */
 
-    pbm_init ( &argc, argv );
+    if (fscanf(ifP, "enddata{raster,%d", &discardid) != 1
+        || getc(ifP) != '}' || getc(ifP) != '\n')
+        pm_error("missing end-of-object marker");
+}
 
-    if ( argc > 2 )
-        pm_usage( "[raster obj]" );
-    
-    if ( argc == 2 )
-        ifp = pm_openr( argv[1] );
-    else
-        ifp = stdin;
 
-    ReadATKRaster( ifp, &cols, &rows, &data );
 
-    pm_close( ifp );
+int
+main(int argc, const char ** argv) {
 
-    pbm_writepbminit( stdout, cols, rows, 0 );
-    bitrow = pbm_allocrow( cols );
+    FILE * ifP;
 
-    for ( row = 0; row < rows; ++row )
-    {
-        charcount = 0;
-        mask = 0x80;
-        for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
-        {
-            if ( charcount >= 8 )
-            {
-                ++data;
-                charcount = 0;
-                mask = 0x80;
-            }
-            *bP = ( *data & mask ) ? PBM_BLACK : PBM_WHITE;
-            ++charcount;
-            mask >>= 1;
-        }
-        ++data;
-        pbm_writepbmrow( stdout, bitrow, cols, 0 );
+    pm_proginit(&argc, argv);
+
+    if (argc-1 < 1)
+        ifP = stdin;
+    else {
+        ifP = pm_openr(argv[1]);
+
+        if (argc-1 > 1)
+            pm_error("Too many arguments.  The only possible argument is "
+                     "the input file name");
     }
 
-    pm_close( stdout );
-    exit( 0 );
-}
+    ReadATKRaster(ifP);
+
+    pm_close(ifP);
 
+    pm_close(stdout);
+
+    return 0;
+}
diff --git a/converter/pbm/brushtopbm.c b/converter/pbm/brushtopbm.c
index 0cffaa4d..ebd817be 100644
--- a/converter/pbm/brushtopbm.c
+++ b/converter/pbm/brushtopbm.c
@@ -1,4 +1,4 @@
-/* brushtopbm.c - read a doodle brush file and write a portable bitmap
+/* brushtopbm.c - read a doodle brush file and write a PBM image
 **
 ** Copyright (C) 1988 by Jef Poskanzer.
 **
@@ -12,96 +12,96 @@
 
 #include "pbm.h"
 
-static void getinit ARGS(( FILE* file, int* colsP, int* rowsP ));
-static bit getbit ARGS(( FILE* file ));
+#define HEADERSIZE 16   /* 16 is just a guess at the header size */
 
-int
-main( argc, argv )
-    int argc;
-    char* argv[];
-    {
-    FILE* ifp;
-    bit* bitrow;
-    register bit* bP;
-    int rows, cols, padright, row, col;
-
-
-    pbm_init( &argc, argv );
-
-    if ( argc > 2 )
-	pm_usage( "[brushfile]" );
-
-    if ( argc == 2 )
-	ifp = pm_openr( argv[1] );
-    else
-	ifp = stdin;
-
-    getinit( ifp, &cols, &rows );
-
-    pbm_writepbminit( stdout, cols, rows, 0 );
-    bitrow = pbm_allocrow( cols );
-
-    /* Compute padding to round cols up to the next multiple of 16. */
-    padright = ( ( cols + 15 ) / 16 ) * 16 - cols;
-
-    for ( row = 0; row < rows; ++row )
-	{
-	/* Get data. */
-        for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
-	    *bP = getbit( ifp );
-	/* Discard line padding. */
-        for ( col = 0; col < padright; ++col )
-	    (void) getbit( ifp );
-	/* Write row. */
-	pbm_writepbmrow( stdout, bitrow, cols, 0 );
-	}
-
-    pm_close( ifp );
-    pm_close( stdout );
-    
-    exit( 0 );
-    }
 
 
-static int item, bitsperitem, bitshift;
+static void
+getinit(FILE *         const ifP,
+        unsigned int * const colsP,
+        unsigned int * const rowsP) {
+
+    unsigned char header[HEADERSIZE];
+    size_t bytesRead;
+
+    bytesRead = fread(header, sizeof(header), 1, ifP);
+    if (bytesRead !=1)
+        pm_error("Error reading header");   
+
+    if (header[0] != 1)
+        pm_error("bad magic number 1");
+    if (header[1] != 0)
+        pm_error("bad magic number 2");
+
+    *colsP =  (header[2] << 8) + header[3];  /* Max 65535 */
+    *rowsP =  (header[4] << 8) + header[5];  /* Max 65535 */
+}
+
+
 
 static void
-getinit( file, colsP, rowsP )
-    FILE* file;
-    int* colsP;
-    int* rowsP;
-    {
-    int i;
-
-    if ( getc( file ) != 1 )
-	pm_error( "bad magic number 1" );
-    if ( getc( file ) != 0 )
-	pm_error( "bad magic number 2" );
-    *colsP = getc( file ) << 8;
-    *colsP += getc( file );
-    *rowsP = getc( file ) << 8;
-    *rowsP += getc( file );
-    bitsperitem = 8;
-
-    /* Junk rest of header. */
-    for ( i = 0; i < 10; ++i )  /* 10 is just a guess at the header size */
-	(void) getc( file );
-    }
+validateEof(FILE * const ifP) {
+
+    int rc;
+    rc = getc(ifP);
+    if (rc != EOF)
+        pm_message("Extraneous data at end of file");
+}
+
+
+/*
+   The routine for converting the raster closely resembles the pbm
+   case of pnminvert.  Input is padded up to 16 bit border.
+   afu December 2013
+ */
+
+
 
-static bit
-getbit( file )
-    FILE* file;
-    {
-    bit b;
-
-    if ( bitsperitem == 8 )
-	{
-	item = getc( file );
-	bitsperitem = 0;
-	bitshift = 7;
-	}
-    ++bitsperitem;
-    b = ( ( item >> bitshift) & 1 ) ? PBM_WHITE : PBM_BLACK;
-    --bitshift;
-    return b;
+int
+main(int argc, const char ** argv)  {
+
+    FILE * ifP;
+    bit * bitrow;
+    unsigned int rows, cols, row;
+
+    pm_proginit(&argc, argv);
+
+    if (argc-1 > 0) {
+        ifP = pm_openr(argv[1]);
+        if (argc-1 > 1)
+            pm_error("Too many arguments (%u).  "
+                     "The only argument is the brush file name.", argc-1);
+    } else
+        ifP = stdin;
+
+    getinit(ifP, &cols, &rows);
+
+    pbm_writepbminit(stdout, cols, rows, 0);
+
+    bitrow = pbm_allocrow_packed(cols + 16);
+
+    for (row = 0; row < rows; ++row) {
+        unsigned int const inRowBytes = ((cols + 15) / 16) * 2;
+        unsigned int i;
+        size_t bytesRead;
+
+        bytesRead = fread (bitrow, 1, inRowBytes, ifP); 
+        if (bytesRead != inRowBytes)
+            pm_error("Error reading a row of data from brushfile");
+
+        for (i = 0; i < inRowBytes; ++i)
+            bitrow[i] = ~bitrow[i];
+
+        /* Clean off remainder of fractional last character */
+        pbm_cleanrowend_packed(bitrow, cols);
+
+        pbm_writepbmrow_packed(stdout, bitrow, cols, 0);
     }
+
+    validateEof(ifP);
+
+    pm_close(ifP);
+    pm_close(stdout);
+    
+    return 0;
+}
diff --git a/converter/pbm/cistopbm.c b/converter/pbm/cistopbm.c
new file mode 100644
index 00000000..591e2aa5
--- /dev/null
+++ b/converter/pbm/cistopbm.c
@@ -0,0 +1,180 @@
+/*
+ *  cistopbm: Convert images in the CompuServe RLE format to PBM
+ *  Copyright (C) 2009  John Elliott
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pbm.h"
+
+
+static void syntax(const char *prog)
+{
+        pm_usage(" { options } { input }\n\n"
+                 "Input file should be in CompuServe RLE format.\n"
+                 "Output file will be in PBM format.\n"
+                 "Options:\n"
+                 "-i, --inverse: Reverse black and white.\n"
+                 "--:            End of options\n\n"
+"cistopbm v1.01, Copyright 2009 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"
+                 );
+}
+
+int main(int argc, const char **argv)
+{
+    FILE *ifP;
+    int c[3];
+    int inoptions = 1;
+    int n, x, y;
+    int bw = PBM_BLACK;     /* Default colouring is white on black */
+    const char *inpname = NULL;
+    int height, width;
+    bit **bits;
+
+    pm_proginit(&argc, argv);
+
+    for (n = 1; n < argc; n++)
+    {
+        if (!strcmp(argv[n], "--"))
+        {
+            inoptions = 0;
+            continue;
+        }
+        if (inoptions)
+        {
+            if (pm_keymatch(argv[n], "-h", 2) ||
+                pm_keymatch(argv[n], "-H", 2) ||
+                pm_keymatch(argv[n], "--help", 6))
+            {
+                syntax(argv[0]);
+                return EXIT_SUCCESS;
+            }
+            if (pm_keymatch(argv[n], "-i", 2) ||
+                pm_keymatch(argv[n], "-I", 2) ||
+                pm_keymatch(argv[n], "--inverse", 9))
+            {
+                bw ^= (PBM_WHITE ^ PBM_BLACK);
+                continue;
+            }
+            if (argv[n][0] == '-' && argv[n][1] != 0)
+            {
+                pm_message("Unknown option: %s", argv[n]);
+                syntax(argv[0]);
+                return EXIT_FAILURE;
+            }
+        }
+
+        if (inpname == NULL) inpname = argv[n];
+        else { syntax(argv[0]); return EXIT_FAILURE; }
+    }
+    if (inpname == NULL) inpname = "-";
+    ifP  = pm_openr(inpname);
+
+    /* There may be junk before the magic number. If so, skip it. */
+    x = 0;
+    c[0] = c[1] = c[2] = EOF;
+
+    /* Read until the array c[] holds the magic number. */
+    do
+    {
+        c[0] = c[1];
+        c[1] = c[2];
+        c[2] = fgetc(ifP);
+
+        /* If character read was EOF, end of file was reached and magic number
+         * not found.
+         */
+        if (c[2] == EOF)
+        {
+            pm_error("Input file is not in CompuServe RLE format");
+        }
+        ++x;
+    } while (c[0] != 0x1B || c[1] != 0x47);
+
+    /* x = number of bytes read. Should be 3 if signature is at the start */
+    if (x > 3)
+    {
+        pm_message("Warning: %d bytes of junk skipped before image",
+                   x - 3);
+    }
+    /* Parse the resolution */
+    switch(c[2])
+    {
+    case 0x48:      height = 192; width = 256; break;
+    case 0x4D:      height =  96; width = 128; break;
+    default:        pm_error("Unknown resolution 0x%02x", c[2]);
+        break;
+    }
+    /* Convert the data */
+    bits = pbm_allocarray(width, height);
+    x = y = 0;
+    do
+    {
+        c[0] = fgetc(ifP);
+
+        /* Stop if we hit EOF or Escape */
+        if (c[0] == EOF)  break;        /* EOF */
+        if (c[0] == 0x1B) break;        /* End of graphics */
+        /* Other non-printing characters are ignored; some files contain a
+         * BEL
+         */
+        if (c[0] < 0x20)  continue;
+
+        /* Each character gives the number of pixels to draw in the appropriate
+         * colour.
+         */
+        for (n = 0x20; n < c[0]; n++)
+        {
+            if (x < width && y < height) bits[y][x] = bw;
+            x++;
+            /* Wrap at end of line */
+            if (x >= width)
+            {
+                x = 0;
+                y++;
+            }
+        }
+        /* And toggle colours */
+        bw ^= (PBM_WHITE ^ PBM_BLACK);
+    }
+    while (1);
+
+    /* See if the end-graphics signature (ESC G N) is present. */
+    c[1] = EOF;
+    if (c[0] == 0x1B)
+    {
+        c[1] = fgetc(ifP);
+        c[2] = fgetc(ifP);
+    }
+    if (c[0] != 0x1B || c[1] != 0x47 || c[2] != 0x4E)
+    {
+        pm_message("Warning: End-graphics signature not found");
+    }
+    /* See if we decoded the right number of pixels */
+    if (x != 0 || y != height)
+    {
+        pm_message("Warning: %d pixels found, should be %d",
+                   y * width + x, width * height);
+    }
+    pbm_writepbm(stdout, bits, width, height, 0);
+    pm_close(ifP);
+    return 0;       
+}
diff --git a/converter/pbm/cmuwm.h b/converter/pbm/cmuwm.h
deleted file mode 100644
index e667f25e..00000000
--- a/converter/pbm/cmuwm.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/* cmuwm.h - definitions for the CMU window manager format
-*/
-
-#ifndef CMUWM_H_INCLUDED
-#define CMUWM_H_INCLUDED
-
-struct cmuwm_header
-    {
-    long magic;
-    long width;
-    long height;
-    short depth;
-    };
-
-#define CMUWM_MAGIC 0xf10040bbL
-
-#endif
diff --git a/converter/pbm/cmuwmtopbm.c b/converter/pbm/cmuwmtopbm.c
index eabff40c..ccf8cfc9 100644
--- a/converter/pbm/cmuwmtopbm.c
+++ b/converter/pbm/cmuwmtopbm.c
@@ -20,9 +20,17 @@
 
 
 #include "pbm.h"
-#include "cmuwm.h"
 
+/*--------------------------
+  CMUWN Header format:
 
+  32 bit const magic = 0xf10040bb ;
+  32 bit int   width;
+  32 bit int   height;
+  16 bit int   depth;
+
+  values are big-endian.
+--------------------------*/
 
 static void
 readCmuwmHeader(FILE *         const ifP,
@@ -32,6 +40,7 @@ readCmuwmHeader(FILE *         const ifP,
 
     const char * const initReadError =
         "CMU window manager header EOF / read error";
+    uint32_t const cmuwmMagic = 0xf10040bb;
 
     long l;
     short s;
@@ -39,20 +48,20 @@ readCmuwmHeader(FILE *         const ifP,
 
     rc = pm_readbiglong(ifP, &l);
     if (rc == -1 )
-        pm_error(initReadError);
-    if ((uint32_t)l != CMUWM_MAGIC)
+        pm_error("%s", initReadError);
+    if ((uint32_t)l != cmuwmMagic)
         pm_error("bad magic number in CMU window manager file");
     rc = pm_readbiglong(ifP, &l);
     if (rc == -1)
-        pm_error(initReadError);
+        pm_error("%s", initReadError);
     *colsP = l;
     rc = pm_readbiglong(ifP, &l);
     if (rc == -1 )
-        pm_error(initReadError);
+        pm_error("%s", initReadError);
     *rowsP = l;
     rc = pm_readbigshort(ifP, &s);
     if (rc == -1)
-        pm_error(initReadError);
+        pm_error("%s", initReadError);
     *depthP = s;
 }
 
diff --git a/converter/pbm/escp2topbm.c b/converter/pbm/escp2topbm.c
index 28296da9..632e6345 100644
--- a/converter/pbm/escp2topbm.c
+++ b/converter/pbm/escp2topbm.c
@@ -14,65 +14,266 @@
 ** copyright notice and this permission notice appear in supporting
 ** documentation.  This software is provided "as is" without express or
 ** implied warranty.
+
+** Major changes were made in July 2015 by Akira Urushibata.
+** Most notably the output functions were rewritten.
+** The -plain option is honored as in other programs.
+
+*   Implementation note (July 2015)
+*
+*   The input file does not have a global header.  Image data is divided
+*   into stripes (or data blocks).   Each stripe has a header with
+*   local values for width, height, horizontal/vertical resolution
+*   and compression mode.
+*
+*   We calculate the global height by adding up the local (stripe)
+*   height values, which may vary.
+*
+*   The width value in the first stripe is used throughout; if any
+*   subsequent stripe reports a different value we abort.
+*
+*   We ignore the resolution fields.  Changes in compression mode
+*   are tolerated; they pose no problem.
+*
+*   The official manual says resolution changes within an image are
+*   not allowed.  It does not mention whether changes in stripe height or
+*   width values should be allowed.
+*
+*   A different implementation approach would be to write temporary
+*   PBM files for each stripe and concatenate them at the final stage
+*   with a system call to "pnmcat -tb".  This method has the advantage
+*   of being capable of handling variations in width.
 */
 
-#include <string.h>
 
-#include "pbm.h"
+#include <stdbool.h>
+
 #include "mallocvar.h"
+#include "pbm.h"
+
+#define ESC 033
+
+
+
+static int
+huntEsc(FILE * const ifP) {
+/*-----------------------------------------------------------------------------
+  Hunt for valid start of image stripe in input.
+
+  Return values:
+    ESC: start of image stripe (data block)
+    EOF: end of file
+    0: any other char or sequence
+-----------------------------------------------------------------------------*/
+    int const ch1 = getc(ifP);
+
+    switch (ch1) {
+    case EOF: return EOF;
+    case ESC: {
+        int const ch2 = getc(ifP);
+
+        switch (ch2) {
+        case EOF: return EOF;
+        case '.': return ESC;
+        default:  return 0;
+        }
+    } break;
+    default: return 0;
+    }
+}
+
+
+
+static unsigned char
+readChar(FILE * const ifP) {
+
+    int const ch = getc(ifP);
+
+    if (ch == EOF)
+        pm_error("EOF encountered while reading image data.");
+
+    return (unsigned char) ch;
+}
+
+
+
+static void       
+readStripeHeader(unsigned int * const widthThisStripeP,
+                 unsigned int * const rowsThisStripeP,
+                 unsigned int * const compressionP,
+                 FILE *         const ifP) {
+
+    unsigned char stripeHeader[6];
+    unsigned int widthThisStripe, rowsThisStripe;
+    unsigned int compression;
+
+    if (fread(stripeHeader, sizeof(stripeHeader), 1, ifP) != 1)
+        pm_error("Error reading image data.");
+
+    compression     = stripeHeader[0];
+    /* verticalResolution   = stripeHeader[1]; */
+    /* horizontalResolution = stripeHeader[2]; */
+    rowsThisStripe  = stripeHeader[3];  
+    widthThisStripe = stripeHeader[5] * 256 + stripeHeader[4];
+
+    if (widthThisStripe == 0 || rowsThisStripe == 0)
+        pm_error("Error: Abnormal value in data block header:  "
+                 "Says stripe has zero width or height");
+
+    if (compression != 0 && compression != 1)
+        pm_error("Error: Unknown compression mode %u", compression);
+
+    *widthThisStripeP = widthThisStripe;
+    *rowsThisStripeP  = rowsThisStripe;
+    *compressionP     = compression;
+}
+
+
 
 /* RLE decoder */
-static unsigned int 
-dec_epson_rle(unsigned        const int k, 
-              unsigned        const char * in, 
-              unsigned char * const out) {
+static void
+decEpsonRLE(unsigned int    const blockSize, 
+            unsigned char * const outBuffer,
+            FILE *          const ifP) {
 
-    unsigned int i;
-    unsigned int pos;
     unsigned int dpos;
 
-    pos = 0;  /* initial value */
-    dpos = 0; /* initial value */
+    for (dpos = 0; dpos < blockSize; ) {
+        unsigned char const flag = readChar(ifP);
 
-    while (dpos < k) {
-        if (in[pos] < 128) {
-            for (i = 0; i < in[pos] + 1; ++i)
-                out[dpos+i] = in[pos + i + 1];     
+        if (flag < 128) {
             /* copy through */
-            pos += i + 1;
+
+            unsigned int const nonrunLength = flag + 1;
+
+            unsigned int i;
+
+            for (i = 0; i < nonrunLength; ++i)
+                outBuffer[dpos+i] = readChar(ifP);
+
+            dpos += nonrunLength;
+        } else if (flag == 128) {
+            pm_message("Code 128 detected in compressed input data: ignored");
         } else {
-            for (i = 0; i < 257 - in[pos]; ++i)
-                out[dpos + i] = in[pos + 1];  
             /* inflate this run */
-            pos += 2;
+
+            unsigned int const runLength = 257 - flag;
+            unsigned char const repeatChar = readChar( ifP );
+
+            unsigned int i;
+
+            for (i = 0; i < runLength; ++i)
+                outBuffer[dpos + i] = repeatChar;  
+            dpos += runLength;
         }
-        dpos += i;
     }
-    if(dpos > k)
-      pm_error("Corrupt compressed block"); 
-    return pos;        /* return number of treated input bytes */
+    if (dpos != blockSize)
+      pm_error("Corruption detected in compressed input data");
 }
 
 
 
-int
-main(int    argc,
-     char * argv[]) {
+static void
+processStripeRaster(unsigned char ** const bitarray,
+                    unsigned int     const rowsThisStripe,
+                    unsigned int     const width,
+                    unsigned int     const compression,
+                    FILE *           const ifP,
+                    unsigned int *   const rowIdxP) {
+         
+    unsigned int const initialRowIdx = *rowIdxP;
+    unsigned int const widthInBytes = pbm_packed_bytes(width);
+    unsigned int const blockSize = rowsThisStripe * widthInBytes;
+    unsigned int const margin = compression==1 ? 256 : 0;
+
+    unsigned char * imageBuffer;
+    unsigned int i;
+    unsigned int rowIdx;
 
-    unsigned int const size = 4096; /* arbitrary value */
+    /* We allocate a new buffer each time this function is called.  Add some
+       margin to the buffer for compressed mode to cope with overruns caused
+       by corrupt input data.
+    */
+
+    MALLOCARRAY(imageBuffer, blockSize + margin);
+
+    if (imageBuffer == NULL)
+        pm_error("Failed to allocate buffer for a block of size %u",
+                 blockSize);
+
+    if (compression == 0) {
+        if (fread(imageBuffer, blockSize, 1, ifP) != 1)
+            pm_error("Error reading image data");
+    } else /* compression == 1 */
+        decEpsonRLE(blockSize, imageBuffer, ifP);
+
+    /* Hand over image data to output by pointer assignment */
+    for (i = 0, rowIdx = initialRowIdx; i < rowsThisStripe; ++i)
+        bitarray[rowIdx++] = &imageBuffer[i * widthInBytes];
+
+    *rowIdxP = rowIdx;
+}
 
-    FILE *ifP;
-    unsigned int i, len, pos, opos, width, height;
-    unsigned char *input, *output;
-    const char * fileName;
 
-    pbm_init(&argc, argv);
 
-    MALLOCARRAY(input, size);
-    MALLOCARRAY(output, size);
-    
-    if (input == NULL || output == NULL)
-        pm_error("Cannot allocate memory");
+static void
+expandBitarray(unsigned char *** const bitarrayP,
+               unsigned int   *  const bitarraySizeP) {
+
+    unsigned int const heightIncrement = 5120;
+    unsigned int const heightMax = 5120 * 200;
+        /* 5120 rows is sufficient for US legal at 360 DPI */
+
+    *bitarraySizeP += heightIncrement;
+    if (*bitarraySizeP > heightMax)
+        pm_error("Image too tall");
+    else
+        REALLOCARRAY_NOFAIL(*bitarrayP, *bitarraySizeP); 
+}
+
+
+
+static void
+writePbmImage(unsigned char ** const bitarray,
+              unsigned int     const width,
+              unsigned int     const height) {
+
+    unsigned int row;
+
+    if (height == 0)
+        pm_error("No image");
+
+    pbm_writepbminit(stdout, width, height, 0);
+ 
+    for (row = 0; row < height; ++row) {
+        pbm_cleanrowend_packed(bitarray[row], width);
+        pbm_writepbmrow_packed(stdout, bitarray[row], width, 0);
+    }
+}
+
+
+
+int
+main(int          argc,
+     const char * argv[]) {
+
+    FILE * ifP;
+    unsigned int width;
+        /* Width of the image, or zero to mean width is not yet known.
+           (We get the width from the first stripe in the input; until
+           we've seen that stripe, we don't know the width)
+        */
+    unsigned int height;
+        /* Height of the image as seen so far.  (We process a stripe at a
+           time, increasing this value as we go).
+        */
+    unsigned int rowIdx;
+    unsigned char ** bitarray;
+    unsigned int bitarraySize;
+    const char * fileName;
+    bool eof;
+
+    pm_proginit(&argc, argv);
 
     if (argc-1 > 1)
         pm_error("Too many arguments (%u).  Only argument is filename.",
@@ -85,69 +286,64 @@ main(int    argc,
 
     ifP = pm_openr(fileName);
 
-    /* read the whole file */
-    len = 0;  /* initial value */
-    for (i = 0; !feof(ifP); ++i) {
-        size_t bytesRead;
-        REALLOCARRAY(input, (i+1) * size);
-        if (input == NULL)
-            pm_error("Cannot allocate memory");
-        bytesRead = fread(input + i * size, 1, size, ifP);
-        len += bytesRead;
-    }
+    /* Initialize bitarray */
+    bitarray = NULL;  bitarraySize = 0;
+    expandBitarray(&bitarray, &bitarraySize);
 
-    /* filter out raster data */
-    height = 0;  /* initial value */
-    width  = 0;  /* initial value */
-    pos = 0;     /* initial value */
-    opos = 0;    /* initial value */
-
-    while (pos < len) {
-        /* only ESC sequences are regarded  */
-        if (input[pos] == '\x1b' && input[pos+1] == '.') {
-            unsigned int const k =
-                input[pos+5] * ((input[pos+7] * 256 + input[pos+6] + 7) / 8);
-            unsigned int const margin = 256;
-            if(input[pos+5] == 0)
-                pm_error("Abnormal height value in escape sequence");
-            height += input[pos+5];
-            if(width == 0) /* initialize */
-                width = input[pos+7] * 256 + input[pos+6];
-            else if(width != input[pos+7] * 256 + input[pos+6])
-                pm_error("Abnormal width value in escape sequence");
-
-            REALLOCARRAY(output, opos + k + margin);
-            if (output == NULL)
-                pm_error("Cannot allocate memory");
-
-            switch (input[pos+2]) {
-            case 0:
-                /* copy the data block */
-                memcpy(output + opos, input + pos + 8, k);        
-                pos += k + 8;
-                opos += k;
-                break;
-            case 1: {
-                /* inflate the data block */
-                unsigned int l;
-                l = dec_epson_rle(k,input+pos+8,output+opos);  
-                pos += l + 8;
-                opos += k;
-            }
-                break;
-            default:
-                pm_error("unknown compression mode");
-                break;
+    for (eof = false, width = 0, height = 0, rowIdx = 0; !eof; ) {
+        int const r = huntEsc(ifP);
+
+        if (r == EOF)
+            eof = true;
+        else {
+            if (r == ESC) {
+                unsigned int compression;
+                unsigned int rowsThisStripe;
+                unsigned int widthThisStripe;
+            
+                readStripeHeader(&widthThisStripe, &rowsThisStripe,
+                                 &compression, ifP);
+
+                if (rowsThisStripe == 0)
+                    pm_error("Abnormal data block height value: 0");
+                else if (rowsThisStripe != 24 && rowsThisStripe != 8 &&
+                         rowsThisStripe != 1) {
+                    /* The official Epson manual says valid values are 1, 8,
+                       24 but we just print a warning message and continue if
+                       other values are detected.
+                    */ 
+                    pm_message("Abnormal data block height value: %u "
+                               "(ignoring)",
+                               rowsThisStripe);
+                }
+                if (width == 0) {
+                    /* Get width from 1st stripe header */
+                    width = widthThisStripe;
+                } else if (width != widthThisStripe) {
+                    /* width change not allowed */
+                    pm_error("Error: Width changed in middle of image "
+                             "from %u to %u",
+                             width, widthThisStripe);
+                }
+                height += rowsThisStripe;
+                if (height > bitarraySize)
+                    expandBitarray(&bitarray, &bitarraySize);
+
+                processStripeRaster(bitarray, rowsThisStripe, width,
+                                    compression, ifP, &rowIdx);
+            } else {
+                /* r != ESC; do nothing */
             }
         }
-        else
-            ++pos;      /* skip bytes outside the ESCX sequence */
     }
 
-    pbm_writepbminit(stdout, width, height, 0);
-    fwrite(output, opos, 1, stdout);
-    free(input); free(output);
-    fclose(stdout); fclose(ifP);
+    writePbmImage(bitarray, width, height);
+
+    fclose(stdout);
+    fclose(ifP);
 
     return 0;
 }
+
+
+
diff --git a/converter/pbm/g3topbm.c b/converter/pbm/g3topbm.c
index 54f1f577..fcac1981 100644
--- a/converter/pbm/g3topbm.c
+++ b/converter/pbm/g3topbm.c
@@ -97,7 +97,7 @@ parseCommandLine(int argc, char ** const argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We may have parms that are negative numbers */
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (widthSpec && paper_sizeSpec)
@@ -169,7 +169,7 @@ readBit(struct bitStream * const bitStreamP,
     if ((bitStreamP->shbit & 0xff) == 0) {
         bitStreamP->shdata = getc(bitStreamP->fileP);
         if (bitStreamP->shdata == EOF)
-            asprintfN(errorP, "EOF or error reading file");
+            pm_asprintf(errorP, "EOF or error reading file");
         else {
             bitStreamP->shbit = 0x80;
             if ( bitStreamP->reversebits )
@@ -195,6 +195,8 @@ readBitAndDetectEol(struct bitStream * const bitStreamP,
 /*----------------------------------------------------------------------------
    Same as readBit(), but iff the bit read is the final bit of an EOL
    mark, return *eolP == TRUE.
+
+   An EOL mark is 11 zero bits followed by a one.
 -----------------------------------------------------------------------------*/
     readBit(bitStreamP, bitP, errorP);
     if (!*errorP) {
@@ -265,19 +267,19 @@ addtohash(g3TableEntry *     hash[],
 
 
 
-static g3TableEntry*
+static g3TableEntry *
 hashfind(g3TableEntry *       hash[], 
-         int          const length, 
-         int          const code, 
-         int          const a, 
-         int          const b) {
+         int            const length, 
+         int            const code, 
+         int            const a, 
+         int            const b) {
 
     unsigned int pos;
     g3TableEntry * te;
 
     pos = ((length + a) * (code + b)) % HASHSIZE;
     te = hash[pos];
-    return ((te && te->length == length && te->code == code) ? te : 0);
+    return ((te && te->length == length && te->code == code) ? te : NULL);
 }
 
 
@@ -316,7 +318,13 @@ static g3TableEntry *
 g3code(unsigned int const curcode,
        unsigned int const curlen,
        bit          const color) {
+/*----------------------------------------------------------------------------
+   Return the position in the code tables mtable and ttable of the
+   G3 code which is the 'curlen' bits long with value '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;
 
     switch (color) {
@@ -379,7 +387,11 @@ processG3Code(const g3TableEntry * const teP,
               unsigned int *       const colP,
               bit *                const colorP,
               unsigned int *       const countP) {
-              
+/*----------------------------------------------------------------------------
+   'teP' is a pointer into the mtable/ttable.  Note that the thing it points
+   to is irrelevant to us; it is only the position in the table that
+   matters.
+-----------------------------------------------------------------------------*/
     enum g3tableId const teId =
         (teP > mtable ? 2 : 0) + (teP - ttable) % 2;
 
@@ -395,17 +407,17 @@ processG3Code(const g3TableEntry * const teP,
     switch (teId) {
     case TERMWHITE:
     case TERMBLACK: {
-        unsigned int runLengthSoFar;
+        unsigned int totalRunLength;
         unsigned int col;
         
         col = *colP;
-        runLengthSoFar = MIN(*countP + teCount, MAXCOLS - col);
+        totalRunLength = MIN(*countP + teCount, MAXCOLS - col);
 
-        if (runLengthSoFar > 0) {
+        if (totalRunLength > 0) {
             if (*colorP == PBM_BLACK)
-                writeBlackBitSpan(packedBitrow, runLengthSoFar, col);
+                writeBlackBitSpan(packedBitrow, totalRunLength, col);
             /* else : Row was initialized to white, so we just skip */
-            col += runLengthSoFar;
+            col += totalRunLength;
         }
         *colorP = !*colorP;
         *countP = 0;
@@ -428,12 +440,12 @@ formatBadCodeException(const char ** const exceptionP,
                        unsigned int  const curlen,
                        unsigned int  const curcode) {
 
-    asprintfN(exceptionP,
-        "bad code word at Column %u.  "
-        "No prefix of the %u bits 0x%x matches any recognized "
-        "code word and no code words longer than 13 bits are "
-        "defined.  ",
-        col, curlen, curcode);
+    pm_asprintf(exceptionP,
+                "bad code word at Column %u.  "
+                "No prefix of the %u bits 0x%x matches any recognized "
+                "code word and no code words longer than 13 bits are "
+                "defined.  ",
+                col, curlen, curcode);
 }
 
 
@@ -485,8 +497,8 @@ readFaxRow(struct bitStream * const bitStreamP,
 
     while (!done) {
         if (col >= MAXCOLS) {
-            asprintfN(exceptionP, "Line is too long for this program to "
-                      "handle -- longer than %u columns", MAXCOLS);
+            pm_asprintf(exceptionP, "Line is too long for this program to "
+                        "handle -- longer than %u columns", MAXCOLS);
             done = TRUE;
         } else {
             unsigned int bit;
@@ -507,7 +519,7 @@ readFaxRow(struct bitStream * const bitStreamP,
                 done = TRUE;
             else {
                 curcode = (curcode << 1) | bit;
-                curlen++;
+                ++curlen;
             
                 if (curlen > 13) {
                     formatBadCodeException(exceptionP, col, curlen, curcode);
@@ -516,7 +528,8 @@ readFaxRow(struct bitStream * const bitStreamP,
                     const g3TableEntry * const teP =
                         g3code(curcode, curlen, currentColor);
                         /* Address of structure that describes the 
-                           current G3 code
+                           current G3 code.  Null means 'curcode' isn't
+                           a G3 code yet (probably just the beginning of one)
                         */
                     if (teP) {
                         processG3Code(teP, packedBitrow,
@@ -570,7 +583,7 @@ handleRowException(const char * const exception,
                        row, exception);
         else
             pm_error("Problem reading Row %u.  Aborting.  %s", row, exception);
-        strfree(exception);
+        pm_strfree(exception);
     }
 
     if (error) {
@@ -579,7 +592,7 @@ handleRowException(const char * const exception,
                        row, error);
         else
             pm_error("Unable to read Row %u.  Aborting.  %s", row, error);
-        strfree(error);
+        pm_strfree(error);
     }
 }
 
@@ -626,16 +639,16 @@ analyzeLineSize(lineSizeAnalyzer * const analyzerP,
 
     if (analyzerP->expectedLineSize &&
         thisLineSize != analyzerP->expectedLineSize)
-        asprintfN(&error, "Image contains a line of %u pixels.  "
-                  "You specified lines should be %u pixels.",
-                  thisLineSize, analyzerP->expectedLineSize);
+        pm_asprintf(&error, "Image contains a line of %u pixels.  "
+                    "You specified lines should be %u pixels.",
+                    thisLineSize, analyzerP->expectedLineSize);
     else {
         if (analyzerP->maxLineSize && thisLineSize != analyzerP->maxLineSize)
-            asprintfN(&error, "There are at least two different "
-                      "line lengths in this image, "
-                      "%u pixels and %u pixels.  "
-                      "This is a violation of the G3 standard.  ",
-                      thisLineSize, analyzerP->maxLineSize);
+            pm_asprintf(&error, "There are at least two different "
+                        "line lengths in this image, "
+                        "%u pixels and %u pixels.  "
+                        "This is a violation of the G3 standard.  ",
+                        thisLineSize, analyzerP->maxLineSize);
         else
             error = NULL;
     }
@@ -649,7 +662,7 @@ analyzeLineSize(lineSizeAnalyzer * const analyzerP,
         } else
             pm_error("%s", error);
 
-        strfree(error);
+        pm_strfree(error);
     }
     analyzerP->maxLineSize = MAX(thisLineSize, analyzerP->maxLineSize);
 }
@@ -693,8 +706,8 @@ readFax(struct bitStream * const bitStreamP,
         unsigned int lineSize;
 
         if (row >= MAXROWS)
-            asprintfN(&error, "Image is too tall.  This program can "
-                      "handle at most %u rows", MAXROWS);
+            pm_asprintf(&error, "Image is too tall.  This program can "
+                        "handle at most %u rows", MAXROWS);
         else {
             const char * exception;
 
@@ -714,9 +727,9 @@ readFax(struct bitStream * const bitStreamP,
                     if (stretch) {
                         ++row;
                         if (row >= MAXROWS)
-                            asprintfN(&error, "Image is too tall.  This "
-                                      "program can handle at most %u rows "
-                                      "after stretching", MAXROWS);
+                            pm_asprintf(&error, "Image is too tall.  This "
+                                        "program can handle at most %u rows "
+                                        "after stretching", MAXROWS);
                         else
                             packedBits[row] = packedBits[row-1];
                     }
diff --git a/converter/pbm/icontopbm.c b/converter/pbm/icontopbm.c
deleted file mode 100644
index a0d1bd2b..00000000
--- a/converter/pbm/icontopbm.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/* icontopbm.c - read a Sun icon file and produce a portable bitmap
-**
-** Copyright (C) 1988 by Jef Poskanzer.
-**
-** Permission to use, copy, modify, and distribute this software and its
-** documentation for any purpose and without fee is hereby granted, provided
-** that the above copyright notice appear in all copies and that both that
-** copyright notice and this permission notice appear in supporting
-** documentation.  This software is provided "as is" without express or
-** implied warranty.
-*/
-
-#include <string.h>
-
-#include "nstring.h"
-#include "pbm.h"
-
-/* size in bytes of a bitmap */
-#define BitmapSize(width, height) (((((width) + 15) >> 3) &~ 1) * (height))
-
-static void
-ReadIconFile(FILE *                const file, 
-             int *                 const widthP, 
-             int *                 const heightP, 
-             short unsigned int ** const dataP) {
-
-    char variable[80+1];
-    int ch;
-    int status, value, i, data_length, gotsome;
-
-    gotsome = 0;
-    *widthP = *heightP = -1;
-    for ( ; ; )
-    {
-        while ( ( ch = getc( file ) ) == ',' || ch == '\n' || ch == '\t' ||
-                ch == ' ' )
-            ;
-        for ( i = 0;
-              ch != '=' && ch != ',' && ch != '\n' && ch != '\t' && 
-                  ch != ' ' && (i < (sizeof(variable) - 1));
-              i++ )
-        {
-            variable[i] = ch;
-            if ((ch = getc( file )) == EOF)
-                pm_error( "invalid input file -- premature EOF" );
-        }
-        variable[i] = '\0';
-
-        if ( streq( variable, "*/" )&& gotsome )
-            break;
-
-        if ( fscanf( file, "%d", &value ) != 1 )
-            continue;
-
-        if ( streq( variable, "Width" ) )
-        {
-            *widthP = value;
-            gotsome = 1;
-        }
-        else if ( streq( variable, "Height" ) )
-        {
-            *heightP = value;
-            gotsome = 1;
-        }
-        else if ( streq( variable, "Depth" )  )
-        {
-            if ( value != 1 )
-                pm_error( "invalid depth" );
-            gotsome = 1;
-        }
-        else if ( streq( variable, "Format_version" ) )
-        {
-            if ( value != 1 )
-                pm_error( "invalid Format_version" );
-            gotsome = 1;
-        }
-        else if ( streq( variable, "Valid_bits_per_item" ) )
-        {
-            if ( value != 16 )
-                pm_error( "invalid Valid_bits_per_item" );
-            gotsome = 1;
-        }
-    }
-
-    if ( *widthP <= 0 )
-        pm_error( "invalid width (must be positive): %d", *widthP );
-    if ( *heightP <= 0 )
-        pm_error( "invalid height (must be positive): %d", *heightP );
-
-    data_length = BitmapSize( *widthP, *heightP );
-    *dataP = (short unsigned int *) malloc( data_length );
-    if ( *dataP == NULL )
-        pm_error( "out of memory" );
-    data_length /= sizeof( short );
-    
-    for ( i = 0 ; i < data_length; i++ )
-    {
-        if ( i == 0 )
-            status = fscanf( file, " 0x%4hx", *dataP );
-        else
-            status = fscanf( file, ", 0x%4hx", *dataP + i );
-        if ( status != 1 )
-            pm_error( "error 4 scanning bits item" );
-    }
-}
-
-
-
-int
-main(int  argc, char ** argv) {
-
-    FILE* ifp;
-    bit* bitrow;
-    register bit* bP;
-    int rows, cols, row, col, shortcount, mask;
-    short unsigned int * data;
-
-
-    pbm_init( &argc, argv );
-
-    if ( argc > 2 )
-        pm_usage( "[iconfile]" );
-
-    if ( argc == 2 )
-        ifp = pm_openr( argv[1] );
-    else
-        ifp = stdin;
-
-    ReadIconFile( ifp, &cols, &rows, &data );
-
-    pm_close( ifp );
-
-    pbm_writepbminit( stdout, cols, rows, 0 );
-    bitrow = pbm_allocrow( cols );
-
-    for ( row = 0; row < rows; row++ )
-    {
-        shortcount = 0;
-        mask = 0x8000;
-        for ( col = 0, bP = bitrow; col < cols; col++, bP++ )
-        {
-            if ( shortcount >= 16 )
-            {
-                data++;
-                shortcount = 0;
-                mask = 0x8000;
-            }
-            *bP = ( *data & mask ) ? PBM_BLACK : PBM_WHITE;
-            shortcount++;
-            mask = mask >> 1;
-        }
-        data++;
-        pbm_writepbmrow( stdout, bitrow, cols, 0 );
-    }
-
-    pm_close( stdout );
-    exit( 0 );
-}
-
diff --git a/converter/pbm/macp.h b/converter/pbm/macp.h
index 26a720a2..d00dc5c9 100644
--- a/converter/pbm/macp.h
+++ b/converter/pbm/macp.h
@@ -1,12 +1,16 @@
-/* macp.h - header file for MacPaint files
-*/
-
+/*=============================================================================
+                               macp.h
+===============================================================================
+  Information about MacPaint files
+=============================================================================*/
 #ifndef MACP_H_INCLUDED
 #define MACP_H_INCLUDED
 
-#define	HEADER_LENGTH	512
-#define	MAX_LINES	720
-#define	BYTES_WIDE	72
-#define MAX_COLS	576	/* = BYTES_WIDE * 8 */
+#define	MACBIN_HEAD_LEN	128
+#define	MACP_HEAD_LEN	512
+#define	MACP_ROWS	720
+#define	MACP_COLCHARS	72
+#define MACP_COLS	((MACP_COLCHARS) * 8)
+#define MACP_BYTES	((MACP_COLCHARS) * (MACP_ROWS))
 
 #endif
diff --git a/converter/pbm/macptopbm.c b/converter/pbm/macptopbm.c
index f4a341d3..db628b6c 100644
--- a/converter/pbm/macptopbm.c
+++ b/converter/pbm/macptopbm.c
@@ -1,6 +1,8 @@
 /* macptopbm.c - read a MacPaint file and produce a portable bitmap
 **
 ** Copyright (C) 1988 by Jef Poskanzer.
+** Some code of ReadMacPaintFile() is based on the work of
+** Patrick J. Naughton.  (C) 1987, All Rights Reserved.
 **
 ** Permission to use, copy, modify, and distribute this software and its
 ** documentation for any purpose and without fee is hereby granted, provided
@@ -8,133 +10,347 @@
 ** copyright notice and this permission notice appear in supporting
 ** documentation.  This software is provided "as is" without express or
 ** implied warranty.
+
+
+** Apr 2015 afu
+** Changed code style (ANSI-style function definitions, etc.)
+** Added automatic detection of MacBinary header.
+** Added diagnostics for corruptions.
+** Replaced byte-wise operations with bit-wise ones.
 */
 
 #include "pbm.h"
+#include "pm_c_util.h"
 #include "macp.h"
 
-static void ReadMacPaintFile ARGS(( FILE* file, int extraskip, int* scanLineP, unsigned char Pic[MAX_LINES][BYTES_WIDE] ));
 
-static unsigned char Pic[MAX_LINES][BYTES_WIDE];
+
+static bool
+validateMacPaintVersion( const unsigned char * const rBuff,
+                         const int offset ) {
+/*---------------------------------------------------------------------------
+  Macpaint (or PNTG) files have two headers.
+  The 512 byte MacPaint header is mandatory.
+  The newer 128 byte MacBinary header is optional.  If it exists, it comes
+  before the MacPaint header.
+
+  Here we examine the first four bytes of the MacPaint header to get
+  the version number.
+
+  Valid version numbers are 0, 2, 3.
+  We also allow 1.
+-----------------------------------------------------------------------------*/
+
+    bool retval;
+    const unsigned char * const vNum = rBuff + offset;
+
+   if ( ( ( vNum[0] | vNum[1] | vNum[2] ) != 0x00 ) || vNum[3] > 3 )
+        retval = FALSE;
+    else
+        retval = TRUE;
+
+    pm_message("MacPaint version (at offset %u): %02x %02x %02x %02x (%s)",
+               offset, vNum[0], vNum[1], vNum[2], vNum[3],
+               retval == TRUE ? "valid" : "not valid" );
+
+    return( retval );
+}
+
+
+
+static bool
+scanMacBinaryHeader( const unsigned char * rBuff ) {
+/*----------------------------------------------------------------------------
+  We check byte 0 and 1, and then the MacPaint header version assuming it
+  starts at offset 128.
+
+  Byte 0: must be 0x00.
+  Byte 1: (filename length) must be 1-63.
+
+  Other fields that may be of interest:
+
+  Bytes 2 through 63: (Internal Filename)
+    See Apple Charmap for valid characters.
+    Unlike US-Ascii, 8-bit characters (range 0x80 - 0xFF) are valid.
+    0x00-0x1F and 0x7F are control characters.  0x00 appears in some files.
+    Colon ':' (0x3a) should be avoided in Mac environments but in practice
+    does appear.
+
+  Bytes 65 through 68: (File Type)
+    Four Ascii characters.  Should be "PNTG".
+
+  Bytes 82 to 85: (SizeOfDataFork)
+    uint32 value.  It seems this is file size (in bytes) / 256 + N, N <= 4.
+
+  Bytes 100 through 124:
+    Should be all zero if the header is MacBinary I.
+    Defined and used in MacBinary II.
+
+  Bytes 124,125: CRC
+    (MacBinary II only) CRC value of bytes 0 through 123.
+
+  All multi-byte values are big-endian.
+
+  Reference:
+  http://www.fileformat.info/format/macpaint/egff.htm
+  Fully describes the fields.  However, the detection method described
+  does not work very well.
+
+  Also see:
+  http://fileformats.archiveteam.org/wiki/MacPaint
+-----------------------------------------------------------------------------*/
+    bool          foundMacBinaryHeader;
+
+    /* Examine byte 0.  It should be 0x00.  Note that the first
+       byte of a valid MacPaint header should also be 0x00.
+    */
+    if ( rBuff[0] != 0x00 ) {
+        foundMacBinaryHeader = FALSE;
+    }
+
+    /* Examine byte 1, the length of the filename.
+       It should be in the range 1 - 63.
+    */
+    else if( rBuff[1] == 0 || rBuff[1] > 63 ) {
+        foundMacBinaryHeader = FALSE;
+    }
+
+    /* Check the MacPaint header version starting at offset 128. */
+    else if ( validateMacPaintVersion ( rBuff, MACBIN_HEAD_LEN ) == FALSE) {
+        foundMacBinaryHeader = FALSE;
+    }
+    else
+        foundMacBinaryHeader = TRUE;
+
+    if( foundMacBinaryHeader == TRUE)
+      pm_message("Input file contains a MacBinary header "
+                   "followed by a MacPaint header.");
+    else
+      pm_message("Input file does not start with a MacBinary header.");
+
+    return ( foundMacBinaryHeader );
+}
+
+
+
+
+static void
+skipHeader( FILE * const ifP ) {
+/*--------------------------------------------------------------------------
+  Determine whether the MacBinary header exists.
+  If it does, read off the initial 640 (=128 + 512) bytes of the file.
+  If it doesn't, read off 512 bytes.
+
+  In the latter case we check the MacHeader version number, but just issue
+  a warning if the value is invalid.  This is for backward comaptibility.
+---------------------------------------------------------------------------*/
+    unsigned int re;
+    const unsigned int buffsize = MAX( MACBIN_HEAD_LEN, MACP_HEAD_LEN );
+    unsigned char * const rBuff = malloc(buffsize);
+
+    if( rBuff == NULL )
+        pm_error("Out of memory.");
+
+    /* Read 512 bytes.
+       See if MacBinary header exists in the first 128 bytes and
+       the next 4 bytes signal the start of a MacPaint header. */
+    re = fread ( rBuff, MACP_HEAD_LEN, 1, ifP);
+        if (re < 1)
+        pm_error("EOF/error while reading header.");
+
+    if ( scanMacBinaryHeader( rBuff ) == TRUE ) {
+    /* MacBinary header found.  Read another 128 bytes to complete the
+       MacPaint header, but don't conduct any further analysis. */
+        re = fread ( rBuff, MACBIN_HEAD_LEN, 1, ifP);
+            if (re < 1)
+            pm_error("EOF/error while reading MacPaint header.");
+
+    } else {
+    /* MacBinary header not found.  We assume file starts with
+       MacPaint header.   Check MacPaint version but dismiss error. */
+        if (validateMacPaintVersion( rBuff, 0 ) == TRUE)
+          pm_message("Input file starts with valid MacPaint header.");
+        else
+          pm_message("  - Ignoring invalid version number.");
+    }
+    free( rBuff );
+}
+
+
+
+static void
+skipExtraBytes( FILE * const ifP,
+                int    const extraskip) {
+/*--------------------------------------------------------------------------
+  This function exists for backward compatibility.  Its purpose is to
+  manually delete the MacBinary header.
+
+  We check the MacHeader version number, but just issue a warning if the
+  value is invalid.
+---------------------------------------------------------------------------*/
+    unsigned int re;
+    unsigned char * const rBuff = malloc(MAX (extraskip, MACP_HEAD_LEN));
+
+    if( rBuff == NULL )
+        pm_error("Out of memory.");
+
+    re = fread ( rBuff, 1, extraskip, ifP);
+        if (re < extraskip)
+        pm_error("EOF/error while reading off initial %u bytes"
+                     "specified by -extraskip.", extraskip);
+    re = fread ( rBuff, MACP_HEAD_LEN, 1, ifP);
+        if (re < 1)
+        pm_error("EOF/error while reading MacPaint header.");
+
+    /* Check the MacPaint version number.  Dismiss error. */
+    if (validateMacPaintVersion( rBuff, 0 ) == TRUE)
+        pm_message("Input file starts with valid MacPaint header.");
+    else
+        pm_message("  - Ignoring invalid version number.");
+
+    free( rBuff );
+}
+
+
+
+static unsigned char
+readChar( FILE * const ifP ) {
+
+    int const ch = getc( ifP );
+
+    if (ch ==EOF)
+        pm_error("EOF encountered while unpacking image data.");
+
+    /* else */
+        return ((unsigned char) ch);
+}
+
+
+
+
+static void
+ReadMacPaintFile( FILE *  const ifP,
+                  int  * outOfSyncP,
+                  int  * pixelCntP ) {
+/*---------------------------------------------------------------------------
+  Unpack image data.  Compression method is called "Packbits".
+  This run-length encoding scheme has also been adopted by
+  Postscript and TIFF.  See source: converter/other/pnmtops.c
+
+  Unpacked raster array is raw PBM.  No conversion is required.
+
+  One source says flag byte should not be 0xFF (255), but we don't reject
+  the value, for in practice, it is widely used.
+
+  Sequences should never cross row borders.
+  Violations of this rule are recorded in outOfSync.
+
+  Note that pixelCnt counts bytes, not bits, so it is the number of pixels
+  multiplied by 8.  This counter exists to detect corruptions.
+---------------------------------------------------------------------------*/
+    int           pixelCnt   = 0;   /* Initial value */
+    int           outOfSync  = 0;   /* Initial value */
+    unsigned int  flag;             /* Read from input */
+    unsigned int  i;
+    unsigned char * const bitrow = pbm_allocrow_packed(MACP_COLS);
+
+    while ( pixelCnt < MACP_BYTES ) {
+        flag = (unsigned int) readChar( ifP );    /* Flag (count) byte */
+        if ( flag < 0x80 ) {
+            /* Unpack next (flag + 1) chars as is */
+            for ( i = 0; i <= flag; i++ )
+                if( pixelCnt < MACP_BYTES) {
+                  int const colChar = pixelCnt % MACP_COLCHARS;
+                  pixelCnt++;
+                  bitrow[colChar] = readChar( ifP );
+                  if (colChar == MACP_COLCHARS-1)
+                      pbm_writepbmrow_packed( stdout, bitrow, MACP_COLS, 0 );
+                  if (colChar == 0 && i > 0 )
+                      outOfSync++;
+                }
+        }
+        else {
+          /* Repeat next char (2's complement of flagCnt) times */
+            unsigned int  const flagCnt = 256 - flag;
+            unsigned char const ch = readChar( ifP );
+            for ( i = 0; i <= flagCnt; i++ )
+                if( pixelCnt < MACP_BYTES) {
+                  int const colChar = pixelCnt % MACP_COLCHARS;
+                  pixelCnt++;
+                  bitrow[colChar] = ch;
+                  if (colChar == MACP_COLCHARS-1)
+                      pbm_writepbmrow_packed( stdout, bitrow, MACP_COLS, 0 );
+                  if (colChar == 0 && i > 0 )
+                      outOfSync++;
+                }
+        }
+    }
+    pbm_freerow_packed ( bitrow );
+    *outOfSyncP  = outOfSync;
+    *pixelCntP   = pixelCnt;
+}
+
 
 int
-main( argc, argv )
-    int argc;
-    char* argv[];
-    {
-    FILE* ifp;
-    bit* bitrow;
-    int argn, extraskip, scanLine, rows, cols, row, bcol, i;
-    const char* usage = "[-extraskip N] [macpfile]";
+main( int argc, char * argv[])  {
 
+    FILE * ifp;
+    int argn, extraskip;
+    const char * const usage = "[-extraskip N] [macpfile]";
+    int outOfSync;
+    int pixelCnt;
 
     pbm_init( &argc, argv );
 
-    argn = 1;
-    extraskip = 0;
+    argn = 1;      /* initial value */
+    extraskip = 0; /* initial value */
 
     /* Check for flags. */
-    if ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
-	{
-	if ( pm_keymatch( argv[argn], "-extraskip", 2 ) )
-	    {
-	    argn++;
-	    if ( argn == argc || sscanf( argv[argn], "%d", &extraskip ) != 1 )
-		pm_usage( usage );
-	    }
-	else
-	    pm_usage( usage );
-	argn++;
-	}
-
-    if ( argn < argc )
-	{
-	ifp = pm_openr( argv[argn] );
-	argn++;
-	}
+    if ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) {
+        if ( pm_keymatch( argv[argn], "-extraskip", 2 ) ) {
+            argn++;
+            if ( argn == argc || sscanf( argv[argn], "%d", &extraskip ) != 1 )
+                pm_usage( usage );
+        }
+        else
+            pm_usage( usage );
+        argn++;
+    }
+
+    if ( argn < argc ) {
+        ifp = pm_openr( argv[argn] );
+        argn++;
+        }
     else
-	ifp = stdin;
+        ifp = stdin;
 
     if ( argn != argc )
-	pm_usage( usage );
+        pm_usage( usage );
 
-    ReadMacPaintFile( ifp, extraskip, &scanLine, Pic );
+    if ( extraskip > 256 * 1024 )
+        pm_error("-extraskip value too large");
+    else if ( extraskip > 0 )
+        skipExtraBytes( ifp, extraskip);
+    else
+        skipHeader( ifp );
 
+    pbm_writepbminit( stdout, MACP_COLS, MACP_ROWS, 0 );
+
+    ReadMacPaintFile( ifp, &outOfSync, &pixelCnt );
+    /* We may not be at EOF.
+       Macpaint files often have extra bytes after image data. */
     pm_close( ifp );
 
-    cols = BYTES_WIDE * 8;
-    rows = scanLine;
-    pbm_writepbminit( stdout, cols, rows, 0 );
-    bitrow = pbm_allocrow( cols );
+    if ( pixelCnt == 0 )
+        pm_error("No image data.");
+
+    else if ( pixelCnt < MACP_BYTES )
+        pm_error("Compressed image data terminated prematurely.");
 
-    for ( row = 0; row < rows; row++ )
-	{
-	for ( bcol = 0; bcol < BYTES_WIDE; bcol++ )
-	    for ( i = 0; i < 8; i++ )
-		bitrow[bcol * 8 + i] =
-		    ( (Pic[row][bcol] >> (7 - i)) & 1 ) ? PBM_BLACK : PBM_WHITE;
-	pbm_writepbmrow( stdout, bitrow, cols, 0 );
-	}
+    else if ( outOfSync > 0 )
+        pm_message("Warning: Corrupt image data.  %d rows misaligned.",
+                   outOfSync);
 
     pm_close( stdout );
     exit( 0 );
-    }
-
-/*
-** Some of the following routine is:
-**
-**                Copyright 1987 by Patrick J. Naughton
-**                         All Rights Reserved
-** Permission to use, copy, modify, and distribute this software and its
-** documentation for any purpose and without fee is hereby granted,
-** provided that the above copyright notice appear in all copies and that
-** both that copyright notice and this permission notice appear in
-** supporting documentation.
-*/
-
-static void
-ReadMacPaintFile( file, extraskip, scanLineP, Pic )
-    FILE* file;
-    int extraskip;
-    int* scanLineP;
-    unsigned char Pic[MAX_LINES][BYTES_WIDE];
-    {
-    unsigned int i, j, k;
-    unsigned char ch;
-
-    /* Skip over the header. */
-    for ( i = 0; i < extraskip; i++ )
-	getc( file );
-    for ( i = 0; i < HEADER_LENGTH; i++ )
-	getc( file );
-
-    *scanLineP = 0;
-    k = 0;
-
-    while ( *scanLineP < MAX_LINES )
-	{
-	ch = (unsigned char) getc( file );	/* Count byte */
-	i = (unsigned int) ch;
-	if ( ch < 0x80 )
-	    {	/* Unpack next (I+1) chars as is */
-	    for ( j = 0; j <= i; j++ )
-		if ( *scanLineP < MAX_LINES )
-		    {
-		    Pic[*scanLineP][k++] = (unsigned char) getc( file );
-		    if ( ! (k %= BYTES_WIDE) )
-			*scanLineP += 1;
-		    }
-	    }
-	else
-	    {	/* Repeat next char (2's comp I) times */
-	    ch = getc( file );
-	    for ( j = 0; j <= 256 - i; j++ )
-		if ( *scanLineP < MAX_LINES )
-		    {
-		    Pic[*scanLineP][k++] = (unsigned char) ch;
-		    if ( ! (k %= BYTES_WIDE) )
-			*scanLineP += 1;
-		    }
-	    }
-	}
-    }
+}
diff --git a/converter/pbm/pbmto10x.c b/converter/pbm/pbmto10x.c
index f8a38b5d..d040b3ed 100644
--- a/converter/pbm/pbmto10x.c
+++ b/converter/pbm/pbmto10x.c
@@ -12,16 +12,14 @@
 ** Modified to shorten stripes and eliminate blank stripes. Dec 1994.
 */
 
+#include <stdbool.h>
+
 #include "pbm.h"
 #include "mallocvar.h"
 
 #define LOW_RES_ROWS    8       /* printed per pass */
 #define HIGH_RES_ROWS   16      /* printed per pass */
 
-static int  highres = 0;
-static FILE *ifp;
-static int  rows, cols, format;
-
 
 
 static void
@@ -29,8 +27,6 @@ outstripe(char * const stripe,
           char * const sP, 
           int    const reschar) {
 
-    int ncols;
-
     char * p;
 
     p = sP;  /* initial value */
@@ -41,10 +37,14 @@ outstripe(char * const stripe,
             ++p;
             break;
         }
-    ncols = p - stripe;
-    if (ncols > 0) {
-        printf("\033%c%c%c", reschar, ncols % 256, ncols / 256);
-        fwrite(stripe, sizeof(char), ncols, stdout);
+
+    {
+        unsigned int const ncols = p - stripe;
+
+        if (ncols > 0) {
+            printf("\033%c%c%c", reschar, ncols % 256, ncols / 256);
+            fwrite(stripe, sizeof(char), ncols, stdout);
+        }
     }
     putchar('\n');          /* flush buffer */
 }
@@ -52,26 +52,44 @@ outstripe(char * const stripe,
 
 
 static void
-res_60x72(void) {
-    int i, item, npins, row, col;
-    bit *bitrows[LOW_RES_ROWS], *bP[LOW_RES_ROWS];
-    char *stripe, *sP;
+res_60x72(FILE * const ifP,
+          int    const rows,
+          int    const cols,
+          int    const format) {
+
+    int row;
+    unsigned int i;
+    bit * bitrows[LOW_RES_ROWS];
+    char *stripe;
+    char *sP;
 
     MALLOCARRAY(stripe, cols);
     if (stripe == NULL)
         pm_error("Unable to allocate %u bytes for a stripe buffer.",
-                 cols * sizeof(stripe[0]));
+                 (unsigned)(cols * sizeof(stripe[0])));
+
     for (i = 0; i < LOW_RES_ROWS; ++i)
         bitrows[i] = pbm_allocrow(cols);
+
     printf("\033A\010");        /* '\n' = 8/72 */
+
     for (row = 0, sP = stripe; row < rows; row += LOW_RES_ROWS, sP = stripe) {
+        unsigned int col;
+        unsigned int i;
+        unsigned int npins;
+        bit * bP[LOW_RES_ROWS];
+
         if (row + LOW_RES_ROWS <= rows)
             npins = LOW_RES_ROWS;
         else
             npins = rows - row;
+
         for (i = 0; i < npins; ++i)
-            pbm_readpbmrow(ifp, bP[i] = bitrows[i], cols, format);
+            pbm_readpbmrow(ifP, bP[i] = bitrows[i], cols, format);
+
         for (col = 0; col < cols; ++col) {
+            unsigned int item;
+
             item = 0;
             for (i = 0; i < npins; ++i)
                 if (*(bP[i]++) == PBM_BLACK)
@@ -81,32 +99,52 @@ res_60x72(void) {
         outstripe(stripe, sP, 'K');
     }
     printf("\033@");
+
+    for (i = 0; i < LOW_RES_ROWS; ++i)
+        pbm_freerow(bitrows[i]);
+
     free(stripe);
 }
 
 
 
 static void
-res_120x144(void) {
-    int i, pin, item, npins, row, col;
-    bit *bitrows[HIGH_RES_ROWS], *bP[HIGH_RES_ROWS];
-    char *stripe, *sP;
+res_120x144(FILE * const ifP,
+            int    const rows,
+            int    const cols,
+            int    const format) {
+
+    unsigned int i;
+    int row;
+    char *stripe;
+    char * sP;
+    bit * bitrows[HIGH_RES_ROWS];
 
     MALLOCARRAY(stripe, cols);
     if (stripe == NULL)
         pm_error("Unable to allocate %u bytes for a stripe buffer.",
-                 cols * sizeof(stripe[0]));
+                 (unsigned)(cols * sizeof(stripe[0])));
+
     for (i = 0; i < HIGH_RES_ROWS; ++i)
         bitrows[i] = pbm_allocrow(cols);
+
     printf("\0333\001");            /* \n = 1/144" */
+
     for (row = 0, sP = stripe; row < rows; row += HIGH_RES_ROWS, sP = stripe) {
+        unsigned int i;
+        unsigned int col;
+        bit * bP[HIGH_RES_ROWS];
+        unsigned int npins;
+
         if (row + HIGH_RES_ROWS <= rows)
             npins = HIGH_RES_ROWS;
         else
             npins = rows - row;
         for (i = 0; i < npins; ++i)
-            pbm_readpbmrow(ifp, bP[i] = bitrows[i], cols, format);
+            pbm_readpbmrow(ifP, bP[i] = bitrows[i], cols, format);
         for (col = 0; col < cols; ++col) {
+            unsigned int pin;
+            unsigned int item;
             item = 0;
             /* even rows */
             for (pin = i = 0; i < npins; i += 2, ++pin)
@@ -115,8 +153,9 @@ res_120x144(void) {
             *sP++ = item;
         }
         outstripe(stripe, sP, 'L');
-        sP = stripe;
-        for (col = 0; col < cols; ++col) {
+        for (col = 0, sP = stripe; col < cols; ++col) {
+            unsigned int pin;
+            unsigned int item;
             item = 0;
             /* odd rows */
             for (i = 1, pin = 0; i < npins; i += 2, ++pin)
@@ -128,20 +167,29 @@ res_120x144(void) {
         printf("\033J\016");        /* 14/144 down, \n did 1/144 */
     }
     printf("\033@");
+
+    for (i = 0; i < LOW_RES_ROWS; ++i)
+        pbm_freerow(bitrows[i]);
+
     free(stripe);
 }
 
 
 
 int
-main(int argc, char * argv[]) {
+main(int argc, const char ** argv) {
 
     const char * fname;
+    static FILE * ifP;
+    int rows, cols, format;
+
+    bool isHighRes;
 
-    pbm_init( &argc, argv );
+    pm_proginit(&argc, argv);
 
+    isHighRes = false;  /* initial assumption */
     if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'h') {
-        highres = 1;
+        isHighRes = true;
         --argc;
         ++argv;
     }
@@ -152,17 +200,18 @@ main(int argc, char * argv[]) {
     else
         fname = "-";
     
-    ifp = pm_openr(fname);
+    ifP = pm_openr(fname);
 
-    pbm_readpbminit(ifp, &cols, &rows, &format);
+    pbm_readpbminit(ifP, &cols, &rows, &format);
 
-    if (highres)
-        res_120x144();
+    if (isHighRes)
+        res_120x144(ifP, rows, cols, format);
     else
-        res_60x72();
+        res_60x72(ifP, rows, cols, format);
+
+    pm_close(ifP);
 
-    pm_close(ifp);
-    exit(0);
+    return 0;
 }
 
 
diff --git a/converter/pbm/pbmtoascii.c b/converter/pbm/pbmtoascii.c
index 0472f809..976b188f 100644
--- a/converter/pbm/pbmtoascii.c
+++ b/converter/pbm/pbmtoascii.c
@@ -1,4 +1,4 @@
-/* pbmtoascii.c - read a portable bitmap and produce ASCII graphics
+/* pbmtoascii.c - read a PBM image and produce ASCII graphics
 **
 ** Copyright (C) 1988, 1992 by Jef Poskanzer.
 **
@@ -10,8 +10,33 @@
 ** implied warranty.
 */
 
+#include <assert.h>
+#include "mallocvar.h"
 #include "pbm.h"
 
+/*
+  The algorithm is based on describing the 2 or 8 pixels in a cell with a
+  single integer called a signature, which we use as an index into an array to
+  get the character whose glyph best matches those pixels.  The encoding is as
+  follows.  Make a string of bits, with each bit being one pixel of the cell,
+  1 = black, 0 = white.  The order of the string is left to right across the
+  top row, then the next row down, etc.  Considering that string to be a
+  binary cipher, the integer it represents is the signature.
+
+  Example: the 2x4 cell consists of these pixels: (* = black)
+
+      * *
+      *
+
+        *
+  The bit string to represent this is 11100001.  So the signature for this
+  cell is the integer 0xE1 (225).
+
+  You index the array carr2x4 with 0xE1, and get '?' as the character to
+  represent that cell.  (We don't really try very hard to match the shape;
+  it's mostly important to match the density).
+*/
+
 #define SQQ '\''
 #define BSQ '\\'
 
@@ -19,7 +44,7 @@
 **     1
 **     2
 */
-static char carr1x2[4] = {
+static char const carr1x2[4] = {
 /*   0    1    2    3   */
     ' ', '"', 'o', 'M' };
 
@@ -35,47 +60,177 @@ static char carr1x2[4] = {
 #define D06 '&'
 #define D05 '$'
 #define D04 '?'
-static char carr2x4[256] = {
+static char const carr2x4[256] = {
 /*0  1    2   3    4   5    6   7    8   9    A   B    C   D    E   F  */
-' ',SQQ, '`','"', '-',SQQ, SQQ,SQQ, '-','`', '`','`', '-','^', '^','"',/*00-0F*/
-'.',':', ':',':', '|','|', '/',D04, '/','>', '/','>', '~','+', '/','*',/*10-1F*/
-'.',':', ':',':', BSQ,BSQ, '<','<', '|',BSQ, '|',D04, '~',BSQ, '+','*',/*20-2F*/
-'-',':', ':',':', '~',D04, '<','<', '~','>', D04,'>', '=','b', 'd','#',/*30-3F*/
-'.',':', ':',':', ':','!', '/',D04, ':',':', '/',D04, ':',D04, D04,'P',/*40-4F*/
-',','i', '/',D04, '|','|', '|','T', '/',D04, '/','7', 'r','}', '/','P',/*50-5F*/
-',',':', ';',D04, '>',D04, 'S','S', '/',')', '|','7', '>',D05, D05,D06,/*60-6F*/
-'v',D04, D04,D05, '+','}', D05,'F', '/',D05, '/',D06, 'p','D', D06,D07,/*70-7F*/
-'.',':', ':',':', ':',BSQ, ':',D04, ':',BSQ, '!',D04, ':',D04, D04,D05,/*80-8F*/
-BSQ,BSQ, ':',D04, BSQ,'|', '(',D05, '<','%', D04,'Z', '<',D05, D05,D06,/*90-9F*/
-',',BSQ, 'i',D04, BSQ,BSQ, D04,BSQ, '|','|', '|','T', D04,BSQ, '4','9',/*A0-AF*/
-'v',D04, D04,D05, BSQ,BSQ, D05,D06, '+',D05, '{',D06, 'q',D06, D06,D07,/*B0-BF*/
-'_',':', ':',D04, ':',D04, D04,D05, ':',D04, D04,D05, ':',D05, D05,D06,/*C0-CF*/
-BSQ,D04, D04,D05, D04,'L', D05,'[', '<','Z', '/','Z', 'c','k', D06,'R',/*D0-DF*/
-',',D04, D04,D05, '>',BSQ, 'S','S', D04,D05, 'J',']', '>',D06, '1','9',/*E0-EF*/
-'o','b', 'd',D06, 'b','b', D06,'6', 'd',D06, 'd',D07, '#',D07, D07,D08 /*F0-FF*/
-    };
+' ',SQQ, '`','"', '-',SQQ, SQQ,SQQ, '-','`', '`','`', '-','^','^','"',/*00-0F*/
+'.',':', ':',':', '|','|', '/',D04, '/','>', '/','>', '~','+','/','*',/*10-1F*/
+'.',':', ':',':', BSQ,BSQ, '<','<', '|',BSQ, '|',D04, '~',BSQ,'+','*',/*20-2F*/
+'-',':', ':',':', '~',D04, '<','<', '~','>', D04,'>', '=','b','d','#',/*30-3F*/
+'.',':', ':',':', ':','!', '/',D04, ':',':', '/',D04, ':',D04,D04,'P',/*40-4F*/
+',','i', '/',D04, '|','|', '|','T', '/',D04, '/','7', 'r','}','/','P',/*50-5F*/
+',',':', ';',D04, '>',D04, 'S','S', '/',')', '|','7', '>',D05,D05,D06,/*60-6F*/
+'v',D04, D04,D05, '+','}', D05,'F', '/',D05, '/',D06, 'p','D',D06,D07,/*70-7F*/
+'.',':', ':',':', ':',BSQ, ':',D04, ':',BSQ, '!',D04, ':',D04,D04,D05,/*80-8F*/
+BSQ,BSQ, ':',D04, BSQ,'|', '(',D05, '<','%', D04,'Z', '<',D05,D05,D06,/*90-9F*/
+',',BSQ, 'i',D04, BSQ,BSQ, D04,BSQ, '|','|', '|','T', D04,BSQ,'4','9',/*A0-AF*/
+'v',D04, D04,D05, BSQ,BSQ, D05,D06, '+',D05, '{',D06, 'q',D06,D06,D07,/*B0-BF*/
+'_',':', ':',D04, ':',D04, D04,D05, ':',D04, D04,D05, ':',D05,D05,D06,/*C0-CF*/
+BSQ,D04, D04,D05, D04,'L', D05,'[', '<','Z', '/','Z', 'c','k',D06,'R',/*D0-DF*/
+',',D04, D04,D05, '>',BSQ, 'S','S', D04,D05, 'J',']', '>',D06,'1','9',/*E0-EF*/
+'o','b', 'd',D06, 'b','b', D06,'6', 'd',D06, 'd',D07, '#',D07,D07,D08 /*F0-FF*/
+};
 
 
 
-int
-main( argc, argv )
-int argc;
-char* argv[];
+static void
+makeRowOfSigs(FILE *         const ifP,
+              unsigned int   const cols,
+              unsigned int   const rows,
+              int            const format,
+              unsigned int   const cellWidth,
+              unsigned int   const cellHeight,
+              unsigned int   const row,
+              unsigned int * const sig,
+              unsigned int   const ccols) {
+/*----------------------------------------------------------------------------
+   Compute the signatures for every cell in a row.
+
+   Read the pixels from *ifP, which is positioned to the first pixel row
+   of the cell row, which is row number 'row'.  The image dimensions are
+   'cols' x 'rows' pixels.
+
+   Each cell is 'cellWidth' x 'cellHeight'.
+
+   Return the signatures as sig[], which is 'ccols' wide because that's how
+   many cells you get from 'cols' pixels divided into cells 'cellWidth' pixels
+   wide.
+-----------------------------------------------------------------------------*/
+    unsigned int b;
+    unsigned int subrow;  /* row within cell */
+    bit * bitrow;        /* malloc'ed array */
+
+    bitrow = pbm_allocrow(cols);
     {
-    FILE* ifp;
-    int argn, gridx, gridy, rows, cols, format;
-    int ccols, lastcol, row, subrow, subcol;
-    register int col, b;
-    bit* bitrow;
-    register bit* bP;
-    int* sig;
-    register int* sP;
-    char* line;
-    register char* lP;
-    char* carr;
+        unsigned int col;
+        for (col = 0; col < ccols; ++col)
+            sig[col] = 0;
+    }
+
+    b = 0x1;  /* initial value */
+    for (subrow = 0; subrow < cellHeight; ++subrow) {
+        if (row + subrow < rows) {
+            unsigned int subcol;  /* col within cell */
+            pbm_readpbmrow(ifP, bitrow, cols, format);
+            for (subcol = 0; subcol < cellWidth; ++subcol) {
+                unsigned int col, ccol;
+                for (col = subcol, ccol = 0;
+                     col < cols;
+                     col += cellWidth, ++ccol) {
+                    if (bitrow[col] == PBM_BLACK)
+                        sig[ccol] |= b;
+                }
+                b <<= 1;
+            }
+        }
+    }
+    pbm_freerow(bitrow);
+}
+
+
+
+static void
+findRightMargin(const unsigned int * const sig,
+                unsigned int         const ccols,
+                const char *         const carr,
+                unsigned int *       const endColP) {
+/*----------------------------------------------------------------------------
+   Find the first cell of the right margin, i.e. a contiguous set of
+   all-white cells at the right end of the row.
+-----------------------------------------------------------------------------*/
+    unsigned int endcol;
+
+    for (endcol = ccols; endcol > 0; --endcol) {
+        if (carr[sig[endcol-1]] != ' ')
+            break;
+    }
+    *endColP = endcol;
+}
+
+
+
+static void
+assembleCellRow(const unsigned int * const sig,
+                unsigned int         const ccols,
+                const char *         const carr,
+                char *               const line) {
+/*----------------------------------------------------------------------------
+   Return as line[] the line of ASCII codes for the characters of one
+   row of cells, ready for printing.
+-----------------------------------------------------------------------------*/
+    unsigned int col;
+
+    for (col = 0; col < ccols; ++col)
+        line[col] = carr[sig[col]];
+
+    line[ccols] = '\0';
+}
+
+
+
+static void
+pbmtoascii(FILE *       const ifP,
+           unsigned int const cellWidth,
+           unsigned int const cellHeight,
+           const char * const carr) {
+
+    int cols, rows, format;
+    unsigned int ccols;
+    char * line;         /* malloc'ed array */
+    unsigned int row;
+    unsigned int * sig;  /* malloc'ed array */
+        /* This describes in a single integer the pixels of a cell,
+           as described above.
+        */
+    assert(cellWidth * cellHeight <= sizeof(sig[0])*8);
+
+    pbm_readpbminit(ifP, &cols, &rows, &format);
+
+    ccols = (cols + cellWidth - 1) / cellWidth;
+
+    MALLOCARRAY(sig, ccols);
+    if (sig == NULL)
+        pm_error("No memory for %u columns", ccols);
+    MALLOCARRAY_NOFAIL(line, ccols+1);
+    if (line == NULL)
+        pm_error("No memory for %u columns", ccols);
+
+    for (row = 0; row < rows; row += cellHeight) {
+        unsigned int endCol;
+
+        makeRowOfSigs(ifP, cols, rows, format, cellWidth, cellHeight,
+                      row, sig, ccols);
+
+        findRightMargin(sig, ccols, carr, &endCol);
+
+        assembleCellRow(sig, endCol, carr, line);
+
+        puts(line);
+    }
+    free(sig);
+    free(line);
+}
+
+
+
+int
+main(int argc, const char ** argv) {
+
+    FILE * ifP;
+    int argn, gridx, gridy;
+    const char * carr;
     const char* usage = "[-1x2|-2x4] [pbmfile]";
 
-    pbm_init( &argc, argv );
+    pm_proginit(&argc, argv);
 
     /* Set up default parameters. */
     argn = 1;
@@ -85,81 +240,38 @@ char* argv[];
 
     /* Check for flags. */
     while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
-	{
-	if ( pm_keymatch( argv[argn], "-1x2", 2 ) )
-	    {
-	    gridx = 1;
-	    gridy = 2;
-	    carr = carr1x2;
-	    }
-	else if ( pm_keymatch( argv[argn], "-2x4", 2 ) )
-	    {
-	    gridx = 2;
-	    gridy = 4;
-	    carr = carr2x4;
-	    }
-	else
-	    pm_usage( usage );
-	++argn;
-	}
+    {
+        if ( pm_keymatch( argv[argn], "-1x2", 2 ) )
+        {
+            gridx = 1;
+            gridy = 2;
+            carr = carr1x2;
+        }
+        else if ( pm_keymatch( argv[argn], "-2x4", 2 ) )
+        {
+            gridx = 2;
+            gridy = 4;
+            carr = carr2x4;
+        }
+        else
+            pm_usage( usage );
+        ++argn;
+    }
 
     if ( argn < argc )
-	{
-	ifp = pm_openr( argv[argn] );
-	++argn;
-	}
+    {
+        ifP = pm_openr( argv[argn] );
+        ++argn;
+    }
     else
-	ifp = stdin;
+        ifP = stdin;
     
     if ( argn != argc )
         pm_usage( usage );
 
-    pbm_readpbminit( ifp, &cols, &rows, &format );
-    ccols = ( cols + gridx - 1 ) / gridx;
-    bitrow = pbm_allocrow( cols );
-    sig = (int*) pm_allocrow( ccols, sizeof(int) );
-    line = (char*) pm_allocrow( ccols + 1, sizeof(char) );
-
-    for ( row = 0; row < rows; row += gridy )
-	{
-	/* Get a character-row's worth of sigs. */
-	for ( col = 0; col < ccols; ++col )
-	    sig[col] = 0;
-	b = 1;
-	for ( subrow = 0; subrow < gridy; ++subrow )
-	    {
-	    if ( row + subrow < rows )
-		{
-		pbm_readpbmrow( ifp, bitrow, cols, format );
-		for ( subcol = 0; subcol < gridx; ++subcol )
-		    {
-		    for ( col = subcol, bP = &(bitrow[subcol]), sP = sig;
-			  col < cols;
-			  col += gridx, bP += gridx, ++sP )
-			if ( *bP == PBM_BLACK )
-			    *sP |= b;
-		    b <<= 1;
-		    }
-		}
-	    }
-	/* Ok, now remove trailing blanks.  */
-	for ( lastcol = ccols - 1; lastcol >= 0; --lastcol )
-	    if ( carr[sig[lastcol]] != ' ' )
-		break;
-	/* Copy chars to an array and print. */
-	for ( col = 0, sP = sig, lP = line; col <= lastcol; ++col, ++sP, ++lP )
-	    *lP = carr[*sP];
-	*lP++ = '\0';
-	puts( line );
-	}
-
-    pm_close( ifp );
-    pbm_freerow( bitrow );
-    pm_freerow( (char*) sig );
-    pm_freerow( (char*) line );
-
-    /* If the program failed, it previously aborted with nonzero completion
-       code, via various function calls.
-    */
+    pbmtoascii(ifP, gridx, gridy, carr);
+
+    pm_close(ifP);
+
     return 0;
-    }
+}
diff --git a/converter/pbm/pbmtoatk.c b/converter/pbm/pbmtoatk.c
index 9399f602..ea5b7abe 100644
--- a/converter/pbm/pbmtoatk.c
+++ b/converter/pbm/pbmtoatk.c
@@ -118,63 +118,52 @@ process_atk_byte(int *           const pcurcount,
 
 
 int
-main(int argc, char *argv[]) {
+main(int argc, const char ** argv) {
 
-    FILE *ifd;
-    bit *bitrow;
-    register bit *bP;
-    int rows, cols, format, row;
-    int col;
-    unsigned char curbyte, newbyte;
-    int curcount, gather;
+    FILE * ifP;
+    bit * bitrow;
+    int rows, cols, format;
+    unsigned int row;
+    unsigned char curbyte;
+    int curcount;
 
-    pbm_init ( &argc, argv );
+    pm_proginit(&argc, argv);
 
     if (argc-1 > 1)
         pm_error("Too many arguments.  Only argument is file name");
 
     else if (argc-1 == 1) {
-        ifd = pm_openr( argv[1] );
+        ifP = pm_openr(argv[1]);
     } else {
-        ifd = stdin;
+        ifP = stdin;
     }
 
-    pbm_readpbminit(ifd, &cols, &rows, &format);
-    bitrow = pbm_allocrow(cols);
+    pbm_readpbminit(ifP, &cols, &rows, &format);
+    bitrow = pbm_allocrow_packed(cols);
 
-    printf ("\\begindata{raster,%d}\n", 1);
-    printf ("%d %d %d %d ", RASTERVERSION, 0, DEFAULTSCALE, DEFAULTSCALE);
-    printf ("%d %d %d %d\n", 0, 0, cols, rows); /* subraster */
-    printf ("bits %d %d %d\n", 1, cols, rows);
+    printf("\\begindata{raster,%d}\n", 1);
+    printf("%d %d %d %d ", RASTERVERSION, 0, DEFAULTSCALE, DEFAULTSCALE);
+    printf("%d %d %d %d\n", 0, 0, cols, rows); /* subraster */
+    printf("bits %d %d %d\n", 1, cols, rows);
 
     for (row = 0; row < rows; ++row) {
-        pbm_readpbmrow(ifd, bitrow, cols, format);
-        bP = bitrow;
-        gather = 0;
-        newbyte = 0;
-        curbyte = 0;
-        curcount = 0;
-        col = 0;
-        while (col < cols) {
-            if (gather > 7) {
-                process_atk_byte (&curcount, &curbyte, stdout, newbyte, FALSE);
-                gather = 0;
-                newbyte = 0;
-            }
-            newbyte = (newbyte << 1) | (*bP++);
-            gather += 1;
-            col += 1;
-        }
-
-        if (gather > 0) {
-            newbyte = (newbyte << (8 - gather));
-            process_atk_byte (&curcount, &curbyte, stdout, newbyte, TRUE);
+        unsigned int const byteCt = pbm_packed_bytes(cols);
+        unsigned int i;
+
+        pbm_readpbmrow_packed(ifP, bitrow, cols, format);
+        pbm_cleanrowend_packed(bitrow, cols);
+        
+        for (i = 0, curbyte = 0, curcount = 0; i < byteCt; ++i) {
+            process_atk_byte(&curcount, &curbyte, stdout,
+                             bitrow[i],
+                             i + 1 < byteCt ? FALSE : TRUE );
         }
     }
 
-    pm_close( ifd );
+    pbm_freerow_packed(bitrow);
+    pm_close(ifP);
     
-    printf ("\\enddata{raster, %d}\n", 1);
+    printf("\\enddata{raster, %d}\n", 1);
 
     return 0;
 }
diff --git a/converter/pbm/pbmtocis.c b/converter/pbm/pbmtocis.c
new file mode 100644
index 00000000..9bb42c56
--- /dev/null
+++ b/converter/pbm/pbmtocis.c
@@ -0,0 +1,170 @@
+/*
+ *  cistopbm: Convert images in the CompuServe RLE format to PBM
+ *  Copyright (C) 2009  John Elliott
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pbm.h"
+
+/* The maximum length of a run. Limit it to 0x5E bytes so that it is always
+ * represented by a printable character 0x20-0x7E */
+#define MAXRUNLENGTH 0x5E
+
+static void syntax(const char *prog)
+{
+    pm_usage(" { options } { input } }\n\n"
+         "Input file should be in PBM format.\n"
+         "Output will be in CompuServe RLE format.\n"
+         "Options:\n"
+         "-i, --inverse: Reverse black and white.\n"
+         "-w, --whitebg: White background.\n"
+         "--:            End of options\n\n"
+"pbmtocis v1.00, Copyright 2009 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"
+         );
+}
+
+int main(int argc, const char **argv)
+{
+    FILE *ofP = stdout;
+    FILE *ifP;
+    int inoptions = 1;
+    int n, x, y;
+    int bg = PBM_BLACK; /* Default colouring is white on black */
+    int inverse = 0;
+    int cell, last, run;
+    const char *inpname = NULL;
+
+    int outh, outw;
+    int height, width;
+    bit **bits;
+
+    pm_proginit(&argc, argv);
+
+    for (n = 1; n < argc; n++)
+    {
+        if (!strcmp(argv[n], "--"))
+        {
+            inoptions = 0;
+            continue;
+        }
+        if (inoptions)
+        {
+            if (pm_keymatch(argv[n], "-h", 2) ||
+                pm_keymatch(argv[n], "-H", 2) ||
+                pm_keymatch(argv[n], "--help", 6))
+            {
+                syntax(argv[0]);
+                return EXIT_SUCCESS;
+            }
+            if (pm_keymatch(argv[n], "-i", 2) ||
+                pm_keymatch(argv[n], "-I", 2) ||
+                pm_keymatch(argv[n], "--inverse", 9))
+            {
+                inverse = 1;
+                continue;
+            }
+            if (pm_keymatch(argv[n], "-w", 2) ||
+                pm_keymatch(argv[n], "-W", 2) ||
+                pm_keymatch(argv[n], "--whitebg", 9))
+            {
+                bg = PBM_WHITE; 
+                continue;
+            }
+            if (argv[n][0] == '-' && argv[n][1] != 0)
+            {
+                pm_message("Unknown option: %s", argv[n]);
+                syntax(argv[0]);
+                return EXIT_FAILURE;
+            }
+        }
+
+        if (inpname == NULL) inpname = argv[n];
+        else { syntax(argv[0]); return EXIT_FAILURE; }
+    }
+    if (inpname == NULL) inpname = "-";
+    ifP  = pm_openr(inpname);
+
+    /* Load the PBM */
+    bits = pbm_readpbm(ifP, &width, &height);
+
+    if      (width <= 128 && height <= 96)  { outw = 128; outh = 96; }
+    else if (width <= 256 && height <= 192) { outw = 256; outh = 192; }
+    else
+    {
+        outw = 256;
+        outh = 192;
+        pm_message("Warning: Input file is larger than 256x192. "
+                "It will be cropped.");
+    }
+    /* Write the magic number */
+    fputc(0x1B, ofP);
+    fputc(0x47, ofP);
+    fputc((outw == 128) ? 0x4D : 0x48, ofP);
+
+    /* And now start encoding */
+    y = x = 0;
+    last = PBM_BLACK;
+    run = 0;
+    while (y < outh)
+    {
+        if (x < width && y < height)    
+        {
+            cell = bits[y][x];
+            if (inverse) cell ^= (PBM_BLACK ^ PBM_WHITE);
+        }
+        else cell = bg;
+
+        if (cell == last)   /* Cell is part of current run */
+        {
+            ++run;
+            if (run > MAXRUNLENGTH)
+            {       
+                fputc(0x20 + MAXRUNLENGTH, ofP);
+                fputc(0x20, ofP);
+                run -= MAXRUNLENGTH;
+            }   
+        }
+        else    /* change */
+        {
+            fputc(run + 0x20, ofP);
+            last = last ^ (PBM_BLACK ^ PBM_WHITE);
+            run = 1;
+        }
+        ++x;
+        if (x >= outw) { x = 0; ++y; }
+    }
+    if (last == bg) /* Last cell written was background. Write foreground */
+    {
+        fputc(run + 0x20, ofP);
+    }
+    else if (run)   /* Write background and foreground */
+    {
+        fputc(run + 0x20, ofP);
+        fputc(0x20, ofP);
+    }
+    /* Write the end-graphics signature */
+    fputc(0x1B, ofP);
+    fputc(0x47, ofP);
+    fputc(0x4E, ofP);
+    pm_close(ifP);
+    return 0;   
+}
diff --git a/converter/pbm/pbmtocmuwm.c b/converter/pbm/pbmtocmuwm.c
index 773d988b..983ea491 100644
--- a/converter/pbm/pbmtocmuwm.c
+++ b/converter/pbm/pbmtocmuwm.c
@@ -18,18 +18,20 @@
 */
 
 #include "pbm.h"
-#include "cmuwm.h"
+
+
 
 static void
 putinit(unsigned int const rows,
         unsigned int const cols) {
 
-    const char * const initWriteError =
+    const char initWriteError[] =
         "CMU window manager header write error";
+    uint32_t const cmuwmMagic = 0xf10040bb;
 
     int rc;
 
-    rc = pm_writebiglong(stdout, CMUWM_MAGIC);
+    rc = pm_writebiglong(stdout, cmuwmMagic);
     if (rc == -1)
         pm_error(initWriteError);
     rc = pm_writebiglong(stdout, cols);
diff --git a/converter/pbm/pbmtoepsi.c b/converter/pbm/pbmtoepsi.c
index 5eccc298..87985a1f 100644
--- a/converter/pbm/pbmtoepsi.c
+++ b/converter/pbm/pbmtoepsi.c
@@ -16,19 +16,24 @@
 ** implied warranty.
 */
 
+/*
+ *
+ * Official guide from Adobe:
+ *
+ * Encapsulated PostScript File Format Specification
+ * http://partners.adobe.com/public/developer/en/ps/5002.EPSF_Spec.pdf
+ *
+*/
+
 #include "pm_c_util.h"
 #include "pbm.h"
 #include "shhopt.h"
 
-#if !defined(MAXINT)
-#define MAXINT (0x7fffffff)
-#endif
-
 struct cmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    const char *inputFilespec;  /* Filespecs of input files */
+    const char *inputFileName;
 
     unsigned int dpiX;     /* horiz component of DPI option */
     unsigned int dpiY;     /* vert component of DPI option */
@@ -40,8 +45,9 @@ struct cmdlineInfo {
 
 
 static void
-parse_dpi(char * const dpiOpt, 
-          unsigned int * const dpiXP, unsigned int * const dpiYP) {
+parseDpi(char *         const dpiOpt, 
+         unsigned int * const dpiXP,
+         unsigned int * const dpiYP) {
 
     char *dpistr2;
     unsigned int dpiX, dpiY;
@@ -72,7 +78,7 @@ parse_dpi(char * const dpiOpt,
 
 
 static void
-parseCommandLine(int argc, char ** const argv,
+parseCommandLine(int argc, const char ** const argv,
                  struct cmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that the file spec array we return is stored in the storage that
@@ -97,48 +103,58 @@ parseCommandLine(int argc, char ** const argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
     
 
     if (dpiOptSpec)
-        parse_dpi(dpiOpt, &cmdlineP->dpiX, &cmdlineP->dpiY);
+        parseDpi(dpiOpt, &cmdlineP->dpiX, &cmdlineP->dpiY);
     else
         cmdlineP->dpiX = cmdlineP->dpiY = 72;
     
     if ((argc-1) > 1)
-        pm_error("Too many arguments (%d).  Only argument is input filespec",
+        pm_error("Too many arguments (%d).  Only argument is input file name",
                  argc-1);
     
     if (argc-1 == 0)
-        cmdlineP->inputFilespec = "-";
+        cmdlineP->inputFileName = "-";
     else
-        cmdlineP->inputFilespec = argv[1];
+        cmdlineP->inputFileName = argv[1];
 }
 
 
 
 static void
-findPrincipalImage(bit ** const bits, 
-                   int    const rows,
-                   int    const cols,
-                   int *  const topP,
-                   int *  const bottomP,
-                   int *  const leftP,
-                   int *  const rightP) {
+findPrincipalImage(bit **         const bits, 
+                   unsigned int   const rows,
+                   unsigned int   const cols,
+                   unsigned int * const topP,
+                   unsigned int * const bottomP,
+                   unsigned int * const leftP,
+                   unsigned int * const rightP) {
+/*----------------------------------------------------------------------------
+   Find the foreground image on a white background.
+
+   Find the image in the pixels bits[][], which is 'rows' rows by
+   'cols' columns.
 
-    int top, bottom, left, right;
-    int row;
+   Return the boundaries of the foreground image as *topP, *bottomP, *leftP,
+   and *rightP.
+
+   If the image is all white, consider the entire image foreground.
+-----------------------------------------------------------------------------*/
+    unsigned int top, bottom, left, right;
+    unsigned int row;
 
     /* Initial values */
-    top = MAXINT;
-    bottom = -MAXINT;
-    left = MAXINT;
-    right = -MAXINT;
+    top    = rows;
+    bottom = 0;
+    left   = cols;
+    right  = 0;
  
-    for (row = 0; row < rows; row++) {
-        int col;
-        for (col = 0; col < cols; col++) {
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+        for (col = 0; col < cols; ++col) {
             if (bits[row][col] == PBM_BLACK) {
                 if (row < top) 
                     top = row;
@@ -152,16 +168,19 @@ findPrincipalImage(bit ** const bits,
         }
     }
 
-    if(bottom == -MAXINT) {  /* No black pixels encountered */ 
+    if (top > bottom) {
+        /* No black pixels encountered */ 
         pm_message("Blank page");
-        top = left = 0;
-        bottom = rows-1;  right = cols-1;
-	}
+        top    = 0;
+        left   = 0;
+        bottom = rows - 1;
+        right  = cols - 1;
+    }
 
-    *topP = top;
+    *topP    = top;
     *bottomP = bottom;
-    *leftP = left;
-    *rightP = right;
+    *leftP   = left;
+    *rightP  = right;
 }
 
 
@@ -190,7 +209,8 @@ eightPixels(bit ** const bits,
 /*----------------------------------------------------------------------------
   Compute a byte that represents the 8 pixels starting at Column 'col' of
   row 'row' of the raster 'bits'.  The most significant bit of the result
-  represents the leftmost pixel, with 1 meaning black.
+  represents the leftmost pixel, with 1 meaning black.  (Note that this is
+  the opposite of Postscript.)
 
   The row is 'cols' columns wide, so fill on the right with white if there
   are not eight pixels in the row starting with Column 'col'.
@@ -212,23 +232,23 @@ eightPixels(bit ** const bits,
 
 
 int
-main(int argc, char * argv[]) {
+main(int argc, const char * argv[]) {
 
     struct cmdlineInfo cmdline;
-    FILE *ifP;
-    bit **bits;
+    FILE * ifP;
+    bit ** bits;
     int rows, cols;
-    int top, bottom, left, right;
+    unsigned int top, bottom, left, right;
         /* boundaries of principal part of image -- i.e. excluding white
            borders
         */
 
-    pbm_init( &argc, argv );
+    pm_proginit(&argc, argv);
     
     parseCommandLine(argc, argv, &cmdline);
 
-    ifP = pm_openr(cmdline.inputFilespec);
-    bits = pbm_readpbm( ifP, &cols, &rows );
+    ifP = pm_openr(cmdline.inputFileName);
+    bits = pbm_readpbm(ifP, &cols, &rows);
     pm_close(ifP);
 
     findPrincipalImage(bits, rows, cols, &top, &bottom, &left, &right);
@@ -244,24 +264,26 @@ main(int argc, char * argv[]) {
                right - left + 1, bottom - top + 1, bottom - top + 1);
 
         for (row = top; row <= bottom; row++) {
-            int col;
-	    int outChars = 2;
-	    printf("%% ");
+            unsigned int col;
+            unsigned int outChars;
+            printf("%% ");
+
+            outChars = 2;  /* initial value */
 
             for (col = left; col <= right; col += 8) {
                 if (outChars == 72) {
-		  printf("\n%% ");
-                  outChars = 2;
-		}  
+                    printf("\n%% ");
+                    outChars = 2;
+                }  
 
                 printf("%02x", eightPixels(bits, row, col, cols));
                 outChars += 2;
-	    }
-	    if (outChars > 0)
+            }
+            if (outChars > 0)
                 printf("\n");
         }
         printf("%%%%EndImage\n");
         printf("%%%%EndPreview\n");
     }
-    exit(0);
+    return 0;
 }
diff --git a/converter/pbm/pbmtoepson.c b/converter/pbm/pbmtoepson.c
index 86185d15..bb36791d 100644
--- a/converter/pbm/pbmtoepson.c
+++ b/converter/pbm/pbmtoepson.c
@@ -11,13 +11,12 @@
 ** implied warranty.
 */
 
-#define _BSD_SOURCE    /* Make sure strcasecmp() is in string.h */
-
+#define _BSD_SOURCE    /* Make sure strcaseeq() is in nstring.h */
 #include <stdio.h>
-#include <string.h>
 
 #include "pm_c_util.h"
 #include "mallocvar.h"
+#include "nstring.h"
 #include "shhopt.h"
 
 #include "pbm.h"
@@ -29,22 +28,22 @@ enum epsonProtocol {ESCP9, ESCP};
 
 enum adjacence {ADJACENT_ANY, ADJACENT_YES, ADJACENT_NO};
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    const char *inputFilespec;  /* '-' if stdin */
-    unsigned int dpi;  /* zero means "any" */
-    enum adjacence adjacence;
+    const char *       inputFileName;  /* '-' if stdin */
+    unsigned int       dpi;  /* zero means "any" */
+    enum adjacence     adjacence;
     enum epsonProtocol protocol;
 };
 
 
 
 static void
-parseCommandLine(int                 argc, 
-                 char **             argv,
-                 struct cmdlineInfo *cmdlineP ) {
+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.  
@@ -56,7 +55,7 @@ parseCommandLine(int                 argc,
    was passed to us as the argv array.  We also trash *argv.
 -----------------------------------------------------------------------------*/
     optEntry *option_def;
-        /* Instructions to optParseOptions3 on how to parse our options.
+        /* Instructions to pm_optParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
 
@@ -69,20 +68,20 @@ parseCommandLine(int                 argc,
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENT3 */
-    OPTENT3(0, "protocol",   OPT_STRING,   &protocol,
+    OPTENT3(0, "protocol",     OPT_STRING,   &protocol,
             &protocolSpec,                    0);
-    OPTENT3(0, "dpi",        OPT_UINT,   &cmdlineP->dpi,
-            &dpiSpec,                    0);
-    OPTENT3(0, "adjacent",   OPT_FLAG,   NULL,
+    OPTENT3(0, "dpi",          OPT_UINT,     &cmdlineP->dpi,
+            &dpiSpec,                         0);
+    OPTENT3(0, "adjacent",     OPT_FLAG,     NULL,
             &adjacentSpec,                    0);
-    OPTENT3(0, "nonadjacent",   OPT_FLAG,   NULL,
-            &nonadjacentSpec,                    0);
+    OPTENT3(0, "nonadjacent",  OPT_FLAG,     NULL,
+            &nonadjacentSpec,                 0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    optParseOptions3( &argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3( &argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
 
@@ -96,11 +95,11 @@ parseCommandLine(int                 argc,
     if (!protocolSpec)
         cmdlineP->protocol = ESCP9;
     else {
-        if (strcasecmp(protocol, "escp9") == 0)
+        if (strcaseeq(protocol, "escp9"))
             cmdlineP->protocol = ESCP9;
-        else if (strcasecmp(protocol, "escp") == 0)
+        else if (strcaseeq(protocol, "escp"))
             cmdlineP->protocol = ESCP;
-        else if (strcasecmp(protocol, "escp2") == 0)
+        else if (strcaseeq(protocol, "escp2"))
             pm_error("This program cannot do ESC/P2.  Try Pbmtoescp2.");
         else
             pm_error("Unrecognized value '%s' for -protocol.  "
@@ -118,13 +117,15 @@ parseCommandLine(int                 argc,
         cmdlineP->adjacence = ADJACENT_ANY;
 
     if (argc-1 < 1)
-        cmdlineP->inputFilespec = "-";
+        cmdlineP->inputFileName = "-";
     else {
-        cmdlineP->inputFilespec = argv[1];
+        cmdlineP->inputFileName = argv[1];
         if (argc-1 > 1)
             pm_error("Too many arguments (%d).  The only non-option argument "
                      "is the file name", argc-1);
     }
+
+    free(option_def);
 }
 
 
@@ -273,7 +274,7 @@ convertToEpson(const bit **       const bits,
                enum adjacence     const adjacence) {
     
     unsigned int const rowsPerStripe = 8;
-    unsigned int const stripes = (rows + rowsPerStripe-1) / rowsPerStripe;
+    unsigned int const stripeCt = (rows + rowsPerStripe-1) / rowsPerStripe;
 
     unsigned int stripe;
     char m;
@@ -288,7 +289,7 @@ convertToEpson(const bit **       const bits,
        stripe can be fewer than 8 rows.
     */
 
-    for (stripe = 0; stripe < stripes; ++stripe) {
+    for (stripe = 0; stripe < stripeCt; ++stripe) {
         const bit ** const stripeBits = &bits[stripe*rowsPerStripe];
         unsigned int const stripeRows = 
             MIN(rowsPerStripe, rows - stripe * rowsPerStripe);
@@ -313,18 +314,18 @@ convertToEpson(const bit **       const bits,
 
 
 int
-main(int argc, char *argv[]) {
+main(int argc, const char ** argv) {
 
-    struct cmdlineInfo cmdline;
-    FILE* ifP;
+    struct CmdlineInfo cmdline;
+    FILE * ifP;
     const bit** bits;
     int rows, cols;
 
-    pbm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
-    ifP = pm_openr(cmdline.inputFilespec);
+    ifP = pm_openr(cmdline.inputFileName);
 
     bits = (const bit **)pbm_readpbm(ifP, &cols, &rows);
 
diff --git a/converter/pbm/pbmtoescp2.c b/converter/pbm/pbmtoescp2.c
index e280b3df..6f284f3c 100644
--- a/converter/pbm/pbmtoescp2.c
+++ b/converter/pbm/pbmtoescp2.c
@@ -1,4 +1,4 @@
-/* pbmtoescp2.c - read a portable bitmap and produce Epson ESC/P2 raster
+ /* pbmtoescp2.c - read a portable bitmap and produce Epson ESC/P2 raster
 **                 graphics output data for Epson Stylus printers
 **
 ** Copyright (C) 2003 by Ulrich Walcher (u.walcher@gmx.de)
@@ -10,45 +10,65 @@
 ** copyright notice and this permission notice appear in supporting
 ** documentation.  This software is provided "as is" without express or
 ** implied warranty.
+**
+** Major changes were made in July 2015 by Akira Urushibata.
+** Added 720 DPI capability.
+** Added -formfeed, -raw and -stripeheight.
+** Replaced Packbits run length encoding function.  (Use library function.)
+*
+*  ESC/P Reference Manual (1997)
+*  ftp://download.epson-europe.com/pub/download/182/epson18162eu.zip
 */
 
-/* I used the Epson ESC/P Reference Manual (1997) in writing this. */
-
 #include <string.h>
 
 #include "pm_c_util.h"
-#include "pbm.h"
+#include "mallocvar.h"
 #include "shhopt.h"
+#include "runlength.h"
+#include "pbm.h"
+
+
 
 static char const esc = 033;
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     const char * inputFileName;
     unsigned int resolution;
     unsigned int compress;
+    unsigned int stripeHeight;
+    bool raw;
+    bool formfeed;
 };
 
 
 
 static void
-parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo *cmdlineP) {
+parseCommandLine(int argc, const char ** argv,
+                 struct CmdlineInfo *cmdlineP) {
 
     optStruct3 opt;
     unsigned int option_def_index = 0;
-    optEntry *option_def = malloc(100*sizeof(optEntry));
+    optEntry * option_def = malloc(100*sizeof(optEntry));
 
-    unsigned int compressSpec, resolutionSpec;
+    unsigned int compressSpec, resolutionSpec, stripeHeightSpec,
+                 rawSpec, formfeedSpec;
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;
     opt.allowNegNum = FALSE;
     OPTENT3(0, "compress",     OPT_UINT,    &cmdlineP->compress,    
-            &compressSpec, 0);
+            &compressSpec,    0);
     OPTENT3(0, "resolution",   OPT_UINT,    &cmdlineP->resolution,  
-            &resolutionSpec, 0);
+            &resolutionSpec,  0);
+    OPTENT3(0, "stripeheight", OPT_UINT,    &cmdlineP->stripeHeight,  
+            &stripeHeightSpec, 0);
+    OPTENT3(0, "raw",          OPT_FLAG,    NULL,  
+            &rawSpec,    0);
+    OPTENT3(0, "formfeed",     OPT_FLAG,    NULL,  
+            &formfeedSpec,    0);
     
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
     
     if (argc-1 > 1)
         pm_error("Too many arguments: %d.  "
@@ -62,79 +82,81 @@ parseCommandLine(int argc, char ** argv,
         cmdlineP->compress = 1;
 
     if (resolutionSpec) {
-        if (cmdlineP->resolution != 360 && cmdlineP->resolution != 180)
+        if (cmdlineP->resolution != 720 && cmdlineP->resolution != 360 &&
+            cmdlineP->resolution != 180)
             pm_error("Invalid -resolution value: %u.  "
-                     "Only 180 and 360 are valid.", cmdlineP->resolution);
+                     "Only 180, 360 and 720 are valid.", cmdlineP->resolution);
     } else
         cmdlineP->resolution = 360;
 
+    if (stripeHeightSpec) {
+        if (cmdlineP->stripeHeight == 0 ||
+            cmdlineP->stripeHeight > 255)
+            pm_error("Invalid -stripeheight value: %u. "
+                     "Should be 24, 8, or 1, and must be in the range 1-255",
+                     cmdlineP->stripeHeight);
+        else if (cmdlineP->stripeHeight != 24 &&
+                 cmdlineP->stripeHeight != 8  &&
+                 cmdlineP->stripeHeight != 1)
+            pm_message("Proceeding with irregular -stripeheight value: %u. "
+                       "Should be 24, 8, or 1.", cmdlineP->stripeHeight);
+        else if (cmdlineP->resolution == 720 &&
+                 cmdlineP->stripeHeight != 1)
+            /* The official Epson manual mandates single-row stripes for
+               720 dpi high-resolution images.
+            */
+            pm_message("Proceeding with irregular -stripeheight value: %u. "
+                       "Because resolution i 720dpi, should be 1.",
+                        cmdlineP->stripeHeight);
+    } else
+        cmdlineP->stripeHeight = cmdlineP->resolution == 720 ? 1 : 24;
+
+    if (rawSpec && formfeedSpec)
+        pm_error("You cannot specify both -raw and -formfeed");
+    else {
+        cmdlineP->raw = rawSpec ? true : false ;
+        cmdlineP->formfeed = formfeedSpec ? true : false ;
+    }
+
     if (argc-1 == 1)
         cmdlineP->inputFileName = argv[1];
     else
         cmdlineP->inputFileName = "-";
+
+    free(option_def);
 }
 
 
 
-static unsigned int
-enc_epson_rle(unsigned int          const l, 
-              const unsigned char * const src, 
-              unsigned char *       const dest) {
-/*----------------------------------------------------------------------------
-  compress l data bytes from src to dest and return the compressed
-  length
------------------------------------------------------------------------------*/
-    unsigned int i;      /* index */
-    unsigned int state;  /* run state */
-    unsigned int pos;    /* source position */
-    unsigned int dpos;   /* destination position */
-
-    pos = dpos = state  = 0;
-    while ( pos < l )
-    {
-        for (i=0; i<128 && pos+i<l; i++)
-            /* search for begin of a run, smallest useful run is 3
-               equal bytes 
-            */
-            if(src[pos+i]==src[pos+i+1] && src[pos+i]==src[pos+i+2])
-            {
-                state=1;                       /* set run state */
-                break;
-            }
-	if(i)
-	{
-        /* set counter byte for copy through */
-        dest[dpos] = i-1;       
-        /* copy data bytes before run begin or end cond. */
-        memcpy(dest+dpos+1,src+pos,i);    
-        pos+=i; dpos+=i+1;                 /* update positions */
-	}
-    if (state)
-    {
-        for (i=0; src[pos+i]==src[pos+i+1] && i<128 && pos+i<l; i++);
-        /* found the runlength i */
-        dest[dpos]   = 257-i;           /* set counter for byte repetition */
-        dest[dpos+1] = src[pos];        /* set byte to be repeated */
-        pos+=i; dpos+=2; state=0;       /* update positions, reset run state */
-        }
-    }
-    return dpos;
+static void
+writeSetup(unsigned int const hres) {
+
+    /* Set raster graphic mode. */
+    printf("%c%c%c%c%c%c", esc, '(', 'G', 1, 0, 1);
+
+    /* Set line spacing in units of 1/360 inches. */
+    printf("%c%c%c", esc, '+', 24 * hres / 10);
 }
 
 
 
 int
-main(int argc, char* argv[]) {
+main(int argc, const char * argv[]) {
 
-    FILE* ifP;
+    FILE * ifP;
     int rows, cols;
     int format;
-    unsigned int row, idx, len;
-    unsigned int h, v;
-    unsigned char *bytes, *cprbytes;
-    struct cmdlineInfo cmdline;
+    unsigned int row;
+    unsigned int idx;
+    unsigned int outColByteCt;
+    unsigned int stripeByteCt;
+    unsigned int hres, vres;
+    unsigned char * inBuff;
+    unsigned char * bitrow[256];
+    unsigned char * compressedData;
+    struct CmdlineInfo cmdline;
     
-    pbm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
@@ -142,51 +164,83 @@ main(int argc, char* argv[]) {
 
     pbm_readpbminit(ifP, &cols, &rows, &format);
 
-    bytes = malloc(24*pbm_packed_bytes(cols)+2);
-    cprbytes = malloc(2*24*pbm_packed_bytes(cols));
-    if (bytes == NULL || cprbytes == NULL)
-        pm_error("Cannot allocate memory");
+    if (cols / 256 > 127)  /* Limit in official Epson manual */
+        pm_error("Image width is too large");
 
-    h = v = 3600/cmdline.resolution;
+    outColByteCt = pbm_packed_bytes(cols);
+    stripeByteCt = cmdline.stripeHeight * outColByteCt;
 
-    /* Set raster graphic mode. */
-    printf("%c%c%c%c%c%c", esc, '(', 'G', 1, 0, 1);
+    MALLOCARRAY(inBuff, stripeByteCt);
+    if (inBuff == NULL)
+      pm_error("Out of memory trying to create input buffer of %u bytes",
+               stripeByteCt);
 
-    /* Set line spacing in units of 1/360 inches. */
-    printf("%c%c%c", esc, '+', 24*h/10);
-
-    /* Write out raster stripes 24 rows high. */
-    for (row = 0; row < rows; row += 24) {
-        unsigned int const linesThisStripe = (rows-row<24) ? rows%24 : 24;
-        printf("%c%c%c%c%c%c%c%c", esc, '.', cmdline.compress, 
-               v, h, linesThisStripe, 
-               cols%256, cols/256);
-        /* Read pbm rows, each padded to full byte */
-        for (idx = 0; idx < 24 && row+idx < rows; ++idx)
-            pbm_readpbmrow_packed(ifP,bytes+idx*pbm_packed_bytes(cols),
-                                  cols,format);
-        /* Add delimiter to end of rows, using inverse of final
-           data byte to prevent match. */
-        *(bytes+idx*pbm_packed_bytes(cols)) =
-          ~ *(bytes+idx*pbm_packed_bytes(cols)-1);
-
-        /* Write raster data. */
-        if (cmdline.compress != 0) {
-            /* compressed */
-            len = enc_epson_rle(linesThisStripe * pbm_packed_bytes(cols), 
-                                bytes, cprbytes);
-            fwrite(cprbytes,len,1,stdout);
-        } else
-            /* uncompressed */
-            fwrite(bytes, pbm_packed_bytes(cols), linesThisStripe, stdout);    
-
-        if (rows-row >= 24) putchar('\n');
+    if (cmdline.compress != 0)
+        pm_rlenc_allocoutbuf(&compressedData, stripeByteCt, PM_RLE_PACKBITS);
+    else
+        compressedData = NULL;
+
+    for (idx = 0; idx <= cmdline.stripeHeight; ++idx)
+        bitrow[idx]= &inBuff[idx * outColByteCt];
+
+    hres = vres = 3600 / cmdline.resolution;
+        /* Possible values for hres, vres: 20, 10, 5 */
+
+    if (!cmdline.raw)
+        writeSetup(hres);
+
+    /* Write out raster stripes */
+
+    for (row = 0; row < rows; row += cmdline.stripeHeight ) {
+        unsigned int const rowsThisStripe =
+            MIN(rows - row, cmdline.stripeHeight);
+        unsigned int const outCols = outColByteCt * 8;
+
+        if (rowsThisStripe > 0) {
+            unsigned int idx;
+
+            printf("%c%c%c%c%c%c%c%c", esc, '.', cmdline.compress, vres, hres,
+                   cmdline.stripeHeight, outCols % 256, outCols / 256);
+
+            /* Read pbm rows, each padded to full byte */
+
+            for (idx = 0; idx < rowsThisStripe; ++idx) {
+                pbm_readpbmrow_packed (ifP, bitrow[idx], cols, format);
+                pbm_cleanrowend_packed(bitrow[idx], cols);
+            }
+
+            /* If at bottom pad with empty rows up to stripe height */
+            if (rowsThisStripe < cmdline.stripeHeight )
+                memset(bitrow[rowsThisStripe], 0,
+                       (cmdline.stripeHeight - rowsThisStripe) * outColByteCt);
+
+            /* Write raster data */
+            if (cmdline.compress != 0) {  /* compressed */
+                size_t compressedDataCt;
+
+                pm_rlenc_compressbyte(inBuff, compressedData, PM_RLE_PACKBITS,
+                                      stripeByteCt, &compressedDataCt);
+                fwrite(compressedData, compressedDataCt, 1, stdout);
+            } else                        /* uncompressed */
+                fwrite(inBuff, stripeByteCt, 1, stdout);
+
+            /* Emit newline to print the stripe */
+            putchar('\n');
+        }
     }
-    free(bytes); free(cprbytes);
+
+    free(inBuff); 
+    free(compressedData);
     pm_close(ifP);
 
-    /* Reset printer. */
-    printf("%c%c", esc, '@');
+    /* Form feed */
+    if (cmdline.formfeed)
+        putchar('\f');
+
+    if (!cmdline.raw) {
+        /* Reset printer. a*/
+        printf("%c%c", esc, '@');
+    }
 
     return 0;
 }
diff --git a/converter/pbm/pbmtog3.c b/converter/pbm/pbmtog3.c
index c0dd8c64..f0fd1252 100644
--- a/converter/pbm/pbmtog3.c
+++ b/converter/pbm/pbmtog3.c
@@ -65,7 +65,7 @@ struct outStream {
 static struct outStream out;
 
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -79,7 +79,7 @@ struct cmdlineInfo {
 
 static void
 parseCommandLine(int argc, char ** const argv,
-                 struct cmdlineInfo * const cmdlineP) {
+                 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.
@@ -108,7 +108,7 @@ parseCommandLine(int argc, char ** const argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = TRUE;  /* We may have parms that are negative numbers */
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     free(option_def);
@@ -407,7 +407,7 @@ int
 main(int    argc,
      char * argv[]) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     FILE * ifP;
     unsigned char * bitrow;
        /* This is the bits of the current row, as read from the input and
diff --git a/converter/pbm/pbmtog3.test b/converter/pbm/pbmtog3.test
deleted file mode 100644
index 9ca45079..00000000
--- a/converter/pbm/pbmtog3.test
+++ /dev/null
@@ -1,23 +0,0 @@
-echo Test 1.  Should print 3697098186 144
-./pbmtog3 ../../testgrid.pbm | cksum
-echo Test 2.  Should print 1248301383 122
-./pbmtog3 -nofixedwidth ../../testgrid.pbm | cksum
-echo Test 3.  Should print 686713716 144
-./pbmtog3 -reverse ../../testgrid.pbm | cksum
-echo Test 4.  Should print 215463240 122
-./pbmtog3 -nofixedwidth -reverse ../../testgrid.pbm | cksum
-echo Test 5.  Should print 28792587 47
-pbmmake -w 10 10 | ./pbmtog3 | cksum
-echo Test 6.  Should print 277456854 32
-pbmmake -w 10 10 | ./pbmtog3 -nofixedwidth | cksum
-echo Test 7.  Should print 28792587 47
-pbmmake -w 10000 10 | ./pbmtog3 | cksum
-echo Test 8.  Should print 871281767 162
-pbmmake -w 10000 10 | ./pbmtog3 -nofixedwidth | cksum
-echo Test 9.  Should print 3736247115 62
-pbmmake -b 10 10 | ./pbmtog3 | cksum
-echo Test 10.  Should print 2820255307 2191856
-pbmmake -g 1700 2286 | ./pbmtog3 | cksum
-echo Test 11.  Should print 4159089282 2226575
-pbmmake -g 1800 2286 | ./pbmtog3 | cksum
-echo Tests done.
diff --git a/converter/pbm/pbmtogem.c b/converter/pbm/pbmtogem.c
index cefbdc95..9eab0416 100644
--- a/converter/pbm/pbmtogem.c
+++ b/converter/pbm/pbmtogem.c
@@ -27,17 +27,21 @@
 *  removed rounding of the imagewidth to the next word boundary
 *  removed arbitrary limit to imagewidth
 *  changed pattern length to 1 to simplify locating of compressable parts
-*	in real world images
+*       in real world images
 *  add solid run and pattern run compression
 *
 *  Deficiencies:
 *  Compression of repeated scanlines not added
 *  
-*	Johann Haider (jh@fortec.tuwien.ac.at)
+*       Johann Haider (jh@fortec.tuwien.ac.at)
 *
 * 94/01/31 Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de)
 * Changed to remove architecture dependencies
 * Added compression of repeated scanlines
+*
+* Feb 2010 afu
+* Added dimension check to prevent short int from overflowing
+* Changed code style (ANSI-style function definitions, etc.)
 */
 
 #include <stdio.h>
@@ -47,59 +51,11 @@
 #define SOLID_0 0
 #define SOLID_1 0xff
 #define MINRUN 4
+#define INT16MAX 32767
+
 #define putsolid(v,c) putc((v&0x80)|c, stdout)
 #define putpattern(v,c) putc(0, stdout);putc(c, stdout);putc(v, stdout)
 
-static void putinit ARGS ((int rows, int cols));
-static void putbit ARGS(( bit b ));
-static void putitem ARGS(( void ));
-static void putrow ARGS(( void ));
-static void flushrow ARGS ((void));
-static void putstring ARGS((register unsigned char *p, register int n));
-
-int
-main( argc, argv )
-    int argc;
-    char* argv[];
-    {
-    FILE* ifp;
-    bit* bitrow;
-    register bit* bP;
-    int rows, cols, format, row, col;
-
-    pbm_init( &argc, argv );
-
-    if ( argc > 2 )
-	pm_usage( "[pbmfile]" );
-
-    if ( argc == 2 )
-	ifp = pm_openr( argv[1] );
-    else
-	ifp = stdin;
-
-    pbm_readpbminit( ifp, &cols, &rows, &format );
-
-    bitrow = pbm_allocrow( cols );
-
-    putinit (rows, cols);
-    for ( row = 0; row < rows; ++row )
-	{
-#ifdef DEBUG
-	fprintf (stderr, "row %d\n", row);
-#endif
-	pbm_readpbmrow( ifp, bitrow, cols, format );
-        for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
-	    putbit( *bP );
-        putrow( );
-        }
-    flushrow ();
-
-    pm_close( ifp );
-
-
-    exit( 0 );
-    }
-
 static short item;
 static int outcol, outmax;
 static short bitsperitem, bitshift;
@@ -107,9 +63,9 @@ static short linerepeat;
 static unsigned char *outrow, *lastrow;
 
 static void
-putinit (rows, cols)
-     int rows, cols;
+putinit (int const rows, int const cols)
 {
+
   if (pm_writebigshort (stdout, (short) 1) == -1 /* Image file version */
       || pm_writebigshort (stdout, (short) 8) == -1 /* Header length */
       || pm_writebigshort (stdout, (short) 1) == -1 /* Number of planes */
@@ -130,17 +86,6 @@ putinit (rows, cols)
 }
 
 static void
-putbit( bit b )
-    {
-    if ( bitsperitem == 8 )
-	putitem( );
-    ++bitsperitem;
-    if ( b == PBM_BLACK )
-	item += 1 << bitshift;
-    --bitshift;
-    }
-
-static void
 putitem( )
     {
     outrow[outcol++] = item;
@@ -149,19 +94,93 @@ putitem( )
     bitshift = 7;
     }
 
+
+static void
+putbit( bit const b )
+    {
+    if ( bitsperitem == 8 )
+        putitem( );
+    ++bitsperitem;
+    if ( b == PBM_BLACK )
+        item += 1 << bitshift;
+    --bitshift;
+    }
+
+
 static void
-putstring (p, n)
-register unsigned char *p;
-register int n;
+putstring ( unsigned char *p, int n)
 {
 #ifdef DEBUG
     fprintf (stderr, "Bitstring, length: %d, pos %d\n", n, outcol);
 #endif
     (void) putc((char) 0x80, stdout);     /* a Bit string */
-    (void) putc(n, stdout);	/* count */
+    (void) putc(n, stdout);     /* count */
     fwrite( p, n, 1, stdout );
 }
 
+
+static void
+flushrow( )
+    {
+    unsigned char *outp, *p, *q;
+    int count;
+    int col = outmax;
+
+    if (linerepeat > 1)
+      {
+        /* Put out line repeat count */
+        fwrite ("\0\0\377", 3, 1, stdout);
+        putchar (linerepeat);
+      }
+    for (outp = p = lastrow; col > 0;)
+    {
+            for (q = p, count=0; (count < col) && (*q == *p); q++,count++);
+            if (count > MINRUN)
+            {
+                if (p > outp)
+                {
+                    putstring (outp, p-outp);
+                    outp = p;
+                }
+                col -= count;
+                switch (*p)
+                {
+                case SOLID_0:
+#ifdef DEBUG
+/*                      if (outcol > 0) */
+                        fprintf (stderr, "Solid run 0, length: %d\n", count);
+#endif
+                        putsolid (SOLID_0, count);
+                        break;
+
+                case SOLID_1:
+#ifdef DEBUG
+                        fprintf (stderr, "Solid run 1, length: %d, pos %d\n", count, outcol);
+#endif
+                        putsolid (SOLID_1, count);
+                        break;
+                default:
+#ifdef DEBUG
+                        fprintf (stderr, "Pattern run, length: %d\n", count);
+#endif
+                        putpattern (*p, count);
+                        break;
+                }
+                outp = p = q;
+            }
+            else
+            {
+                p++;
+                col--;
+            }
+    }           
+    if (p > outp)
+         putstring (outp, p-outp);
+    if (ferror (stdout))
+      pm_error ("write error");
+}
+
+
 static void
 putrow( )
 {
@@ -173,7 +192,7 @@ putrow( )
     {
       unsigned char *temp;
       if (linerepeat != -1) /* Unless first line */
-	flushrow ();
+        flushrow ();
       /* Swap the pointers */
       temp = outrow; outrow = lastrow; lastrow = temp;
       linerepeat = 1;
@@ -183,64 +202,47 @@ putrow( )
     linerepeat++;
 }
 
-static void
-flushrow( )
-    {
-    register unsigned char *outp, *p, *q;
-    register int count;
-    int col = outmax;
 
-    if (linerepeat > 1)
-      {
-	/* Put out line repeat count */
-	fwrite ("\0\0\377", 3, 1, stdout);
-	putchar (linerepeat);
-      }
-    for (outp = p = lastrow; col > 0;)
+int
+main( int argc, char* argv[])
     {
-	    for (q = p, count=0; (count < col) && (*q == *p); q++,count++);
-	    if (count > MINRUN)
-	    {
-		if (p > outp)
-		{
-		    putstring (outp, p-outp);
-		    outp = p;
-		}
-		col -= count;
-		switch (*p)
-		{
-		case SOLID_0:
-#ifdef DEBUG
-/*			if (outcol > 0) */
-			fprintf (stderr, "Solid run 0, length: %d\n", count);
-#endif
-			putsolid (SOLID_0, count);
-			break;
+    FILE* ifp;
+    bit* bitrow;
+    int rows, cols, format, row, col;
 
-		case SOLID_1:
-#ifdef DEBUG
-			fprintf (stderr, "Solid run 1, length: %d, pos %d\n", count, outcol);
-#endif
-			putsolid (SOLID_1, count);
-			break;
-		default:
+    pbm_init( &argc, argv );
+
+    if ( argc > 2 )
+        pm_usage( "[pbmfile]" );
+
+    if ( argc == 2 )
+        ifp = pm_openr( argv[1] );
+    else
+        ifp = stdin;
+
+    pbm_readpbminit( ifp, &cols, &rows, &format );
+
+    if( rows>INT16MAX || cols>INT16MAX )
+      pm_error ("Input image is too large.");
+
+
+    bitrow = pbm_allocrow( cols );
+
+    putinit (rows, cols);
+    for ( row = 0; row < rows; ++row )
+        {
 #ifdef DEBUG
-			fprintf (stderr, "Pattern run, length: %d\n", count);
+        fprintf (stderr, "row %d\n", row);
 #endif
-			putpattern (*p, count);
-			break;
-		}
-		outp = p = q;
-	    }
-	    else
-	    {
-		p++;
-		col--;
-	    }
-    }		
-    if (p > outp)
-         putstring (outp, p-outp);
-    if (ferror (stdout))
-      pm_error ("write error");
-}
+        pbm_readpbmrow( ifp, bitrow, cols, format );
+        for ( col = 0; col < cols; ++col )
+            putbit( bitrow[col] );
+        putrow( );
+        }
+    flushrow ();
+
+    pm_close( ifp );
 
+
+    exit( 0 );
+    }
diff --git a/converter/pbm/pbmtoibm23xx.c b/converter/pbm/pbmtoibm23xx.c
index 334b649d..183d5419 100644
--- a/converter/pbm/pbmtoibm23xx.c
+++ b/converter/pbm/pbmtoibm23xx.c
@@ -84,7 +84,7 @@ parseCommandLine(int argc, char ** const argv,
     opt.short_allowed = 0;
     opt.allowNegNum = 0;
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (!xresSpec)
diff --git a/converter/pbm/pbmtolj.c b/converter/pbm/pbmtolj.c
index be28f635..0cceb4fe 100644
--- a/converter/pbm/pbmtolj.c
+++ b/converter/pbm/pbmtolj.c
@@ -94,7 +94,7 @@ parseCommandLine(int argc, char ** argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We may have parms that are negative numbers */
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (argc-1 == 0) 
@@ -162,7 +162,7 @@ putinit(struct cmdlineInfo const cmdline) {
     /* Set raster graphics resolution */
     printf("\033*t%dR", cmdline.dpi);
 
-    /* Start raster graphics, relative adressing */
+    /* Start raster graphics, relative addressing */
     printf("\033*r1A");
 
     bitsperitem = 1;
@@ -545,7 +545,7 @@ main(int argc, char * argv[]) {
 
     struct cmdlineInfo cmdline;
     FILE * ifP;
-    bool eof;
+    int eof;
 
     pbm_init(&argc, argv);
 
diff --git a/converter/pbm/pbmtomacp.c b/converter/pbm/pbmtomacp.c
index 600cc407..df5cbb0c 100644
--- a/converter/pbm/pbmtomacp.c
+++ b/converter/pbm/pbmtomacp.c
@@ -1,296 +1,443 @@
-/* pbmtomacp.c - read a portable bitmap and produce a MacPaint bitmap file
-**
-** Copyright (C) 1988 by Douwe vand der Schaaf.
-**
-** Permission to use, copy, modify, and distribute this software and its
-** documentation for any purpose and without fee is hereby granted, provided
-** that the above copyright notice appear in all copies and that both that
-** copyright notice and this permission notice appear in supporting
-** documentation.  This software is provided "as is" without express or
-** implied warranty.
+/*=============================================================================
+                                  pbmtomacp
+===============================================================================
+  Read a PBM file and produce a MacPaint bitmap file
+
+  Copyright (C) 2015 by Akira Urushibata ("douso").
+
+  Replacement of a previous program of the same name written in 1988
+  by Douwe van der Schaaf (...!mcvax!uvapsy!vdschaaf).
+
+  Permission to use, copy, modify, and distribute this software and its
+  documentation for any purpose and without fee is hereby granted, provided
+  that the above copyright notice appear in all copies and that both that
+  copyright notice and this permission notice appear in supporting
+  documentation.  This software is provided "as is" without express or implied
+  warranty.
+=============================================================================*/
+
+/*
+
+  Implemention notes
+
+  Header size is 512 bytes.  There is no MacBinary header.
+
+  White margin which is added for input files with small dimensions
+  is treated separately from the active image raster.  The margins
+  are directly coded based on the number of rows/columns.
+
+  Output file size never exceeds 53072 bytes.  When -norle is specified,
+  output is always 53072 bytes.  It is conceivable that decoders which
+  examine the size of Macpaint files (for general validation or for
+  determination of header type and size) do exist.
+
+  The uncompressed output (-norle case) fully conforms to Macpaint
+  specifications.  No special treatment by the decoder is required.
 */
 
-#include <string.h>
+#include <assert.h>
 
 #include "pm_c_util.h"
 #include "pbm.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+#include "runlength.h"
 #include "macp.h"
 
-#define TRUE		1
-#define FALSE		0
-#define EQUAL		1
-#define UNEQUAL		0
-
 #define MIN3(a,b,c)     (MIN((MIN((a),(b))),(c)))
 
-static void fillbits ARGS(( bit **bits, bit **bitsr, int top, int left, int bottom, int right ));
-static void writemacp ARGS(( bit **bits ));
-static int packit ARGS(( bit *pb, bit *bits ));
-static void filltemp ARGS(( bit *dest, bit *src ));
-static void sendbytes ARGS(( bit *pb, register int npb ));
-static void header ARGS(( void ));
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line, in a form
+       easy for the program to use.
+    */
+    const char * inputFileName;  /* File name of input file */
+    unsigned int left;
+    unsigned int right;
+    unsigned int top;
+    unsigned int bottom;
+    unsigned int leftSpec;
+    unsigned int rightSpec;
+    unsigned int topSpec;
+    unsigned int bottomSpec;
+    bool         norle;
+};
 
-static FILE *fdout;
 
-int
-main(argc, argv)
-int argc;
-char *argv[];
-{ FILE *ifp;
-  register bit **bits, **bitsr;
-  int argn, rows, cols;
-  int left,bottom,right,top;
-  int lflg, rflg, tflg, bflg;
-  const char * const usage = "[-l left] [-r right] [-b bottom] [-t top] [pbmfile]";
-
-
-  pbm_init( &argc, argv );
-
-  argn = 1;
-  fdout = stdout;
-  lflg = rflg = tflg = bflg = 0;
-  left = right = top = bottom = 0;  /* To quiet compiler warning */
-
-  while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
-  { switch ( argv[argn][1] )
-    { case 'l':
-      lflg++;
-      argn++;
-      left = atoi( argv[argn] );
-      break;
-
-      case 'r':
-      rflg++;
-      argn++;
-      right = atoi( argv[argn] );
-      break;
-
-      case 't':
-      tflg++;
-      argn++;
-      top = atoi( argv[argn] );
-      break;
-
-      case 'b':
-      bflg++;
-      argn++;
-      bottom = atoi( argv[argn] );
-      break;
-
-      case '?':
-      default:
-      pm_usage( usage );
+
+static void
+parseCommandLine(int                        argc,
+                 const char **        const argv,
+                 struct CmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   Parse program command line described in Unix standard form by argc
+   and argv.  Return the information in the options as *cmdlineP.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;  /* malloc'ed */
+        /* Instructions to OptParseOptions3 on how to parse our options.  */
+    optStruct3 opt;
+
+    unsigned int norleSpec;
+
+    unsigned int option_def_index;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "left",     OPT_UINT,  &cmdlineP->left,
+            &cmdlineP->leftSpec,     0);
+    OPTENT3(0, "right",    OPT_UINT,  &cmdlineP->right,
+            &cmdlineP->rightSpec,    0);
+    OPTENT3(0, "top",      OPT_UINT,  &cmdlineP->top,
+            &cmdlineP->topSpec,      0);
+    OPTENT3(0, "bottom",   OPT_UINT,  &cmdlineP->bottom,
+            &cmdlineP->bottomSpec,   0);
+    OPTENT3(0, "norle", OPT_FLAG,  NULL,
+            &norleSpec, 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. */
+
+    cmdlineP->norle = norleSpec;
+
+    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 %d", argc-1);
     }
-    ++argn;
-  }
 
-  if ( argn == argc )
-  { ifp = stdin;
-  }
-  else
-  { ifp = pm_openr( argv[argn] );
-    ++argn;
-  }
+    free(option_def);
+}
 
-  if ( argn != argc )
-    pm_usage( usage );
 
-  bitsr = pbm_readpbm( ifp, &cols, &rows );
 
-  pm_close( ifp );
+struct CropPadDimensions {
+    unsigned int imageWidth;   /* Active image content */
+    unsigned int imageHeight;
+    unsigned int leftCrop;     /* Cols cropped off from input */
+    unsigned int topCrop;      /* Rows cropped off from input */
+    unsigned int topMargin;    /* White padding for output */
+    unsigned int bottomMargin;
+    unsigned int leftMargin;
+};
 
-  bits = pbm_allocarray( MAX_COLS, MAX_LINES );
 
-  if( !lflg )
-    left = 0;
 
-  if( rflg )
-    right = MIN3( right, cols - 1, left + MAX_COLS - 1 );
-  else
-    right = MIN( cols - 1,  left + MAX_COLS - 1 );
+static void
+calculateCropPad(struct CmdlineInfo         const cmdline,
+                 unsigned int               const cols,
+                 unsigned int               const rows,
+                 struct CropPadDimensions * const cropPadP) {
+/*--------------------------------------------------------------------------
+  Validate -left -right -top -bottom from command line.
+
+  Determine what rows, columns to take from input if any of these are
+  specified and return it as *cropPadP.
+
+  'cols and 'rows' are the dimensions of the input image.
+
+  Center image if it is smaller than the fixed Macpaint format size.
+----------------------------------------------------------------------------*/
+    unsigned int const left = cmdline.leftSpec ? cmdline.left : 0;
+    unsigned int const top  = cmdline.topSpec  ? cmdline.top  : 0;
+
+    unsigned int right, bottom, width, height;
+
+    if (cmdline.leftSpec) {
+        if (cmdline.rightSpec && left >= cmdline.right)
+            pm_error("-left value must be smaller than -right value");
+        else if (left + 1 > cols)
+            pm_error("Specified -left value is beyond right edge "
+                     "of input image");
+    }
+    if (cmdline.topSpec) {
+        if (cmdline.bottomSpec && top >= cmdline.bottom)
+            pm_error("-top value must be smaller than -bottom value");
+        else if (top + 1 > rows)
+            pm_error("Specified -top value is beyond bottom edge "
+                     "of input image");
+    }
+    if (cmdline.rightSpec) {
+        if (cmdline.right + 1 > cols)
+            pm_message("Specified -right value %u is beyond edge of "
+                       "input image", cmdline.right);
+
+        right = MIN3(cmdline.right, cols - 1, left + MACP_COLS - 1);
+    } else
+        right = MIN(cols - 1,  left + MACP_COLS - 1);
 
-  if( !tflg )
-    top = 0;
+    if (cmdline.bottomSpec) {
+        if (cmdline.bottom + 1 > rows)
+            pm_message("Specified -bottom value %u is beyond edge of "
+                       "input image", cmdline.bottom);
 
-  if( bflg )
-    bottom = MIN3( bottom, rows - 1, top + MAX_LINES - 1);
-  else
-    bottom = MIN( rows - 1, top + MAX_LINES - 1 );
+            bottom = MIN3(cmdline.bottom, rows - 1, top + MACP_ROWS - 1);
+    } else
+        bottom = MIN(rows - 1, top + MACP_ROWS - 1);
 
-    if( right <= left || left < 0 || right - left + 1 > MAX_COLS )
-      pm_error("error in right (= %d) and/or left (=%d)",right,left );
-    if( bottom <= top || top < 0 || bottom - top + 1 > MAX_LINES )
-      pm_error("error in bottom (= %d) and/or top (=%d)",bottom,top );
+    cropPadP->leftCrop = left;
+    cropPadP->topCrop  = top;
 
-  fillbits( bits, bitsr, top, left, bottom, right );
+    assert(right >= left);
 
-  writemacp( bits );
+    width = right - left + 1;
+    assert(width > 0 && width <= MACP_COLS);
 
-  exit( 0 );
+    cropPadP->leftMargin = (MACP_COLS - width) / 2;
 
+    if (width < cols)
+        pm_message("%u of %u input columns will be output", width, cols);
+
+    height = bottom - top + 1;
+    assert(height > 0 && height <= MACP_ROWS);
+
+    cropPadP->topMargin    = (MACP_ROWS - height) / 2;
+    cropPadP->bottomMargin = cropPadP->topMargin + height - 1;
+
+    if (height < rows)
+        pm_message("%u out of %u input rows will be output", height, rows);
+
+    cropPadP->imageWidth  = width;
+    cropPadP->imageHeight = height;
 }
 
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
 
-/* centreer het over te zenden plaatje in het MacPaint document
- *
- * Het plaatje wordt vanaf al of niet opgegeven (left, bottom)
- * in een pbm bitmap van de juist macpaint afmetingen gezet,
- * en eventueel afgekapt.
- */
+
 static void
-fillbits( bits, bitsr, top, left, bottom, right )
-bit **bits, **bitsr;
-int top, left, bottom, right;
-{ register bit *bi, *bir;
-  register int i, j;
-  register int bottomr, leftr, topr, rightr;
-  int width, height;
-
-  width = right - left + 1;
-  leftr = (MAX_COLS - width) / 2;
-  rightr = leftr + width - 1;
-
-  height = bottom - top + 1;
-  topr = ( MAX_LINES - height ) / 2;
-  bottomr = topr + height - 1;
-
-  for( i = 0; i < topr; i++ )
-  { bi = bits[i];
-    for( j = 0; j < MAX_COLS; j++ )
-      *bi++ = 0;
-  }
-
-  for( i = topr; i <= bottomr; i++ )
-  { bi = bits[i];
-    { for( j = 0; j < leftr; j++ )
-	*bi++ = 0;
-      bir = bitsr[ i - topr + top ];
-      for( j = leftr; j <= rightr; j++ )
-	*bi++ = bir[j - leftr + left];
-      for( j = rightr + 1; j < MAX_COLS; j++ )
-	*bi++ = 0;
-  } }
-
-  for( i = bottomr + 1; i < MAX_LINES; i++ )
-  { bi = bits[i];
-    for( j = 0; j < MAX_COLS; j++ )
-      *bi++ = 0;
-  }
-} /* fillbits */
-      
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+writeMacpHeader(FILE * const ofP) {
+
+    char const ch = 0x00;    /* header contains nothing */
+
+    unsigned int i;
+
+    for (i = 0; i < MACP_HEAD_LEN; ++i)
+        fputc(ch, ofP);
+}
+
+
 
 static void
-writemacp( bits )
-bit **bits;
-{ register int i;
-  bit pb[MAX_COLS * 2];
-  int npb;
-
-  header();
-  for( i=0; i < MAX_LINES; i++ )
-  { npb = packit( pb, bits[i] );
-    sendbytes( pb, npb );
-  }
-} /* writemacp */
-
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
-/* pack regel van MacPaint doc in Apple's format
- * return value = # of bytes in pb 
- */
-static int
-packit( pb, bits )
-     bit *pb, *bits;
-{ register int charcount, npb, newcount, flg;
-  bit temp[72];
-  bit *count, *srcb, *destb, save;
-
-  srcb = bits; destb = temp;
-  filltemp( destb, srcb );
-  srcb = temp;
-  destb = pb;
-  npb = 0;
-  charcount = BYTES_WIDE;
-  flg = EQUAL;
-  while( charcount ) { 
-      save = *srcb++;
-      charcount--;
-      newcount = 1;
-      while( charcount && (*srcb == save) ) { 
-          srcb++;
-          newcount++;
-          charcount--;
-      }
-      if( newcount > 2 ) { 
-          count = destb++;
-          *count = 257 - newcount;
-          *destb++ = save;
-          npb += 2;
-          flg = EQUAL;
-      } else { 
-          if( flg == EQUAL ) { 
-              count = destb++;
-              *count = newcount - 1;
-              npb++;
-          } else
-            *count += newcount;
-          while( newcount-- ) { 
-              *destb++ = save;
-              npb++;
-          }
-          flg = UNEQUAL;
-      } 
-  }
-  return npb;
-} /* packit */
-
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+writeMacpRowUnpacked(const bit  * const imageBits,
+                     unsigned int const leftMarginCharCt,
+                     unsigned int const imageColCharCt,
+                     FILE *       const ofP) {
+/*--------------------------------------------------------------------------
+  Encode (without compression) and output one row.  The row comes divided into
+  three parts: left margin, image, right margin.
+----------------------------------------------------------------------------*/
+    char const marginByte = 0x00;  /* White bits for margin */
+    unsigned int const rightMarginCharCt =
+        MACP_COLCHARS - leftMarginCharCt - imageColCharCt;
+    
+    unsigned int i;
+
+    fputc(MACP_COLCHARS - 1, ofP);
+
+    for (i = 0; i < leftMarginCharCt; ++i)
+        fputc(marginByte, ofP);
+
+    if (imageColCharCt > 0)
+        fwrite(imageBits, 1, imageColCharCt, ofP);
+
+    for (i = 0; i < rightMarginCharCt; ++i)
+        fputc(marginByte, ofP);
+}
+
+
 
 static void
-filltemp( dest, src )
-bit *dest, *src;
-{ register unsigned char ch, zero, acht;
-  register int i, j;
-
-  zero = '\0';
-  acht = 8;
-  i = BYTES_WIDE;
-  while( i-- )
-  { ch = zero; 
-    j = acht;
-    while( j-- )
-    { ch <<= 1;
-      if( *src++ )
-	ch++;
+writeMacpRowPacked(const bit  * const packedBits,
+                   unsigned int const leftMarginCharCt,
+                   unsigned int const imageColCharCt,
+                   unsigned int const rightMarginCharCt,
+                   FILE *       const ofP) {
+/*--------------------------------------------------------------------------
+  Encode one row and write it to *ofP.
+
+  As in the unpacked case, the row comes divided into three parts: left
+  margin, image, right margin.  Unlike the unpacked case we need to know both
+  the size of the packed data and the size of the right margin.
+----------------------------------------------------------------------------*/
+    char const marginByte = 0x00;  /* White bits for margin */
+
+    if (leftMarginCharCt > 0) {
+        fputc(257 - leftMarginCharCt, ofP);
+        fputc(marginByte, ofP);
     }
-    *dest++ = ch;
-  }
-} /* filltemp */
 
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+    if (imageColCharCt > 0)
+        fwrite(packedBits, 1, imageColCharCt, ofP);
+
+    if (rightMarginCharCt > 0) {
+        fputc(257 - rightMarginCharCt, ofP);
+        fputc(marginByte, ofP);
+    }
+}
+
+
 
 static void
-sendbytes( pb, npb )
-bit *pb;
-register int npb;
-{ register bit *b;
+writeMacpRow(bit        * const imageBits,
+             unsigned int const leftMarginCharCt,
+             unsigned int const imageColCharCt,
+             bool         const norle,
+             FILE *       const ofP) {
+/*--------------------------------------------------------------------------
+  Write the row 'imageBits' to Standard Output.
+
+  Write it packed, unless packing would lead to unnecessary bloat or 'norle'
+  is true.
+----------------------------------------------------------------------------*/
+    if (norle)
+        writeMacpRowUnpacked(imageBits, leftMarginCharCt, imageColCharCt, ofP);
+    else {
+        unsigned int const rightMarginCharCt =
+            MACP_COLCHARS - leftMarginCharCt - imageColCharCt;
+        unsigned char packedBits[MACP_COLCHARS+1];
+        size_t packedImageLength;
+
+        if (pm_rlenc_maxbytes(MACP_COLCHARS, PM_RLE_PACKBITS)
+            > MACP_COLCHARS + 1)
+            pm_error("INTERNAL ERROR: RLE buffer too small");
+
+        pm_rlenc_compressbyte(imageBits, packedBits, PM_RLE_PACKBITS,
+                              imageColCharCt,  &packedImageLength);
+
+        if (packedImageLength +
+            (leftMarginCharCt  > 0 ? 1 : 0) * 2 +
+            (rightMarginCharCt > 0 ? 1 : 0) * 2
+            < MACP_COLCHARS) {
+            /* It's smaller compressed, so do that */
+            writeMacpRowPacked(packedBits, leftMarginCharCt,
+                               packedImageLength, rightMarginCharCt, ofP);
+        } else { /* Extremely rare */
+            /* It's larger compressed, so do it uncompressed.  See note
+               at top of file.
+            */
+            writeMacpRowUnpacked(imageBits, leftMarginCharCt, imageColCharCt,
+                                 ofP);
+        }
+    }
+}
 
-  b = pb;
-  while( npb-- )
-    (void) putc( *b++, fdout );
-} /* sendbytes */
 
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
 
 static void
-header()
-{ register int i;
-  register char ch;
-
-  /* header contains nothing ... */
-  ch = '\0';
-  for(i = 0; i < HEADER_LENGTH; i++ )
-    (void) putc( ch, fdout );
-} /* header */
+encodeRowsWithShift(bit *                    const bitrow,
+                    FILE *                   const ifP,
+                    int                      const inCols,
+                    int                      const format,
+                    bool                     const norle,
+                    struct CropPadDimensions const cropPad,
+                    FILE *                   const ofP) {
+/*--------------------------------------------------------------------------
+  Shift input rows to put only specified columns to output.  Add padding on
+  left and right if necessary.
+
+  No shift if the input image is the exact size (576 columns) of the Macpaint
+  format.  If the input image is too wide and -left was not specified, extra
+  content on the right is discarded.
+----------------------------------------------------------------------------*/
+    unsigned int const offset     =
+        (cropPad.leftMargin + 8 - cropPad.leftCrop % 8) % 8;
+    unsigned int const leftTrim   =
+        cropPad.leftMargin % 8;
+    unsigned int const rightTrim  =
+        (8 - (leftTrim + cropPad.imageWidth) % 8 ) % 8;
+    unsigned int const startChar  =
+        (cropPad.leftCrop + offset) / 8;
+    unsigned int const imageCharCt =
+        pbm_packed_bytes(leftTrim + cropPad.imageWidth);
+    unsigned int const leftMarginCharCt =
+        cropPad.leftMargin / 8;
+
+    unsigned int row;
+
+    for (row = 0; row < cropPad.imageHeight; ++row) {
+        pbm_readpbmrow_bitoffset(ifP, bitrow, inCols, format, offset);
+        
+        /* Trim off fractional margin portion in first byte of image data */
+        if (leftTrim > 0) {
+            bitrow[startChar] <<= leftTrim;
+            bitrow[startChar] >>= leftTrim;
+        }
+        /* Do the same with bits in last byte of relevant image data */
+        if (rightTrim > 0) {
+            bitrow[startChar + imageCharCt - 1] >>= rightTrim;
+            bitrow[startChar + imageCharCt - 1] <<= rightTrim;
+        }
+
+        writeMacpRow(&bitrow[startChar], leftMarginCharCt,
+                     imageCharCt, norle, ofP);
+    }
+}
+
+
+
+static void
+writeMacp(unsigned int             const cols,
+          unsigned int             const rows,
+          int                      const format,
+          FILE *                   const ifP,
+          bool                     const norle,
+          struct CropPadDimensions const cropPad,
+          FILE *                   const ofP) {
+
+    unsigned int row, skipRow;
+    bit * bitrow;
+
+    writeMacpHeader(ofP);
+
+    /* Write top padding */
+    for (row = 0; row < cropPad.topMargin; ++row)
+        writeMacpRow(NULL, MACP_COLCHARS, 0, norle, ofP);
+
+    /* Allocate PBM row with one extra byte for the shift case. */
+    bitrow = pbm_allocrow_packed(cols + 8);
+
+    for (skipRow = 0; skipRow < cropPad.topCrop; ++skipRow)
+        pbm_readpbmrow_packed(ifP, bitrow, cols, format);
+
+    encodeRowsWithShift(bitrow, ifP, cols, format, norle, cropPad, ofP);
+
+    pbm_freerow_packed(bitrow);
+
+    /* Add bottom padding */
+    for (row = cropPad.bottomMargin + 1; row < MACP_ROWS; ++row)
+        writeMacpRow(NULL, MACP_COLCHARS, 0, norle, ofP);
+}
+
+
+
+int
+main(int argc, const char *argv[]) {
+
+    FILE * ifP;
+    int rows, cols;
+    int format;
+    struct CmdlineInfo cmdline;
+    struct CropPadDimensions cropPad;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    pbm_readpbminit(ifP, &cols, &rows, &format);
+
+    calculateCropPad(cmdline, cols, rows, &cropPad);
+
+    writeMacp(cols, rows, format, ifP, cmdline.norle, cropPad, stdout);
+
+    pm_close(ifP);
+
+    return 0;
+}
+
diff --git a/converter/pbm/pbmtomatrixorbital.c b/converter/pbm/pbmtomatrixorbital.c
index 96e1406a..41f8e260 100644
--- a/converter/pbm/pbmtomatrixorbital.c
+++ b/converter/pbm/pbmtomatrixorbital.c
@@ -1,3 +1,5 @@
+#include <stdio.h>
+
 #include "pbm.h"
 
 /* By Bryan Henderson, San Jose CA 2003.09.06.
@@ -12,10 +14,10 @@
 
 
 static void
-generateMo(FILE * const ofP, 
-           bit ** const bits,
-           int    const cols,
-           int    const rows) {
+generateMo(FILE *       const ofP, 
+           bit **       const bits,
+           unsigned int const cols,
+           unsigned int const rows) {
 
     unsigned int col;
 
@@ -51,37 +53,40 @@ generateMo(FILE * const ofP,
 
 
 int
-main(int argc, char * argv[]) {
+main(int argc, const char ** argv) {
 
-    FILE* ifp;
-    bit** bits;
+    FILE * ifP;
+    bit ** bits;
     int rows, cols;
     const char * inputFilename;
 
-    pbm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     if (argc-1 > 1)
-        pm_error("Too many arguments (%d).  The only valid argument is an "
+        pm_error("Too many arguments (%u).  The only valid argument is an "
                  "input file name.", argc-1);
     else if (argc-1 == 1) 
         inputFilename = argv[1];
     else
         inputFilename = "-";
 
-    ifp = pm_openr(inputFilename);
+    ifP = pm_openr(inputFilename);
     
-    bits = pbm_readpbm(ifp, &cols, &rows);
+    bits = pbm_readpbm(ifP, &cols, &rows);
 
     if (rows > 255)
-        pm_error("Image is too high:  %d rows.  Max height: 255 rows", rows);
+        pm_error("Image is too high:  %u rows.  Max height: 255 rows", rows);
     if (cols > 255)
-        pm_error("Image is too wide:  %d cols.  Max width: 255 cols", cols);
+        pm_error("Image is too wide:  %u cols.  Max width: 255 cols", cols);
 
     generateMo(stdout, bits, cols, rows);
     
-    pm_close(ifp);
+    pm_close(ifP);
 
     pbm_freearray(bits, rows);
 
-    exit(0);
+    return 0;
 }
+
+
+
diff --git a/converter/pbm/pbmtomgr.c b/converter/pbm/pbmtomgr.c
index d12e6635..e8e30148 100644
--- a/converter/pbm/pbmtomgr.c
+++ b/converter/pbm/pbmtomgr.c
@@ -89,11 +89,7 @@ main(int argc,
         size_t bytesWritten;
 
         pbm_readpbmrow_packed(ifP, bitrow, cols, format);
-        
-        if (padright > 0) {
-            bitrow[bytesPerRow-1] >>= padright;
-            bitrow[bytesPerRow-1] <<= padright;
-        }
+        pbm_cleanrowend_packed(bitrow, cols);
 
         bytesWritten = fwrite(bitrow, 1, bytesPerRow, stdout);
         if (bytesWritten != bytesPerRow )
diff --git a/converter/pbm/pbmtonokia.c b/converter/pbm/pbmtonokia.c
index b8057393..bf3b9e41 100644
--- a/converter/pbm/pbmtonokia.c
+++ b/converter/pbm/pbmtonokia.c
@@ -4,6 +4,7 @@
    Copyright information is at end of file.
 */
 
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
 #define _BSD_SOURCE    /* Make sure strcaseeq() is in nstring.h */
 #include <string.h>
 #include <assert.h>
@@ -45,7 +46,7 @@ uppercase(const char * const subject) {
 
     if (buffer == NULL)
         pm_error("Out of memory allocating buffer for uppercasing a "
-                 "%u-character string", strlen(subject));
+                 "%u-character string", (unsigned)strlen(subject));
     else {
         unsigned int i;
 
@@ -69,7 +70,7 @@ parseCommandLine(int argc, char ** argv,
    was passed to us as the argv array.
 -----------------------------------------------------------------------------*/
     optEntry * option_def;
-        /* Instructions to optParseOptions3 on how to parse our options.
+        /* Instructions to pm_optParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
 
@@ -92,7 +93,7 @@ parseCommandLine(int argc, char ** argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (fmtSpec) {
@@ -117,8 +118,8 @@ parseCommandLine(int argc, char ** argv,
     if (netSpec) {
         if (strlen(netOpt) != 6)
             pm_error("-net option must be 6 hex digits long.  "
-                     "You specified %u characters", strlen(netOpt));
-        else if (!strishex(netOpt))
+                     "You specified %u characters", (unsigned)strlen(netOpt));
+        else if (!pm_strishex(netOpt))
             pm_error("-net option must be hexadecimal.  You specified '%s'",
                      netOpt);
         else
@@ -131,7 +132,7 @@ parseCommandLine(int argc, char ** argv,
     else if (strlen(cmdlineP->txt) > 120)
         pm_error("Text message is longer (%u characters) than "
                  "the 120 characters allowed by the format.",
-                 strlen(cmdlineP->txt));
+                 (unsigned)strlen(cmdlineP->txt));
 
     if (argc-1 == 0) 
         cmdlineP->inputFileName = "-";
@@ -147,7 +148,7 @@ parseCommandLine(int argc, char ** argv,
 static void
 freeCmdline(struct cmdlineInfo const cmdline) {
 
-    strfree(cmdline.networkCode);
+    pm_strfree(cmdline.networkCode);
 }
 
 
@@ -253,7 +254,7 @@ convertToHexNpm(bit **       const image,
 
         unsigned int it;
 
-        fprintf(ofP, "00%04X", len);
+        fprintf(ofP, "00%04X", (unsigned)len);
 
         for (it = 0; it < len; ++it)
             fprintf(ofP, "%02X", text[it]);
diff --git a/converter/pbm/pbmtopi3.c b/converter/pbm/pbmtopi3.c
index 1dbf1a71..791bcb50 100644
--- a/converter/pbm/pbmtopi3.c
+++ b/converter/pbm/pbmtopi3.c
@@ -1,4 +1,4 @@
-/* pbmtopi3.c - read a portable bitmap and produce a Atari Degas .pi3 file
+/* pbmtopi3.c - read a PBM image and produce a Atari Degas .pi3 file
 **
 ** Module created from other pbmplus tools by David Beckemeyer.
 **
@@ -12,107 +12,87 @@
 ** implied warranty.
 */
 
+/* Output file should always be 32034 bytes. */
+
 #include <stdio.h>
-#include "pbm.h"
 #include "pm_c_util.h"
+#include "pbm.h"
 
-static void putinit ARGS(( void ));
-static void putbit ARGS(( bit b ));
-static void putrest ARGS(( void ));
-static void putitem ARGS(( void ));
-
-int
-main( argc, argv )
-    int argc;
-    char* argv[];
-    {
-    FILE* ifp;
-    bit* bitrow;
-    register bit* bP;
-    int inrows, incols, format, padright, row, col;
-    int const outcols = 640;
-    int const outrows = 400;
-
-    pbm_init( &argc, argv );
-
-    if ( argc > 2 )
-	pm_usage( "[pbmfile]" );
-
-    if ( argc == 2 )
-	ifp = pm_openr( argv[1] );
-    else
-	ifp = stdin;
-
-    pbm_readpbminit( ifp, &incols, &inrows, &format );
-    bitrow = pbm_allocrow( MAX(incols, outcols) );
-
-    /* Compute padding to round cols up to 640 */
-    if(incols < outcols)
-        padright = outcols - incols;
-    else 
-        padright = 0;
-
-    putinit( );
-    for ( row = 0; row < MIN(inrows, outrows); ++row )
-	{
-	pbm_readpbmrow( ifp, bitrow, incols, format );
-        for ( col = 0, bP = bitrow; col < MIN(incols, outcols); ++col, ++bP )
-	    putbit( *bP );
-	for ( col = 0; col < padright; ++col )
-	    putbit( 0 );
-        }
-    while (row++ < outrows)
-	for ( col = 0; col < outcols; ++col)
-	    putbit( 0 );
-
-    pm_close( ifp );
-
-    putrest( );
-
-    exit( 0 );
-    }
 
-static char item;
-static short bitsperitem, bitshift;
 
 static void
-putinit( )
-    {
-    int i;
-    if (pm_writebigshort (stdout, (short) 2) == -1
-	|| pm_writebigshort (stdout, (short) 0x777) == -1)
-      pm_error ("write error");
-    for (i = 1; i < 16; i++)
-      if (pm_writebigshort (stdout, (short) 0) == -1)
-	pm_error ("write error");
-    item = 0;
-    bitsperitem = 0;
-    bitshift = 7;
+putinit(FILE * const ofP)  {
+
+    unsigned int i;
+
+    pm_writebigshort(ofP, (short) 2);
+    pm_writebigshort(ofP, (short) 0x777);
+
+    for (i = 1; i < 16; ++i) {
+        pm_writebigshort (ofP, (short) 0);
     }
+}
 
-static void
-putbit( bit b )
-    {
-    if (bitsperitem == 8)
-	putitem( );
-    ++bitsperitem;
-    if ( b == PBM_BLACK )
-	item += 1 << bitshift;
-    --bitshift;
+
+
+int
+main(int argc, const char ** argv) {
+
+    unsigned int const outRows = 400;
+    unsigned int const outCols = 640;
+    unsigned int const outColByteCt = pbm_packed_bytes(outCols);
+
+    FILE * ifP;
+
+    int inRows, inCols, format;
+    unsigned int row;
+    unsigned int inColByteCt;
+    unsigned int i;
+    bit * bitrow;
+
+    pm_proginit(&argc, argv);
+
+    if (argc-1 < 1)
+        ifP = stdin;
+    else  {
+        ifP = pm_openr(argv[1]);
+
+        if (argc-1 > 1)
+            pm_error("Too many arguments.  The only possible argument "
+                     "is the input file name");
     }
 
-static void
-putrest( )
-    {
-    if ( bitsperitem > 0 )
-	putitem( );
+    pbm_readpbminit(ifP, &inCols, &inRows, &format);
+
+    inColByteCt = pbm_packed_bytes(inCols);
+
+    bitrow = pbm_allocrow_packed(MAX(outCols, inCols));
+    
+    /* Add padding to round cols up to 640 */
+    for (i = inColByteCt; i < outColByteCt; ++i)
+        bitrow[i] = 0x00;
+
+    putinit(stdout);
+
+    for (row = 0; row < MIN(inRows, outRows); ++row) {
+        pbm_readpbmrow_packed(ifP, bitrow, inCols, format);
+        pbm_cleanrowend_packed(bitrow, inCols);
+        fwrite (bitrow, outColByteCt, 1, stdout);
     }
+    pm_close(ifP);
 
-static void
-putitem( )
-    {
-    putc (item, stdout);
-    item = 0;
-    bitsperitem = 0;
-    bitshift = 7;
+    if (row < outRows)  {
+        unsigned int i;
+
+        /* Clear entire row */
+        for (i = 0; i < outColByteCt; ++i)
+            bitrow[i] = 0x00;
+
+        while (row++ < outRows)
+            fwrite(bitrow, outColByteCt, 1, stdout);
     }
+
+    pbm_freerow_packed(bitrow);
+
+    return 0;
+}
diff --git a/converter/pbm/pbmtopk.c b/converter/pbm/pbmtopk.c
index fc94f855..3948ae0d 100644
--- a/converter/pbm/pbmtopk.c
+++ b/converter/pbm/pbmtopk.c
@@ -1,7 +1,12 @@
 /*
   pbmtopk, adapted from "pxtopk.c by tomas rokicki" by AJCD 1/8/90
   
-  compile with: cc -o pbmtopk pbmtopk.c -lm -lpbm
+  References (retrieved May 31 2015):
+  Packed (PK) Font File Format 
+  https://www.tug.org/TUGboat/tb06-3/tb13pk.pdf
+
+  Tex Font Metric Files (TFM)
+  https://www.tug.org/TUGboat/tb06-1/tb11gf.pdf
 */
 
 #define _BSD_SOURCE 1      /* Make sure strdup() is in string.h */
@@ -26,6 +31,29 @@
 #define MAXPARAMS 30
 #define NAMELENGTH 80
 
+/*-----------------------------------------------------------------------
+Macros to handle fixed point numbers
+
+This program uses uses fixed-point numbers to store data where
+normally a floating-point data type (float or double) would be
+employed.
+
+Numbers that contain fractions are stored as signed integers.
+The 20 least-significant bits are for the fractional part, the rest
+(12 bits assuming that int is 32 bit) are for the integer part.
+The technical term for this is "Q20" or "Q12.20" notation.
+
+Float/double data is converted to Q20 fixed point by multiplying
+by 2^20 (= 1048576).  The opposite conversion is conducted by
+dividing by 2^20.
+
+The Q20 data must be within the range -16 < r < 16.  The reason
+behind this restriction is unclear.  The program generally writes
+Q20 data to the output files in 32 bits.  (Exception: in function
+shipchar() there is a provision to write Q20 data in 24 bits,
+provided that 24 bits is sufficient.)
+---------------------------------------------------------------------*/
+
 #define fixword(d) ((int)((double)(d)*1048576))
 #define unfixword(f) ((double)(f) / 1048576)
 #define fixrange(f) ((f) < 16777216 && (f) > -16777216)
diff --git a/converter/pbm/pbmtoppa/Makefile b/converter/pbm/pbmtoppa/Makefile
index 5f205230..cf31ded6 100644
--- a/converter/pbm/pbmtoppa/Makefile
+++ b/converter/pbm/pbmtoppa/Makefile
@@ -9,17 +9,18 @@ include $(BUILDDIR)/config.mk
 
 all: pbmtoppa
 
-BINARIES = pbmtoppa
+PORTBINARIES = pbmtoppa
+
+BINARIES = $(PORTBINARIES)
 
 MERGEBINARIES = $(BINARIES)
 
-OBJECTS = pbmtoppa.o ppa.o pbm.o cutswath.o
-MERGE_OBJECTS = pbmtoppa.o2 ppa.o pbm.o cutswath.o
+ADDL_OBJECTS = ppa.o pbm.o cutswath.o
 
-include $(SRCDIR)/common.mk
+OBJECTS = pbmtoppa.o $(ADDL_OBJECTS)
 
-pbmtoppa: $(OBJECTS) $(NETPBMLIB) $(LIBOPT)
-	$(LD) -o pbmtoppa $(OBJECTS) \
-	  -lm $(shell $(LIBOPT) $(NETPBMLIB)) $(LDFLAGS) $(LDLIBS) \
-	  $(RPATH) $(LADD)
+MERGE_OBJECTS = pbmtoppa.o2 $(ADDL_OBJECTS)
+
+include $(SRCDIR)/common.mk
 
+pbmtoppa: $(OBJECTS)
diff --git a/converter/pbm/pbmtopsg3.c b/converter/pbm/pbmtopsg3.c
index 54d0a0a0..8163b70a 100644
--- a/converter/pbm/pbmtopsg3.c
+++ b/converter/pbm/pbmtopsg3.c
@@ -60,7 +60,7 @@ parseCommandLine(int argc, char ** argv,
     opt.short_allowed = FALSE;
     opt.allowNegNum = FALSE;
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
 
     if (argc-1 == 0)
         cmdlineP->inputFilespec = "-";
@@ -323,7 +323,7 @@ doPages(FILE *         const ifP,
         unsigned int * const pagesP,
         double         const dpi) {
 
-    bool eof;
+    int eof;
     unsigned int pagesDone;
 
     eof = FALSE;
diff --git a/converter/pbm/pbmtoptx.c b/converter/pbm/pbmtoptx.c
index 8cd60326..c0fb0f80 100644
--- a/converter/pbm/pbmtoptx.c
+++ b/converter/pbm/pbmtoptx.c
@@ -12,84 +12,79 @@
 
 #include "pbm.h"
 
-static void putinit ARGS(( void ));
-static void putbit ARGS(( bit b ));
-static void putrest ARGS(( void ));
-static void putitem ARGS(( void ));
+/* Follwing is obtained by reversing bit order (MFS-LFS) and adding 64. */
+/* Note the two escape sequences: \\ and \x7f . */
 
-int
-main( argc, argv )
-int argc;
-char *argv[];
-    {
-    FILE *ifp;
-    register bit *bitrow, *bP;
-    int rows, cols, format, row, col;
-    const char * const usage = "[pbmfile]";
-
-    pbm_init( &argc, argv );
-
-    if ( argc > 2 )
-	pm_usage( usage );
-
-    if ( argc == 2 )
-	ifp = pm_openr( argv[1] );
-    else
-	ifp = stdin;
-
-    pbm_readpbminit( ifp, &cols, &rows, &format );
-    bitrow = pbm_allocrow( cols );
-
-    putinit( );
-    for ( row = 0; row < rows; row++ )
-	{
-	pbm_readpbmrow( ifp, bitrow, cols, format );
-        for ( col = 0, bP = bitrow; col < cols; col++, bP++ )
-	    putbit( *bP );
-	putrest( );
-	putchar( 5 );
-	putchar( '\n' );
-        }
+static unsigned char const ptxchar[64] = 
+  "@`PpHhXxDdTtLl\\|BbRrJjZzFfVvNn^~AaQqIiYyEeUuMm]}CcSsKk[{GgWwOo_\x7f";
 
-    pm_close( ifp );
-    
-    exit( 0 );
-    }
 
-static char item;
-static int bitsperitem, bitshift;
 
 static void
-putinit( )
-    {
-    bitsperitem = 0;
-    item = 64;
-    bitshift = 0;
-    }
+putBitrow(const bit *  const bitrow,
+          unsigned int const cols) {
+/*----------------------------------------------------------------------------
+  Pick up items in 6 bit units from bitrow and convert each to ptx format.
+----------------------------------------------------------------------------*/
+    unsigned int itemCnt;
 
-static void
-putbit( bit b )
-    {
-    if ( bitsperitem == 6 )
-	putitem( );
-    if ( b == PBM_BLACK )
-	item += 1 << bitshift;
-    bitsperitem++;
-    bitshift++;
+    for (itemCnt = 0; itemCnt * 6 < cols; ++itemCnt) {
+        unsigned int const byteCnt = (itemCnt * 6) / 8;
+        bit const byteCur  = bitrow[byteCnt];
+        bit const byteNext = bitrow[byteCnt + 1];
+        
+        unsigned int item;
+
+        switch (itemCnt % 4) {
+        case 0: item = byteCur >> 2;                 break;
+        case 1: item = byteCur << 4 | byteNext >> 4; break;
+        case 2: item = byteCur << 2 | byteNext >> 6; break;
+        case 3: item = byteCur;                      break;
+        }
+        putchar(ptxchar[item & 0x3f]);
     }
+    putchar(5); putchar('\n');  /* end of row mark */
+}
 
-static void
-putrest( )
-    {
-    if ( bitsperitem > 0 )
-	putitem( );
+
+
+int
+main(int argc, const char ** argv)  {
+
+    FILE * ifP;
+    bit * bitrow;
+    int rows, cols, format;
+    unsigned int row;
+
+    pm_proginit(&argc, argv);
+
+    if (argc-1 < 1)
+        ifP = stdin;
+    else {
+        ifP = pm_openr(argv[1]);
+        
+        if (argc-1 > 1)
+            pm_error("Too many arguments.  The only possible argument is "
+                     "the input fil name");
     }
 
-static void
-putitem( )
-    {
-    putchar( item );
-    bitsperitem = 0;
-    item = 64;
-    bitshift = 0;
+    pbm_readpbminit(ifP, &cols, &rows, &format);
+
+    bitrow = pbm_allocrow_packed(cols + 8);
+
+    bitrow[pbm_packed_bytes(cols)] = 0x00;
+
+    for (row = 0; row < rows; ++row) {
+        pbm_readpbmrow_packed(ifP, bitrow, cols, format);
+        pbm_cleanrowend_packed(bitrow, cols);
+        putBitrow(bitrow, cols);
     }
+
+    pbm_freerow_packed(bitrow);
+    pm_close(ifP);
+    
+    return 0;
+}
+
+
+
diff --git a/converter/pbm/pbmtoicon.c b/converter/pbm/pbmtosunicon.c
index d5fefb76..95deab7c 100644
--- a/converter/pbm/pbmtoicon.c
+++ b/converter/pbm/pbmtosunicon.c
@@ -1,4 +1,4 @@
-/* pbmtoicon.c - read a PBM image and produce a Sun icon file
+/* pbmtosunicon.c - read a PBM image and produce a Sun icon file
 **
 ** Copyright (C) 1988 by Jef Poskanzer.
 **
@@ -17,41 +17,46 @@
    Retired bitwise transformation functions.
 */
 
-#include "wordaccess.h"
+#include "pm_config.h"
 #include "pbm.h"
 
-static unsigned short int itemBuff[8];
-static unsigned int itemCnt;    /* takes values 0 to 8 */
-FILE * putFp;
+static struct ItemPutter {
+    unsigned short int itemBuff[8];
+    unsigned int       itemCnt;    /* takes values 0 to 8 */
+    FILE *             putFp;
+} ip;
 
 
 
 static void
 putinit(FILE * const ofP) {
-    putFp = ofP;
-    itemCnt = 0;
+    ip.putFp   = ofP;
+    ip.itemCnt = 0;
 }
 
 
 
 static void
-putitem(wordint const item) {
+putitem(uint16_t const item) {
 
-    if (itemCnt == 8 ) {
+    if (ip.itemCnt == 8 ) {
         /* Buffer is full.  Write out one line. */
         int rc;
     
-        rc = fprintf(putFp,
+        rc = fprintf(ip.putFp,
                      "\t0x%04x,0x%04x,0x%04x,0x%04x,"
                      "0x%04x,0x%04x,0x%04x,0x%04x,\n",
-                     itemBuff[0],itemBuff[1],itemBuff[2],itemBuff[3],
-                     itemBuff[4],itemBuff[5],itemBuff[6],itemBuff[7]);
+                     ip.itemBuff[0], ip.itemBuff[1],
+                     ip.itemBuff[2], ip.itemBuff[3],
+                     ip.itemBuff[4], ip.itemBuff[5],
+                     ip.itemBuff[6], ip.itemBuff[7]);
         if (rc < 0)        
            pm_error("fprintf() failed to write Icon bitmap");
            
-        itemCnt = 0;
+        ip.itemCnt = 0;
     }
-    itemBuff[itemCnt++] = item & 0xffff;  /* Only lower 16 bits are used */
+    ip.itemBuff[ip.itemCnt++] = item & 0xffff;
+        /* Only lower 16 bits are used */
 }
 
 
@@ -61,10 +66,11 @@ putterm(void) {
 
     unsigned int i;
 
-    for (i = 0; i < itemCnt; ++i) {
+    for (i = 0; i < ip.itemCnt; ++i) {
         int rc;
-        rc = fprintf(putFp, "%s0x%04x%c", i == 0  ? "\t" : "", itemBuff[i],
-                     i == itemCnt - 1 ? '\n' : ',');
+        rc = fprintf(ip.putFp, "%s0x%04x%c", i == 0  ? "\t" : "",
+                     ip.itemBuff[i],
+                     i == ip.itemCnt - 1 ? '\n' : ',');
         if (rc < 0)        
             pm_error("fprintf() failed to write Icon bitmap");
     }
@@ -98,58 +104,31 @@ writeIcon(FILE *       const ifP,
           int          const format,
           FILE *       const ofP) {
 
-    unsigned int const wordintSize = sizeof(wordint) * 8;
-        /* wordintSize is usually 32 or 64 bits.  Must be at least 24. */
     unsigned int const items = (cols + 15) / 16;
-    unsigned int const bitrowBytes = pbm_packed_bytes(cols);
     unsigned int const pad = items * 16 - cols;
-    /* 'padleft' is added to the output.  'padbyte' is for cleaning
-       the input
-    */
-    unsigned int const padleft = pad / 2;
-    unsigned int const padbyte = bitrowBytes * 8 - cols;
-    unsigned int const shift   = (wordintSize - 24) + padleft;
-    
-    unsigned char * bitbuffer;
-    unsigned char * bitrow;
+
+    unsigned char * const bitrow = pbm_allocrow_packed(items * 16);
     unsigned int row;
 
-    bitbuffer = pbm_allocrow_packed(cols + wordintSize);
-    bitrow = &bitbuffer[1];
-    bitbuffer[0] = 0;
-    bitrow[bitrowBytes] = 0;
-    
+    bitrow[0] = bitrow[items * 2 - 1] = 0;
+
     writeIconHeader(ofP, cols + pad, rows);
 
     putinit(ofP);
 
     for (row = 0; row < rows; ++row) {
         unsigned int itemSeq;
-        pbm_readpbmrow_packed(ifP, bitrow, cols, format);
 
-        /* Clear post-data junk in final partial byte */
-        if (padbyte > 0) {
-            bitrow[bitrowBytes-1] >>= padbyte;
-            bitrow[bitrowBytes-1] <<= padbyte;
-        }
-        
+        pbm_readpbmrow_bitoffset(ifP, bitrow, cols, format, pad/2);
+
         for (itemSeq = 0; itemSeq < items; ++itemSeq) {
-            /* Scoop up bits, shift-align, send to format & print function.
-    
-               An item is 16 bits, typically spread over 3 bytes due to
-               left-padding.  We use wordint here to scoop up 4 (or more)
-               consecutive bytes.  An item always resides within the higher
-               24 bits of each scoop.  It is essential to use wordint
-               (or rather the wordaccess function bytesToWordInt() ); 
-               simple long, uint_32t, etc. do not work for they are not
-               shift-tolerant.
-            */
+            /* Read bits from bitrow, send to format & print function. */
             
-            wordint const scoop = bytesToWordint(&bitbuffer[itemSeq*2]);
-            putitem (scoop >> shift);
+            putitem((bitrow[itemSeq*2]<<8) + bitrow[itemSeq*2+1]);
         }
     }
-    putterm();    
+    putterm();
+    pbm_freerow_packed(bitrow);
 }
 
 
diff --git a/converter/pbm/pbmtoxbm.c b/converter/pbm/pbmtoxbm.c
index 340642ce..14c6b85e 100644
--- a/converter/pbm/pbmtoxbm.c
+++ b/converter/pbm/pbmtoxbm.c
@@ -23,6 +23,7 @@
 #define _BSD_SOURCE 1      /* Make sure strdup() is in string.h */
 #define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
 
+#include <assert.h>
 #include <string.h>
 
 #include "pm_c_util.h"
@@ -35,7 +36,7 @@
 
 enum xbmVersion { X10, X11 };
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -46,8 +47,8 @@ struct cmdlineInfo {
 
 static void
 parseCommandLine(int                 argc, 
-                 char **             argv,
-                 struct cmdlineInfo *cmdlineP ) {
+                 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.  
@@ -58,8 +59,8 @@ parseCommandLine(int                 argc,
    Note that the strings we return are stored in the storage that
    was passed to us as the argv array.  We also trash *argv.
 -----------------------------------------------------------------------------*/
-    optEntry *option_def;
-    /* Instructions to optParseOptions3 on how to parse our options. */
+    optEntry * option_def;
+    /* Instructions to pm_optParseOptions3 on how to parse our options. */
 
     optStruct3 opt;
     unsigned int option_def_index;
@@ -76,14 +77,14 @@ parseCommandLine(int                 argc,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    optParseOptions3( &argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (!nameSpec)
         cmdlineP->name = NULL;
     else if (strlen(cmdlineP->name) > 56)
         pm_error("Image name too long: %d chars. (max 56)",
-                 strlen(cmdlineP->name));
+                 (unsigned)strlen(cmdlineP->name));
     else if (!ISALPHA(cmdlineP->name[0]) && cmdlineP->name[0] !='_')
         pm_error("Image name '%s' starts with non-alphabet character.",
                   cmdlineP->name);
@@ -111,6 +112,7 @@ parseCommandLine(int                 argc,
             pm_error("Program takes zero or one argument (filename).  You "
                      "specified %u", argc-1);
     }
+    free(option_def);
 }
 
 
@@ -242,18 +244,22 @@ puttermX10(void) {
 
     unsigned int i;
 
+    assert(itemCnt % 2 == 0);
+
     for (i = 0; i < itemCnt; i += 2) {
         int rc;
 
+        assert(i + 1 < itemCnt);
+
         rc = printf("%s0x%02x%02x%s",
                     (i == 0) ? " " : "",
                     itemBuff[i+1],
                     itemBuff[i], 
-                    (i == itemCnt - 2) ? "" : ",");
+                    (i + 2 >= itemCnt) ? "" : ",");
         if (rc < 0)        
-            pm_error("Error writing end of X10 bitmap raster.  "
+            pm_error("Error writing Item %u at end of X10 bitmap raster.  "
                      "printf() failed with errno %d (%s)",
-                     errno, strerror(errno));
+                     i, errno, strerror(errno));
     }
 }
 
@@ -270,12 +276,12 @@ puttermX11(void) {
         rc = printf("%s0x%02x%s",
                     (i == 0)  ? " " : "",
                     itemBuff[i],
-                    (i == itemCnt - 1) ? "" : ",");
+                    (i + 1 >= itemCnt) ? "" : ",");
 
         if (rc < 0)        
-            pm_error("Error writing end of X11 bitmap raster.  "
+            pm_error("Error writing Item %u at end of X11 bitmap raster.  "
                      "printf() failed with errno %d (%s)",
-                     errno, strerror(errno));
+                     i, errno, strerror(errno));
     }
 }
 
@@ -319,8 +325,8 @@ writeXbmHeader(enum xbmVersion const xbmVersion,
                unsigned int    const height,
                FILE *          const ofP) {
 
-    printf("#define %s_width %d\n", name, width);
-    printf("#define %s_height %d\n", name, height);
+    printf("#define %s_width %u\n", name, width);
+    printf("#define %s_height %u\n", name, height);
     printf("static %s %s_bits[] = {\n",
            xbmVersion == X10 ? "short" : "char",
            name);
@@ -337,8 +343,7 @@ convertRaster(FILE *          const ifP,
               enum xbmVersion const xbmVersion) {
               
     unsigned int const bitsPerUnit = xbmVersion == X10 ? 16 : 8;   
-    unsigned int const padright =
-        ((cols + bitsPerUnit - 1 ) / bitsPerUnit) * bitsPerUnit - cols;
+    unsigned int const padright = ROUNDUP(cols, bitsPerUnit) - cols;
         /* Amount of padding to round cols up to the nearest multiple of 
            8 (if x11) or 16 (if x10).
         */
@@ -352,21 +357,15 @@ convertRaster(FILE *          const ifP,
     bitrow = pbm_allocrow_packed(cols + padright);
     
     for (row = 0; row < rows; ++row) {
-        int const bitrowInBytes = pbm_packed_bytes(cols);
-        int const padrightIn    = bitrowInBytes * 8 - cols;
-
         unsigned int i;
 
         pbm_readpbmrow_packed(ifP, bitrow, cols, format);
+        pbm_cleanrowend_packed(bitrow, cols);
 
-        if (padrightIn > 0) {
-            bitrow[bitrowInBytes - 1] >>= padrightIn;
-            bitrow[bitrowInBytes - 1] <<= padrightIn;
-        }
-
-        if (padright >= 8)
+        if (padright >= 8) {
+            assert(bitrowBytes > 0);
             bitrow[bitrowBytes-1] = 0x00;
-
+        }
         for (i = 0; i < bitrowBytes; ++i)
             putitem(bitrow[i]);
     }
@@ -379,15 +378,15 @@ convertRaster(FILE *          const ifP,
 
 
 int
-main(int    argc,
-     char * argv[]) {
+main(int           argc,
+     const char ** argv) {
 
-    struct cmdlineInfo cmdline; 
+    struct CmdlineInfo cmdline; 
     FILE * ifP;
     int rows, cols, format;
     const char * name;
 
-    pbm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
     if (cmdline.name == NULL) 
@@ -403,9 +402,11 @@ main(int    argc,
 
     convertRaster(ifP, cols, rows, format, stdout, cmdline.xbmVersion);
 
-    strfree(name);
+    pm_strfree(name);
     pm_close(ifP);
 
     return 0;
 }
 
+
+
diff --git a/converter/pbm/pbmtoybm.c b/converter/pbm/pbmtoybm.c
index 508e8e92..27ce6cb1 100644
--- a/converter/pbm/pbmtoybm.c
+++ b/converter/pbm/pbmtoybm.c
@@ -9,100 +9,89 @@
 ** copyright notice and this permission notice appear in supporting
 ** documentation.  This software is provided "as is" without express or
 ** implied warranty.
+**
+** Feb 2010 afu
+** Added dimension check to prevent short int from overflowing
+** Changed code style (ANSI-style function definitions, etc.)
 */
 
 #include <stdio.h>
+
+#include "pm.h"
 #include "pbm.h"
+#include "bitreverse.h"
 
 #define YBM_MAGIC  ( ( '!' << 8 ) | '!' )
+#define INT16MAX 32767
+
+static void
+putinit(int const cols,
+        int const rows) {
+
+    pm_writebigshort(stdout, YBM_MAGIC);
+    pm_writebigshort(stdout, cols);
+    pm_writebigshort(stdout, rows);
+}
+
 
-static void putinit ARGS(( int cols, int rows ));
-static void putbit ARGS(( bit b ));
-static void putrest ARGS(( void ));
-static void putitem ARGS(( void ));
 
 int
-main( argc, argv )
-    int argc;
-    char* argv[];
-    {
-    FILE* ifp;
-    bit* bitrow;
-    register bit* bP;
-    int rows, cols, format, padright, row, col;
-
-
-    pbm_init( &argc, argv );
-
-    if ( argc > 2 )
-	pm_usage( "[pbmfile]" );
-    if ( argc == 2 )
-	ifp = pm_openr( argv[1] );
-    else
-	ifp = stdin;
-
-    pbm_readpbminit( ifp, &cols, &rows, &format );
-    bitrow = pbm_allocrow( cols );
+main(int argc, const char *argv[]) {
+
+    FILE * ifP;
+    bit * bitrow;
+    int rows;
+    int cols;
+    int format;
+    unsigned int row;
+    const char * inputFileName;
+
+    pm_proginit(&argc, argv);
+
+    if (argc-1 < 1)
+        inputFileName = "-";
+    else {
+        inputFileName = argv[1];
+
+        if (argc-1 > 1)
+            pm_error("Too many arguments.  The only argument is the optional "
+                     "input file name");
+    }
+
+    ifP = pm_openr(inputFileName);
+
+    pbm_readpbminit(ifP, &cols, &rows, &format);
+
+    if (rows > INT16MAX || cols > INT16MAX)
+        pm_error("Input image is too large.");
+
+    bitrow = pbm_allocrow_packed(cols + 8);
     
-    /* Compute padding to round cols up to the nearest multiple of 16. */
-    padright = ( ( cols + 15 ) / 16 ) * 16 - cols;
+    putinit(cols, rows);
+
+    bitrow[pbm_packed_bytes(cols + 8) - 1] = 0x00;
+    for (row = 0; row < rows; ++row) {
+        uint16_t *   const itemrow = (uint16_t *) bitrow;
+        unsigned int const itemCt   = (cols + 15) / 16;
 
-    putinit( cols, rows );
-    for ( row = 0; row < rows; ++row )
-	{
-	pbm_readpbmrow( ifp, bitrow, cols, format );
-        for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
-	    putbit( *bP );
-	for ( col = 0; col < padright; ++col )
-	    putbit( 0 );
-        }
+        unsigned int i;
 
-    if ( ifp != stdin )
-	fclose( ifp );
+        pbm_readpbmrow_packed(ifP, bitrow, cols, format);
+        pbm_cleanrowend_packed(bitrow, cols);
 
-    putrest( );
+        for (i = 0; i < pbm_packed_bytes(cols); ++i)
+            bitrow[i] = bitreverse[bitrow[i]];
 
-    exit( 0 );
+        for (i = 0; i < itemCt; ++i)
+            pm_writebigshort(stdout, itemrow[i]);
     }
 
-static long item;
-static int bitsperitem, bitshift;
+    pbm_freerow_packed(bitrow);
 
-static void
-putinit( cols, rows )
-    int cols, rows;
-    {
-    pm_writebigshort( stdout, YBM_MAGIC );
-    pm_writebigshort( stdout, cols );
-    pm_writebigshort( stdout, rows );
-    item = 0;
-    bitsperitem = 0;
-    bitshift = 0;
-    }
+    if (ifP != stdin)
+        fclose(ifP);
 
-static void
-putbit( bit b )
-    {
-    if ( bitsperitem == 16 )
-	putitem( );
-    ++bitsperitem;
-    if ( b == PBM_BLACK )
-	item += 1 << bitshift;
-    ++bitshift;
-    }
+    return 0;
+}
 
-static void
-putrest( )
-    {
-    if ( bitsperitem > 0 )
-	putitem( );
-    }
 
-static void
-putitem( )
-    {
-    pm_writebigshort( stdout, item );
-    item = 0;
-    bitsperitem = 0;
-    bitshift = 0;
-    }
diff --git a/converter/pbm/pbmtozinc.c b/converter/pbm/pbmtozinc.c
index 2df39f0d..a89b8c9f 100644
--- a/converter/pbm/pbmtozinc.c
+++ b/converter/pbm/pbmtozinc.c
@@ -1,4 +1,4 @@
-/* pbmtozinc.c - read a portable bitmap and produce an bitmap file
+/* pbmtozinc.c - read a PBM image and produce a bitmap file
 **               in the format used by the Zinc Interface Library (v1.0)
 **               November 1990.
 **
@@ -21,108 +21,164 @@
 #include <stdio.h>
 #include <string.h>
 
+#include "mallocvar.h"
 #include "nstring.h"
 #include "pbm.h"
 
-int
-main(int argc, char * argv[]) {
-
-    FILE* ifp;
-    bit* bitrow;
-    register bit* bP;
-    int rows, cols, format, padright, row;
-    register int col;
-    char name[100];
-    char* cp;
-    int itemsperline;
-    register int bitsperitem;
-    register int item;
-    int firstitem;
-    const char * const hexchar = "084c2a6e195d3b7f";
-
-    pbm_init( &argc, argv );
-
-    if ( argc > 2 )
-        pm_usage( "[pbmfile]" );
-
-    if ( argc == 2 )
-	{
-        ifp = pm_openr( argv[1] );
-        strcpy( name, argv[1] );
-        if ( streq( name, "-" ) )
-            strcpy( name, "noname" );
-
-        if ( ( cp = strchr( name, '.' ) ) != 0 )
+static void
+parseCommandLine(int           const argc,
+                 const char ** const argv,
+                 const char ** const inputFileNameP) {
+
+    if (argc-1 > 0) {
+        *inputFileNameP = argv[1];
+
+        if (argc-1 > 1)
+            pm_error("To many arguments: %u.  "
+                     "The only possible argument is the "
+                     "name of the input file", argc-1);
+    } else
+        *inputFileNameP = "-";
+}
+
+
+
+static const char *
+imageName(const char * const inputFileName) {
+/*----------------------------------------------------------------------------
+   The image name to put in the Zinc file, based on the input file name
+   'inputFileName' ("-" to indicate Standard Input).
+
+   Result is newly malloc'ed space that Caller must free.
+-----------------------------------------------------------------------------*/
+    const char * retval;
+
+    if (streq(inputFileName, "-"))
+        pm_asprintf(&retval, "noname");
+    else {
+        char * nameBuf;
+        char * cp;
+
+        MALLOCARRAY_NOFAIL(nameBuf, strlen(inputFileName) + 1);
+
+        strcpy(nameBuf, inputFileName);
+
+        cp = strchr(nameBuf, '.' );
+        if (cp)
             *cp = '\0';
-	}
-    else
-	{
-        ifp = stdin;
-        strcpy( name, "noname" );
-	}
-
-    pbm_readpbminit( ifp, &cols, &rows, &format );
-    bitrow = pbm_allocrow( cols );
-
-    /* Compute padding to round cols up to the nearest multiple of 16. */
-    padright = ( ( cols + 15 ) / 16 ) * 16 - cols;
-
-    printf( "USHORT %s[] = {\n",name);
-    printf( "  %d\n", cols );
-    printf( "  %d\n", rows );
-
-    itemsperline = 0;
-    bitsperitem = 0;
-    item = 0;
-    firstitem = 1;
-
-#define PUTITEM \
-    { \
-    if ( firstitem ) \
-	firstitem = 0; \
-    else \
-	putchar( ',' ); \
-    if ( itemsperline == 11 ) \
-	{ \
-	putchar( '\n' ); \
-	itemsperline = 0; \
-	} \
-    if ( itemsperline == 0 ) \
-	putchar( ' ' ); \
-    ++itemsperline; \
-    putchar('0'); \
-    putchar('x'); \
-    putchar(hexchar[item & 15]); \
-    putchar(hexchar[(item >> 4) & 15]); \
-    putchar(hexchar[(item >> 8) & 15]); \
-    putchar(hexchar[item >> 12]); \
-    bitsperitem = 0; \
-    item = 0; \
+
+        retval = nameBuf;
     }
+    return retval;
+}
 
-#define PUTBIT(b) \
-    { \
-    if ( bitsperitem == 16 ) \
-	PUTITEM; \
-    if ( (b) == PBM_BLACK ) \
-	item += 1 << bitsperitem; \
-    ++bitsperitem; \
+
+
+typedef struct {
+    unsigned int itemsperline;
+    uint16_t     item;
+    unsigned int firstitem;
+} Packer;
+
+
+
+static void
+packer_init(Packer * const packerP) {
+
+    packerP->itemsperline = 0;
+    packerP->firstitem = 1;
+}
+
+
+
+static void
+packer_putitem(Packer *      const packerP,
+               unsigned char const hi,
+               unsigned char const lo) {
+
+    if (packerP->firstitem)
+        packerP->firstitem = 0;
+    else
+        putchar(',');
+
+    if (packerP->itemsperline == 11) {
+        putchar('\n');
+        packerP->itemsperline = 0;
     }
+    if (packerP->itemsperline == 0)
+        putchar(' ');
+
+    ++packerP->itemsperline;
 
-    for ( row = 0; row < rows; ++row )
-	{
-        pbm_readpbmrow( ifp, bitrow, cols, format );
-        for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
-            PUTBIT( *bP );
-        for ( col = 0; col < padright; ++col )
-            PUTBIT( 0 );
+    printf ("0x%02x%02x", hi, lo);
+
+}
+
+
+
+static void
+writeRaster(FILE *       const ifP,
+            unsigned int const rows,
+            unsigned int const cols,
+            int          const format) {
+
+    unsigned char * const bitrow = pbm_allocrow_packed(cols + 8);
+
+    Packer packer;
+    unsigned int row;
+
+    packer_init(&packer);
+
+    bitrow[pbm_packed_bytes(cols+8) -1 ] = 0x00;
+
+    for (row = 0; row < rows; ++row) {
+        unsigned int const itemCt = (cols + 15 ) / 16;
+
+        unsigned int i;
+
+        pbm_readpbmrow_packed(ifP, bitrow, cols, format);
+
+        pbm_cleanrowend_packed(bitrow, cols);
+
+        for (i = 0; i < itemCt; ++i) {
+            packer_putitem(&packer, bitrow[2*i+0], bitrow[2*i+1]);
+        }
     }
+    pbm_freerow_packed(bitrow);
+}
+
+
+
+int
+main(int argc, const char * argv[]) {
+
+    const char * inputFileName;
+    FILE * ifP;
+    int rows, cols;
+    int format;
+    const char * name;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &inputFileName);
+
+    ifP = pm_openr(inputFileName);
+
+    name = imageName(inputFileName);
+
+    pbm_readpbminit(ifP, &cols, &rows, &format);
+
+    printf("USHORT %s[] = {\n", name);
+    printf("  %d\n", cols);
+    printf("  %d\n", rows);
+
+    writeRaster(ifP, rows, cols, format);
+
+    printf("};\n");
+
+    pm_close(ifP);
 
-    pm_close( ifp );
-    
-    if ( bitsperitem > 0 )
-        PUTITEM;
-    printf( "};\n" );
+    pm_strfree(name);
 
     return 0;
 }
diff --git a/converter/pbm/pi3topbm.c b/converter/pbm/pi3topbm.c
index 8b3b21e3..17b07d6f 100644
--- a/converter/pbm/pi3topbm.c
+++ b/converter/pbm/pi3topbm.c
@@ -22,91 +22,147 @@
  */
 
 #include <stdio.h>
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "shhopt.h"
 #include "pbm.h"
 
+
+
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char * inputFileName;  /* Filename of input file */
+    unsigned int debug;
+};
+
+
+
+static void 
+parseCommandLine(int argc, 
+                 const char ** argv, 
+                 struct CmdlineInfo * const cmdlineP) {
+/* --------------------------------------------------------------------------
+   Parse program command line described in Unix standard form by argc
+   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.
+
+   Note that the strings we return are stored in the storage that
+   was passed to us as the argv array.  We also trash *argv.
+--------------------------------------------------------------------------*/
+    optEntry * option_def;
+    optStruct3 opt;
+        /* Instructions to pm_optParseOptions3 on how to parse our options. */
+    unsigned int option_def_index;
+  
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "debug",    OPT_FLAG,    NULL,       &cmdlineP->debug,       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->inputFileName = "-";
+    else {
+        cmdlineP->inputFileName = argv[1];
+
+        if (argc-1 > 1)
+            pm_error("Program takes zero or one argument (filename).  You "
+                     "specified %u", argc-1);
+    }
+}
+
+
+
+static void
+readAndValidateHeader(FILE * const ifP,
+                      bool   const debug,
+                      bool * const reverseP) {
+
+    short item;
+
+    pm_readbigshort(ifP, &item);
+
+    if (debug)
+        pm_message("resolution is %d", item);
+
+    /* only handles hi-rez 640x400 */
+    if (item != 2)
+        pm_error("bad resolution %d", item);
+
+    pm_readbigshort(ifP, &item);
+
+    *reverseP = (item == 0);
+
+    {
+        unsigned int i;
+
+        for (i = 1; i < 16; ++i)
+            pm_readbigshort (ifP, &item);
+    }
+}
+
+
+
 int
-main(argc, argv)
-	int             argc;
-	char           *argv[];
-{
-	int             debug = 0;
-	FILE           *f;
-	int             x;
-	int             i, k;
-	int             c;
-	int		rows, cols;
-	bit		*bitrow;
-	short res;
-	int black, white;
-	const char * const usage = "[-debug] [pi3file]";
-	int argn = 1;
-
-	pbm_init( &argc, argv );
-
-	while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0')
-	  {
-	    if (pm_keymatch(argv[1], "-debug", 2))
-	      debug = 1;
-	    else
-	      pm_usage (usage);
-	    ++argn;
-	  }
-
-	if (argn == argc)
-	    f = stdin;
-	else
-	  {
-	    f = pm_openr (argv[argn]);
-	    ++argn;
-	  }
-
-	if (argn != argc)
-	  pm_usage (usage);
-
-	if (pm_readbigshort (f, &res) == -1)
-		pm_error ("EOF / read error");
-
-	if (debug)
-		pm_message ("resolution is %d", res);
-
-	/* only handles hi-rez 640x400 */
-	if (res != 2)
-		pm_error( "bad resolution" );
-
-	pm_readbigshort (f, &res);
-	if (res == 0)
-	  {
-	    black = PBM_WHITE;
-	    white = PBM_BLACK;
-	  }
-	else
-	  {
-	    black = PBM_BLACK;
-	    white = PBM_WHITE;
-	  }
-
-	for (i = 1; i < 16; i++)
-	  if (pm_readbigshort (f, &res) == -1)
-	    pm_error ("EOF / read error");
-
-	cols = 640;
-	rows = 400;
-	pbm_writepbminit( stdout, cols, rows, 0 );
-	bitrow = pbm_allocrow( cols );
-
-	for (i = 0; i < rows; ++i) {
-		x = 0;
-		while (x < cols) {
-			if ((c = getc(f)) == EOF)
-				pm_error( "end of file reached" );
-			for (k = 0x80; k; k >>= 1) {
-				bitrow[x] = (k & c) ? black : white;
-				++x;
-			}
-		}
-		pbm_writepbmrow( stdout, bitrow, cols, 0 );
-	}
-	pm_close( f );
-	pm_close( stdout );
-	exit(0);
+main(int argc, const char ** argv) {
+
+    unsigned int const rows = 400;
+    unsigned int const cols = 640;
+
+    struct CmdlineInfo cmdline;
+    FILE * ifP;
+    unsigned int row;
+    bit * bitrow;
+    bool reverse;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    readAndValidateHeader(ifP, cmdline.debug, &reverse);
+
+    pbm_writepbminit(stdout, cols, rows, 0);
+
+    bitrow = pbm_allocrow_packed(cols);
+
+    for (row = 0; row < rows; ++row) {
+        unsigned int const colChars = cols / 8;
+
+        unsigned int bytesReadCt;
+
+        bytesReadCt = fread(bitrow, cols / 8, 1, ifP);
+        if (bytesReadCt != 1) {
+            if (feof(ifP))
+                pm_error( "EOF reached while reading image data" );
+            else
+                pm_error("read error while reading image data");
+        }
+
+        if (reverse) {
+            /* flip all pixels */
+            unsigned int colChar;
+            for (colChar = 0; colChar < colChars; ++colChar)
+                bitrow[colChar] = ~bitrow[colChar];
+        }
+        pbm_writepbmrow_packed(stdout, bitrow, cols, 0);
+    }
+
+    pbm_freerow_packed(bitrow);
+    pm_close(ifP);
+    pm_close(stdout);
+
+    return 0;
 }
diff --git a/converter/pbm/thinkjettopbm.l b/converter/pbm/thinkjettopbm.l
index 71501596..5de4f2bb 100644
--- a/converter/pbm/thinkjettopbm.l
+++ b/converter/pbm/thinkjettopbm.l
@@ -47,8 +47,15 @@
    undefined.  (Simply leaving them undefined typically works anyway, but it
    is a problem if you use compiler options that say to fail when someone
    uses a macro he failed to define).
+
+   We'd like to define YY_NO_UNPUT so as not to generate the unput function,
+   which we don't use, and avoid a compiler warning about defining and not
+   using it.  Alas, Flex 2.5.35 ignores YY_NO_UNPUT and generates the unput
+   function anyway.  So we have to have a bogus reference to silence the
+   unused function compiler warning.  And that means we have to generate
+   the function always.  Flex 2.5.4 does respect YY_NO_UNPUT.
 */
-#define YY_NO_UNPUT
+#define YY_NO_INPUT 1
 #define YY_STACK_USED 0
 #define YY_ALWAYS_INTERACTIVE 0
 #define YY_NEVER_INTERACTIVE 0
@@ -151,7 +158,7 @@ parseCommandLine(int argc, char ** const argv,
    was passed to us as the argv array.
 -----------------------------------------------------------------------------*/
     optEntry *option_def = malloc(100*sizeof(optEntry));
-        /* Instructions to OptParseOptions3 on how to parse our options.
+        /* Instructions to pm_OptParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
 
@@ -164,7 +171,7 @@ parseCommandLine(int argc, char ** const argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
 
@@ -200,6 +207,8 @@ main (int argc, char **argv)
     }
     debugFlag = cmdline.debug;
     yylex ();
+    if (0)
+        yyunput(0, NULL);  /* defeat compiler warning about unused fn */
     return 0;
 }
 
diff --git a/converter/pbm/xbmtopbm.c b/converter/pbm/xbmtopbm.c
index 9505ba67..bbf4e395 100644
--- a/converter/pbm/xbmtopbm.c
+++ b/converter/pbm/xbmtopbm.c
@@ -170,7 +170,7 @@ getXbmHeader(FILE *         const ifP,
             if (strlen(line) == MAX_LINE - 1)
                 pm_error("A line in the input file is %u characters long.  "
                          "%u is the maximum we can handle",
-                         strlen(line), MAX_LINE-1);
+                         (unsigned)strlen(line), MAX_LINE-1);
 
             parseWidthHeightLine(line, &gotWidth, widthP, &gotHeight, heightP);
 
@@ -362,12 +362,8 @@ main(int    argc,
         
         for (i = 0; i < bytesPerRow; ++i)
             bitrow[i] = bitreverse[*p++];
-            
-        if (cols % 8 > 0) {
-            bitrow[bytesPerRow-1] >>= 8 - cols % 8;
-            bitrow[bytesPerRow-1] <<= 8 - cols % 8;
-        }
-            
+
+        pbm_cleanrowend_packed(bitrow, cols);
         pbm_writepbmrow_packed(stdout, bitrow, cols, 0);
     }
 
diff --git a/converter/pbm/ybmtopbm.c b/converter/pbm/ybmtopbm.c
index 739e168a..2a429086 100644
--- a/converter/pbm/ybmtopbm.c
+++ b/converter/pbm/ybmtopbm.c
@@ -10,104 +10,101 @@
 ** implied warranty.
 */
 
-#include <stdio.h>
+#include "pm.h"
 #include "pbm.h"
+#include "bitreverse.h"
 
-static void getinit ARGS(( FILE* file, short* colsP, short* rowsP, short* depthP, short* padrightP ));
-static bit getbit ARGS(( FILE* file ));
+static short const ybmMagic = ( ( '!' << 8 ) | '!' );
 
-#define YBM_MAGIC  ( ( '!' << 8 ) | '!' )
 
-int
-main( argc, argv )
-    int argc;
-    char* argv[];
-    {
-    FILE* ifp;
-    bit* bitrow;
-    register bit* bP;
-    short rows, cols, padright, row, col;
-    short depth;
 
-    pbm_init( &argc, argv );
+static void
+getinit(FILE *  const ifP,
+        short * const colsP,
+        short * const rowsP,
+        short * const depthP) {
 
-    if ( argc > 2 )
-	pm_usage( "[ybmfile]" );
+    short magic;
+    int rc;
 
-    if ( argc == 2 )
-	ifp = pm_openr( argv[1] );
-    else
-	ifp = stdin;
+    rc = pm_readbigshort(ifP, &magic);
+    if (rc == -1)
+        pm_error("EOF / read error");
 
-    getinit( ifp, &cols, &rows, &depth, &padright );
-    if ( depth != 1 )
-	pm_error(
-	    "YBM file has depth of %d, must be 1",
-	    (int) depth );
+    if (magic != ybmMagic)
+        pm_error("bad magic number in YBM file");
 
-    pbm_writepbminit( stdout, cols, rows, 0 );
-    bitrow = pbm_allocrow( cols );
+    rc = pm_readbigshort(ifP, colsP);
+    if (rc == -1 )
+        pm_error("EOF / read error");
 
-    for ( row = 0; row < rows; ++row )
-	{
-	/* Get data. */
-        for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
-	    *bP = getbit( ifp );
-	/* Discard line padding */
-        for ( col = 0; col < padright; ++col )
-	    (void) getbit( ifp );
-	pbm_writepbmrow( stdout, bitrow, cols, 0 );
-	}
+    rc = pm_readbigshort(ifP, rowsP);
+    if (rc == -1)
+        pm_error("EOF / read error");
 
-    pm_close( ifp );
-    pm_close( stdout );
+    *depthP = 1;
+}
 
-    exit( 0 );
-    }
 
-static int item;
-static int bitsperitem, bitshift;
 
-static void
-getinit( file, colsP, rowsP, depthP, padrightP )
-    FILE* file;
-    short* colsP;
-    short* rowsP;
-    short* depthP;
-    short* padrightP;
-    {
-    short magic;
 
-    if ( pm_readbigshort( file, &magic ) == -1 )
-	pm_error( "EOF / read error" );
-    if ( magic != YBM_MAGIC )
-	pm_error( "bad magic number in YBM file" );
-    if ( pm_readbigshort( file, colsP ) == -1 )
-	pm_error( "EOF / read error" );
-      if ( pm_readbigshort( file, rowsP ) == -1 )
-	pm_error( "EOF / read error" );
 
-    *depthP = 1;
-    *padrightP = ( ( *colsP + 15 ) / 16 ) * 16 - *colsP;
-    bitsperitem = 0;
+
+int
+main(int argc, const char * argv[]) {
+
+    FILE * ifP;
+    bit * bitrow;
+    short rows, cols;
+    unsigned int row;
+    short depth;
+    const char * inputFile;
+
+    pm_proginit(&argc, argv);
+
+    if (argc-1 < 1)
+        inputFile = "-";
+    else {
+        inputFile = argv[1];
+
+        if (argc-1 > 1)
+            pm_error("Too many arguments.  The only argument is the optional "
+                     "input file name");
     }
 
-static bit
-getbit( file )
-    FILE* file;
-    {
-    bit b;
-
-    if ( bitsperitem == 0 )
-	{
-	item = getc(file) | getc(file)<<8;
-	if ( item == EOF )
-	    pm_error( "EOF / read error" );
-	bitsperitem = 16;
-	bitshift = 0;
-	}
-    b = ( ( item >> bitshift) & 1 ) ? PBM_BLACK : PBM_WHITE;
-    --bitsperitem;
-    ++bitshift;
-    return b;
+    ifP = pm_openr(inputFile);
+
+    getinit(ifP, &cols, &rows, &depth);
+    if (depth != 1)
+        pm_error("YBM file has depth of %u, must be 1", (unsigned)depth);
+    
+    pbm_writepbminit(stdout, cols, rows, 0);
+
+    bitrow = pbm_allocrow_packed(cols + 8);
+
+    for (row = 0; row < rows; ++row) {
+        uint16_t *   const itemrow = (uint16_t *) bitrow;
+        unsigned int const itemCt  = (cols + 15) / 16;
+
+        unsigned int i;
+
+        /* Get raster. */
+        for (i = 0; i < itemCt; ++i) {
+            short int item;
+            pm_readbigshort(ifP, &item);
+            itemrow[i] = (uint16_t) item; 
+        }
+
+        for (i = 0; i < pbm_packed_bytes(cols); ++i)
+            bitrow[i] = bitreverse[bitrow[i]];
+
+        pbm_cleanrowend_packed(bitrow, cols);
+        pbm_writepbmrow_packed(stdout, bitrow, cols, 0);
     }
+
+    pbm_freerow_packed(bitrow);
+    pm_close(ifP);
+    pm_close(stdout);
+
+    return 0;
+}