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/Makefile19
-rw-r--r--converter/pbm/cmuwmtopbm.c7
-rw-r--r--converter/pbm/g3.h136
-rw-r--r--converter/pbm/g3prefab.c286
-rw-r--r--converter/pbm/g3prefab.h14
-rw-r--r--converter/pbm/g3topbm.c172
-rw-r--r--converter/pbm/g3ttable.c116
-rw-r--r--converter/pbm/g3ttable.h13
-rw-r--r--converter/pbm/pbmtoascii.c49
-rw-r--r--converter/pbm/pbmtoepson.c1
-rw-r--r--converter/pbm/pbmtog3.c729
-rw-r--r--converter/pbm/pbmtolj.c41
-rw-r--r--converter/pbm/pbmtoln03.c211
-rw-r--r--converter/pbm/pbmtomacp.c6
-rw-r--r--converter/pbm/pbmtomgr.c9
-rw-r--r--converter/pbm/pbmtonokia.c9
-rw-r--r--converter/pbm/pbmtopk.c1
-rw-r--r--converter/pbm/pbmtoppa/pbm.c273
-rw-r--r--converter/pbm/pbmtoppa/pbmtoppa.c1
-rw-r--r--converter/pbm/pbmtox10bm37
-rw-r--r--converter/pbm/pbmtoxbm.c1
21 files changed, 1396 insertions, 735 deletions
diff --git a/converter/pbm/Makefile b/converter/pbm/Makefile
index 602cb156..352b73de 100644
--- a/converter/pbm/Makefile
+++ b/converter/pbm/Makefile
@@ -31,11 +31,14 @@ endif
 MATHBINARIES =	pbmtopk
 BINARIES =	$(PORTBINARIES) $(MATHBINARIES)
 SCRIPTS =       pbmtox10bm
+EXTRA_OBJECTS = g3ttable.o g3prefab.o
 
-OBJECTS = $(BINARIES:%=%.o)
+OBJECTS = $(BINARIES:%=%.o) $(EXTRA_OBJECTS)
 
 MERGEBINARIES = $(BINARIES)
-MERGE_OBJECTS = $(MERGEBINARIES:%=%.o2)
+MERGE_OBJECTS = $(MERGEBINARIES:%=%.o2) $(EXTRA_OBJECTS)
+
+HAVE_MERGE_COMPAT=YES
 
 SUBDIRS=pbmtoppa
 
@@ -73,7 +76,7 @@ thinkjettopbm.c:%.c:%.c1 $(SRCDIR)/lib/util/lexheader
 	  grep -v "^[[:space:]]*int yywrap(void);" \
 	  >$@
 
-install.bin: install.bin.local
+install.bin install.merge: install.bin.local
 .PHONY: install.bin.local
 install.bin.local: $(PKGDIR)/bin
 # Remember that $(SYMLINK) might just be a copy command.
@@ -81,7 +84,17 @@ install.bin.local: $(PKGDIR)/bin
 	cd $(PKGDIR)/bin ; \
 	$(SYMLINK) pbmtosunicon$(EXE) pbmtoicon$(EXE)
 
+mergecomptrylist:
+	cat /dev/null >$@
+	echo "TRY(\"pbmtoicon\",   main_pbmtosunicon);"     >>$@
+
 thisdirclean: localclean
 .PHONY: localclean
 localclean:
 	-rm -f thinkjettopbm.c
+
+pbmtog3: g3ttable.o g3prefab.o
+pbmtog3: ADDL_OBJECTS = g3ttable.o g3prefab.o
+
+g3topbm: g3ttable.o
+g3topbm: ADDL_OBJECTS = g3ttable.o
diff --git a/converter/pbm/cmuwmtopbm.c b/converter/pbm/cmuwmtopbm.c
index ccf8cfc9..be8a7fc1 100644
--- a/converter/pbm/cmuwmtopbm.c
+++ b/converter/pbm/cmuwmtopbm.c
@@ -68,8 +68,8 @@ readCmuwmHeader(FILE *         const ifP,
 
 
 int
-main(int     argc,
-     char * argv[]) {
+main(int           argc,
+     const char ** argv) {
 
     FILE * ifP;
     unsigned char * bitrow;
@@ -78,7 +78,7 @@ main(int     argc,
 
     const char * inputFileName;
 
-    pbm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     if (argc-1 > 1)
         pm_error("Too many arguments (%u).  "
@@ -117,6 +117,7 @@ main(int     argc,
         pbm_writepbmrow_packed(stdout, bitrow, cols, 0);
     }
 
+    pbm_freerow_packed(bitrow);
     pm_close(ifP);
     pm_close(stdout);
 
diff --git a/converter/pbm/g3.h b/converter/pbm/g3.h
index e982f2da..3e216a78 100644
--- a/converter/pbm/g3.h
+++ b/converter/pbm/g3.h
@@ -21,126 +21,24 @@
    the subject of this header file.  It also specifies layers
    underneath the bit stream.
 
-   There is also the newer G4.  
+   There is also the newer G4.
 */
-
-typedef struct g3TableEntry {
-    short int code;
-    short int length;
-} g3TableEntry;
-
-static struct g3TableEntry ttable[] = {
-/*    TERMWHITE           TERMBLACK   */
-    { 0x35, 8 },    { 0x37, 10 },       /* white 0 , black 0 */
-    { 0x07, 6 },    { 0x02,  3 },
-    { 0x07, 4 },    { 0x03,  2 },
-    { 0x08, 4 },    { 0x02,  2 },
-    { 0x0b, 4 },    { 0x03,  3 },
-    { 0x0c, 4 },    { 0x03,  4 },
-    { 0x0e, 4 },    { 0x02,  4 },
-    { 0x0f, 4 },    { 0x03,  5 },
-    { 0x13, 5 },    { 0x05,  6 },
-    { 0x14, 5 },    { 0x04,  6 },
-    { 0x07, 5 },    { 0x04,  7 },
-    { 0x08, 5 },    { 0x05,  7 },
-    { 0x08, 6 },    { 0x07,  7 },
-    { 0x03, 6 },    { 0x04,  8 },
-    { 0x34, 6 },    { 0x07,  8 },
-    { 0x35, 6 },    { 0x18,  9 },
-    { 0x2a, 6 },    { 0x17, 10 },
-    { 0x2b, 6 },    { 0x18, 10 },
-    { 0x27, 7 },    { 0x08, 10 },
-    { 0x0c, 7 },    { 0x67, 11 },
-    { 0x08, 7 },    { 0x68, 11 },
-    { 0x17, 7 },    { 0x6c, 11 },
-    { 0x03, 7 },    { 0x37, 11 },
-    { 0x04, 7 },    { 0x28, 11 },
-    { 0x28, 7 },    { 0x17, 11 },
-    { 0x2b, 7 },    { 0x18, 11 },
-    { 0x13, 7 },    { 0xca, 12 },
-    { 0x24, 7 },    { 0xcb, 12 },
-    { 0x18, 7 },    { 0xcc, 12 },
-    { 0x02, 8 },    { 0xcd, 12 },
-    { 0x03, 8 },    { 0x68, 12 },
-    { 0x1a, 8 },    { 0x69, 12 },
-    { 0x1b, 8 },    { 0x6a, 12 },
-    { 0x12, 8 },    { 0x6b, 12 },
-    { 0x13, 8 },    { 0xd2, 12 },
-    { 0x14, 8 },    { 0xd3, 12 },
-    { 0x15, 8 },    { 0xd4, 12 },
-    { 0x16, 8 },    { 0xd5, 12 },
-    { 0x17, 8 },    { 0xd6, 12 },
-    { 0x28, 8 },    { 0xd7, 12 },
-    { 0x29, 8 },    { 0x6c, 12 },
-    { 0x2a, 8 },    { 0x6d, 12 },
-    { 0x2b, 8 },    { 0xda, 12 },
-    { 0x2c, 8 },    { 0xdb, 12 },
-    { 0x2d, 8 },    { 0x54, 12 },
-    { 0x04, 8 },    { 0x55, 12 },
-    { 0x05, 8 },    { 0x56, 12 },
-    { 0x0a, 8 },    { 0x57, 12 },
-    { 0x0b, 8 },    { 0x64, 12 },
-    { 0x52, 8 },    { 0x65, 12 },
-    { 0x53, 8 },    { 0x52, 12 },
-    { 0x54, 8 },    { 0x53, 12 },
-    { 0x55, 8 },    { 0x24, 12 },
-    { 0x24, 8 },    { 0x37, 12 },
-    { 0x25, 8 },    { 0x38, 12 },
-    { 0x58, 8 },    { 0x27, 12 },
-    { 0x59, 8 },    { 0x28, 12 },
-    { 0x5a, 8 },    { 0x58, 12 },
-    { 0x5b, 8 },    { 0x59, 12 },
-    { 0x4a, 8 },    { 0x2b, 12 },
-    { 0x4b, 8 },    { 0x2c, 12 },
-    { 0x32, 8 },    { 0x5a, 12 },
-    { 0x33, 8 },    { 0x66, 12 },
-    { 0x34, 8 },    { 0x67, 12 },       /* white 63 , black 63 */
-
-/* mtable */    
-/*    MKUPWHITE           MKUPBLACK   */
-    { 0x00, 0 },    { 0x00,  0 },   /* dummy to simplify pointer math */
-    { 0x1b, 5 },    { 0x0f, 10 },   /* white 64 , black 64 */
-    { 0x12, 5 },    { 0xc8, 12 },
-    { 0x17, 6 },    { 0xc9, 12 },
-    { 0x37, 7 },    { 0x5b, 12 },
-    { 0x36, 8 },    { 0x33, 12 },
-    { 0x37, 8 },    { 0x34, 12 },
-    { 0x64, 8 },    { 0x35, 12 },
-    { 0x65, 8 },    { 0x6c, 13 },
-    { 0x68, 8 },    { 0x6d, 13 },
-    { 0x67, 8 },    { 0x4a, 13 },
-    { 0xcc, 9 },    { 0x4b, 13 },
-    { 0xcd, 9 },    { 0x4c, 13 },
-    { 0xd2, 9 },    { 0x4d, 13 },
-    { 0xd3, 9 },    { 0x72, 13 },
-    { 0xd4, 9 },    { 0x73, 13 },
-    { 0xd5, 9 },    { 0x74, 13 },
-    { 0xd6, 9 },    { 0x75, 13 },
-    { 0xd7, 9 },    { 0x76, 13 },
-    { 0xd8, 9 },    { 0x77, 13 },
-    { 0xd9, 9 },    { 0x52, 13 },
-    { 0xda, 9 },    { 0x53, 13 },
-    { 0xdb, 9 },    { 0x54, 13 },
-    { 0x98, 9 },    { 0x55, 13 },
-    { 0x99, 9 },    { 0x5a, 13 },
-    { 0x9a, 9 },    { 0x5b, 13 },
-    { 0x18, 6 },    { 0x64, 13 },
-    { 0x9b, 9 },    { 0x65, 13 },
-    { 0x08, 11 },   { 0x08, 11 },        /* extable len = 1792 */
-    { 0x0c, 11 },   { 0x0c, 11 },
-    { 0x0d, 11 },   { 0x0d, 11 },
-    { 0x12, 12 },   { 0x12, 12 },
-    { 0x13, 12 },   { 0x13, 12 },
-    { 0x14, 12 },   { 0x14, 12 },
-    { 0x15, 12 },   { 0x15, 12 },
-    { 0x16, 12 },   { 0x16, 12 },
-    { 0x17, 12 },   { 0x17, 12 },
-    { 0x1c, 12 },   { 0x1c, 12 },
-    { 0x1d, 12 },   { 0x1d, 12 },
-    { 0x1e, 12 },   { 0x1e, 12 },
-    { 0x1f, 12 },   { 0x1f, 12 },
+#include "pm_config.h"  /* uint32_t */
+
+struct BitString {
+    /* A string of bits, up to as many fit in 32 bits. */
+    uint32_t     intBuffer;
+        /* The bits are in the 'bitCount' least significant bit positions
+           of this number.  The rest of the bits of this number are always
+           zero.
+        */
+    unsigned int bitCount;
+        /* The length of the bit string */
+
+    /* Example:  The bit string 010100 would be represented by
+       bitCount = 6, intBuffer = 20
+       (N.B. 20 = 00000000 00000000 00000000 00010100 in binary)
+    */
 };
 
-#define mtable ((ttable)+64*2)
-
 #endif
diff --git a/converter/pbm/g3prefab.c b/converter/pbm/g3prefab.c
new file mode 100644
index 00000000..4c45b6a2
--- /dev/null
+++ b/converter/pbm/g3prefab.c
@@ -0,0 +1,286 @@
+/* Prefabricated G3 Huffman code
+
+   Most g3 fax encoders scan the input data bitwise, count run-lengths
+   and emit the corresponding Huffman codes.  This is a different approach.
+
+   8 bits of raw input data is read and Huffman codes are emitted directly,
+   reading from a look-up table.
+
+   For example if the input is WWBBWWWB then the Huffman codes for
+   White(2), Black(2), White(3), Black(1) are combined and emitted.
+
+   In reality things are a somewhat more complicated for the runs on
+   both ends of the input byte are likely to be parts of longer runs
+   encompassing multiple bytes.
+
+   This method has one serious drawback: It does not work well
+   with adaptive Huffman coding schemes.  This is, of course, never
+   a problem with CCITT G3 fax images for which the Huffman code table
+   is fixed by standard.  For adaptive Huffman coding schemes, one
+   should consider preparing a code table like the one below which
+   encodes mixed black-white sequences up to a certain length.
+
+*/
+#include "g3.h"
+
+#include "g3prefab.h"
+
+ struct PrefabCode const g3prefab_code[256] =
+{
+{ 0, 8, {   0x0000,   0}},   /* 000 */
+{ 7, 1, {   0x0000,   0}},   /* 001 */
+{ 6, 1, {   0x0002,   3}},   /* 002 */
+{ 6, 2, {   0x0000,   0}},   /* 003 */
+{ 5, 2, {   0x0002,   3}},   /* 004 */
+{ 5, 1, {   0x0087,   9}},   /* 005 */
+{ 5, 1, {   0x0003,   2}},   /* 006 */
+{ 5, 3, {   0x0000,   0}},   /* 007 */
+{ 4, 3, {   0x0002,   3}},   /* 008 */
+{ 4, 1, {   0x0027,   7}},   /* 009 */
+{ 4, 1, {   0x043a,  12}},   /* 010 */
+{ 4, 2, {   0x0087,   9}},   /* 011 */
+{ 4, 2, {   0x0003,   2}},   /* 012 */
+{ 4, 1, {   0x00c7,   8}},   /* 013 */
+{ 4, 1, {   0x0002,   2}},   /* 014 */
+{ 4, 4, {   0x0000,   0}},   /* 015 */
+{ 3, 4, {   0x0002,   3}},   /* 016 */
+{ 3, 1, {   0x0028,   7}},   /* 017 */
+{ 3, 1, {   0x013a,  10}},   /* 018 */
+{ 3, 2, {   0x0027,   7}},   /* 019 */
+{ 3, 2, {   0x043a,  12}},   /* 020 */
+{ 3, 1, {  0x10e87,  18}},   /* 021 */
+{ 3, 1, {   0x021f,  11}},   /* 022 */
+{ 3, 3, {   0x0087,   9}},   /* 023 */
+{ 3, 3, {   0x0003,   2}},   /* 024 */
+{ 3, 1, {   0x0037,   6}},   /* 025 */
+{ 3, 1, {   0x063a,  11}},   /* 026 */
+{ 3, 2, {   0x00c7,   8}},   /* 027 */
+{ 3, 2, {   0x0002,   2}},   /* 028 */
+{ 3, 1, {   0x0087,   8}},   /* 029 */
+{ 3, 1, {   0x0003,   3}},   /* 030 */
+{ 3, 5, {   0x0000,   0}},   /* 031 */
+{ 2, 5, {   0x0002,   3}},   /* 032 */
+{ 2, 1, {   0x002b,   7}},   /* 033 */
+{ 2, 1, {   0x0142,  10}},   /* 034 */
+{ 2, 2, {   0x0028,   7}},   /* 035 */
+{ 2, 2, {   0x013a,  10}},   /* 036 */
+{ 2, 1, {   0x4e87,  16}},   /* 037 */
+{ 2, 1, {   0x009f,   9}},   /* 038 */
+{ 2, 3, {   0x0027,   7}},   /* 039 */
+{ 2, 3, {   0x043a,  12}},   /* 040 */
+{ 2, 1, {   0x43a7,  16}},   /* 041 */
+{ 2, 1, {  0x8743a,  21}},   /* 042 */
+{ 2, 2, {  0x10e87,  18}},   /* 043 */
+{ 2, 2, {   0x021f,  11}},   /* 044 */
+{ 2, 1, {   0x87c7,  17}},   /* 045 */
+{ 2, 1, {   0x021e,  11}},   /* 046 */
+{ 2, 4, {   0x0087,   9}},   /* 047 */
+{ 2, 4, {   0x0003,   2}},   /* 048 */
+{ 2, 1, {   0x0038,   6}},   /* 049 */
+{ 2, 1, {   0x01ba,   9}},   /* 050 */
+{ 2, 2, {   0x0037,   6}},   /* 051 */
+{ 2, 2, {   0x063a,  11}},   /* 052 */
+{ 2, 1, {  0x18e87,  17}},   /* 053 */
+{ 2, 1, {   0x031f,  10}},   /* 054 */
+{ 2, 3, {   0x00c7,   8}},   /* 055 */
+{ 2, 3, {   0x0002,   2}},   /* 056 */
+{ 2, 1, {   0x0027,   6}},   /* 057 */
+{ 2, 1, {   0x043a,  11}},   /* 058 */
+{ 2, 2, {   0x0087,   8}},   /* 059 */
+{ 2, 2, {   0x0003,   3}},   /* 060 */
+{ 2, 1, {   0x00c7,   9}},   /* 061 */
+{ 2, 1, {   0x0003,   4}},   /* 062 */
+{ 2, 6, {   0x0000,   0}},   /* 063 */
+{ 1, 6, {   0x0002,   3}},   /* 064 */
+{ 1, 1, {   0x002c,   7}},   /* 065 */
+{ 1, 1, {   0x015a,  10}},   /* 066 */
+{ 1, 2, {   0x002b,   7}},   /* 067 */
+{ 1, 2, {   0x0142,  10}},   /* 068 */
+{ 1, 1, {   0x5087,  16}},   /* 069 */
+{ 1, 1, {   0x00a3,   9}},   /* 070 */
+{ 1, 3, {   0x0028,   7}},   /* 071 */
+{ 1, 3, {   0x013a,  10}},   /* 072 */
+{ 1, 1, {   0x13a7,  14}},   /* 073 */
+{ 1, 1, {  0x2743a,  19}},   /* 074 */
+{ 1, 2, {   0x4e87,  16}},   /* 075 */
+{ 1, 2, {   0x009f,   9}},   /* 076 */
+{ 1, 1, {   0x27c7,  15}},   /* 077 */
+{ 1, 1, {   0x009e,   9}},   /* 078 */
+{ 1, 4, {   0x0027,   7}},   /* 079 */
+{ 1, 4, {   0x043a,  12}},   /* 080 */
+{ 1, 1, {   0x43a8,  16}},   /* 081 */
+{ 1, 1, {  0x21d3a,  19}},   /* 082 */
+{ 1, 2, {   0x43a7,  16}},   /* 083 */
+{ 1, 2, {  0x8743a,  21}},   /* 084 */
+{ 1, 1, {0x21d0e87,  27}},   /* 085 */
+{ 1, 1, {  0x43a1f,  20}},   /* 086 */
+{ 1, 3, {  0x10e87,  18}},   /* 087 */
+{ 1, 3, {   0x021f,  11}},   /* 088 */
+{ 1, 1, {   0x21f7,  15}},   /* 089 */
+{ 1, 1, {  0x43e3a,  20}},   /* 090 */
+{ 1, 2, {   0x87c7,  17}},   /* 091 */
+{ 1, 2, {   0x021e,  11}},   /* 092 */
+{ 1, 1, {   0x8787,  17}},   /* 093 */
+{ 1, 1, {   0x043b,  12}},   /* 094 */
+{ 1, 5, {   0x0087,   9}},   /* 095 */
+{ 1, 5, {   0x0003,   2}},   /* 096 */
+{ 1, 1, {   0x003b,   6}},   /* 097 */
+{ 1, 1, {   0x01c2,   9}},   /* 098 */
+{ 1, 2, {   0x0038,   6}},   /* 099 */
+{ 1, 2, {   0x01ba,   9}},   /* 100 */
+{ 1, 1, {   0x6e87,  15}},   /* 101 */
+{ 1, 1, {   0x00df,   8}},   /* 102 */
+{ 1, 3, {   0x0037,   6}},   /* 103 */
+{ 1, 3, {   0x063a,  11}},   /* 104 */
+{ 1, 1, {   0x63a7,  15}},   /* 105 */
+{ 1, 1, {  0xc743a,  20}},   /* 106 */
+{ 1, 2, {  0x18e87,  17}},   /* 107 */
+{ 1, 2, {   0x031f,  10}},   /* 108 */
+{ 1, 1, {   0xc7c7,  16}},   /* 109 */
+{ 1, 1, {   0x031e,  10}},   /* 110 */
+{ 1, 4, {   0x00c7,   8}},   /* 111 */
+{ 1, 4, {   0x0002,   2}},   /* 112 */
+{ 1, 1, {   0x0028,   6}},   /* 113 */
+{ 1, 1, {   0x013a,   9}},   /* 114 */
+{ 1, 2, {   0x0027,   6}},   /* 115 */
+{ 1, 2, {   0x043a,  11}},   /* 116 */
+{ 1, 1, {  0x10e87,  17}},   /* 117 */
+{ 1, 1, {   0x021f,  10}},   /* 118 */
+{ 1, 3, {   0x0087,   8}},   /* 119 */
+{ 1, 3, {   0x0003,   3}},   /* 120 */
+{ 1, 1, {   0x0037,   7}},   /* 121 */
+{ 1, 1, {   0x063a,  12}},   /* 122 */
+{ 1, 2, {   0x00c7,   9}},   /* 123 */
+{ 1, 2, {   0x0003,   4}},   /* 124 */
+{ 1, 1, {   0x00c7,  10}},   /* 125 */
+{ 1, 1, {   0x0002,   4}},   /* 126 */
+{ 1, 7, {   0x0000,   0}},   /* 127 */
+{ 1, 7, {   0x0000,   0}},   /* 128 */
+{ 1, 1, {   0x000e,   4}},   /* 129 */
+{ 1, 1, {   0x0062,   7}},   /* 130 */
+{ 1, 2, {   0x000c,   4}},   /* 131 */
+{ 1, 2, {   0x005a,   7}},   /* 132 */
+{ 1, 1, {   0x1687,  13}},   /* 133 */
+{ 1, 1, {   0x002f,   6}},   /* 134 */
+{ 1, 3, {   0x000b,   4}},   /* 135 */
+{ 1, 3, {   0x0042,   7}},   /* 136 */
+{ 1, 1, {   0x0427,  11}},   /* 137 */
+{ 1, 1, {   0x843a,  16}},   /* 138 */
+{ 1, 2, {   0x1087,  13}},   /* 139 */
+{ 1, 2, {   0x0023,   6}},   /* 140 */
+{ 1, 1, {   0x08c7,  12}},   /* 141 */
+{ 1, 1, {   0x0022,   6}},   /* 142 */
+{ 1, 4, {   0x0008,   4}},   /* 143 */
+{ 1, 4, {   0x003a,   7}},   /* 144 */
+{ 1, 1, {   0x03a8,  11}},   /* 145 */
+{ 1, 1, {   0x1d3a,  14}},   /* 146 */
+{ 1, 2, {   0x03a7,  11}},   /* 147 */
+{ 1, 2, {   0x743a,  16}},   /* 148 */
+{ 1, 1, { 0x1d0e87,  22}},   /* 149 */
+{ 1, 1, {   0x3a1f,  15}},   /* 150 */
+{ 1, 3, {   0x0e87,  13}},   /* 151 */
+{ 1, 3, {   0x001f,   6}},   /* 152 */
+{ 1, 1, {   0x01f7,  10}},   /* 153 */
+{ 1, 1, {   0x3e3a,  15}},   /* 154 */
+{ 1, 2, {   0x07c7,  12}},   /* 155 */
+{ 1, 2, {   0x001e,   6}},   /* 156 */
+{ 1, 1, {   0x0787,  12}},   /* 157 */
+{ 1, 1, {   0x003b,   7}},   /* 158 */
+{ 1, 5, {   0x0007,   4}},   /* 159 */
+{ 1, 5, {   0x003a,   9}},   /* 160 */
+{ 1, 1, {   0x03ab,  13}},   /* 161 */
+{ 1, 1, {   0x1d42,  16}},   /* 162 */
+{ 1, 2, {   0x03a8,  13}},   /* 163 */
+{ 1, 2, {   0x1d3a,  16}},   /* 164 */
+{ 1, 1, {  0x74e87,  22}},   /* 165 */
+{ 1, 1, {   0x0e9f,  15}},   /* 166 */
+{ 1, 3, {   0x03a7,  13}},   /* 167 */
+{ 1, 3, {   0x743a,  18}},   /* 168 */
+{ 1, 1, {  0x743a7,  22}},   /* 169 */
+{ 1, 1, { 0xe8743a,  27}},   /* 170 */
+{ 1, 2, { 0x1d0e87,  24}},   /* 171 */
+{ 1, 2, {   0x3a1f,  17}},   /* 172 */
+{ 1, 1, {  0xe87c7,  23}},   /* 173 */
+{ 1, 1, {   0x3a1e,  17}},   /* 174 */
+{ 1, 4, {   0x0e87,  15}},   /* 175 */
+{ 1, 4, {   0x001f,   8}},   /* 176 */
+{ 1, 1, {   0x01f8,  12}},   /* 177 */
+{ 1, 1, {   0x0fba,  15}},   /* 178 */
+{ 1, 2, {   0x01f7,  12}},   /* 179 */
+{ 1, 2, {   0x3e3a,  17}},   /* 180 */
+{ 1, 1, {  0xf8e87,  23}},   /* 181 */
+{ 1, 1, {   0x1f1f,  16}},   /* 182 */
+{ 1, 3, {   0x07c7,  14}},   /* 183 */
+{ 1, 3, {   0x001e,   8}},   /* 184 */
+{ 1, 1, {   0x01e7,  12}},   /* 185 */
+{ 1, 1, {   0x3c3a,  17}},   /* 186 */
+{ 1, 2, {   0x0787,  14}},   /* 187 */
+{ 1, 2, {   0x003b,   9}},   /* 188 */
+{ 1, 1, {   0x0ec7,  15}},   /* 189 */
+{ 1, 1, {   0x0073,  10}},   /* 190 */
+{ 1, 6, {   0x0007,   6}},   /* 191 */
+{ 2, 6, {   0x0000,   0}},   /* 192 */
+{ 2, 1, {   0x000c,   4}},   /* 193 */
+{ 2, 1, {   0x005a,   7}},   /* 194 */
+{ 2, 2, {   0x000b,   4}},   /* 195 */
+{ 2, 2, {   0x0042,   7}},   /* 196 */
+{ 2, 1, {   0x1087,  13}},   /* 197 */
+{ 2, 1, {   0x0023,   6}},   /* 198 */
+{ 2, 3, {   0x0008,   4}},   /* 199 */
+{ 2, 3, {   0x003a,   7}},   /* 200 */
+{ 2, 1, {   0x03a7,  11}},   /* 201 */
+{ 2, 1, {   0x743a,  16}},   /* 202 */
+{ 2, 2, {   0x0e87,  13}},   /* 203 */
+{ 2, 2, {   0x001f,   6}},   /* 204 */
+{ 2, 1, {   0x07c7,  12}},   /* 205 */
+{ 2, 1, {   0x001e,   6}},   /* 206 */
+{ 2, 4, {   0x0007,   4}},   /* 207 */
+{ 2, 4, {   0x003a,   9}},   /* 208 */
+{ 2, 1, {   0x03a8,  13}},   /* 209 */
+{ 2, 1, {   0x1d3a,  16}},   /* 210 */
+{ 2, 2, {   0x03a7,  13}},   /* 211 */
+{ 2, 2, {   0x743a,  18}},   /* 212 */
+{ 2, 1, { 0x1d0e87,  24}},   /* 213 */
+{ 2, 1, {   0x3a1f,  17}},   /* 214 */
+{ 2, 3, {   0x0e87,  15}},   /* 215 */
+{ 2, 3, {   0x001f,   8}},   /* 216 */
+{ 2, 1, {   0x01f7,  12}},   /* 217 */
+{ 2, 1, {   0x3e3a,  17}},   /* 218 */
+{ 2, 2, {   0x07c7,  14}},   /* 219 */
+{ 2, 2, {   0x001e,   8}},   /* 220 */
+{ 2, 1, {   0x0787,  14}},   /* 221 */
+{ 2, 1, {   0x003b,   9}},   /* 222 */
+{ 2, 5, {   0x0007,   6}},   /* 223 */
+{ 3, 5, {   0x0000,   0}},   /* 224 */
+{ 3, 1, {   0x000b,   4}},   /* 225 */
+{ 3, 1, {   0x0042,   7}},   /* 226 */
+{ 3, 2, {   0x0008,   4}},   /* 227 */
+{ 3, 2, {   0x003a,   7}},   /* 228 */
+{ 3, 1, {   0x0e87,  13}},   /* 229 */
+{ 3, 1, {   0x001f,   6}},   /* 230 */
+{ 3, 3, {   0x0007,   4}},   /* 231 */
+{ 3, 3, {   0x003a,   9}},   /* 232 */
+{ 3, 1, {   0x03a7,  13}},   /* 233 */
+{ 3, 1, {   0x743a,  18}},   /* 234 */
+{ 3, 2, {   0x0e87,  15}},   /* 235 */
+{ 3, 2, {   0x001f,   8}},   /* 236 */
+{ 3, 1, {   0x07c7,  14}},   /* 237 */
+{ 3, 1, {   0x001e,   8}},   /* 238 */
+{ 3, 4, {   0x0007,   6}},   /* 239 */
+{ 4, 4, {   0x0000,   0}},   /* 240 */
+{ 4, 1, {   0x0008,   4}},   /* 241 */
+{ 4, 1, {   0x003a,   7}},   /* 242 */
+{ 4, 2, {   0x0007,   4}},   /* 243 */
+{ 4, 2, {   0x003a,   9}},   /* 244 */
+{ 4, 1, {   0x0e87,  15}},   /* 245 */
+{ 4, 1, {   0x001f,   8}},   /* 246 */
+{ 4, 3, {   0x0007,   6}},   /* 247 */
+{ 5, 3, {   0x0000,   0}},   /* 248 */
+{ 5, 1, {   0x0007,   4}},   /* 249 */
+{ 5, 1, {   0x003a,   9}},   /* 250 */
+{ 5, 2, {   0x0007,   6}},   /* 251 */
+{ 6, 2, {   0x0000,   0}},   /* 252 */
+{ 6, 1, {   0x0007,   6}},   /* 253 */
+{ 7, 1, {   0x0000,   0}},   /* 254 */
+{ 0, 8, {   0x0000,   0}},   /* 255 */
+  };
diff --git a/converter/pbm/g3prefab.h b/converter/pbm/g3prefab.h
new file mode 100644
index 00000000..4fa4751a
--- /dev/null
+++ b/converter/pbm/g3prefab.h
@@ -0,0 +1,14 @@
+#ifndef G3_PREFAB_H_INCLUDED
+#define G3_PREFAB_H_INCLUDED
+
+struct PrefabCode {
+    unsigned int leadBits;
+    unsigned int trailBits;
+    struct BitString activeBits;
+};
+
+
+extern struct PrefabCode const g3prefab_code[256];
+
+#endif
+
diff --git a/converter/pbm/g3topbm.c b/converter/pbm/g3topbm.c
index fcac1981..5d98fcb2 100644
--- a/converter/pbm/g3topbm.c
+++ b/converter/pbm/g3topbm.c
@@ -4,7 +4,7 @@
 
   This program reads a Group 3 FAX file and produces a PBM image.
 
-  Bryan Henderson wrote this on August 5, 2004 and contributed it to 
+  Bryan Henderson wrote this on August 5, 2004 and contributed it to
   the public domain.
 
   This program is designed to be a drop-in replacement for the program
@@ -18,6 +18,7 @@
   contributing their work to the public domain.
 ===========================================================================*/
 
+#define _DEFAULT_SOURCE /* New name for SVID & BSD source defines */
 #define _BSD_SOURCE   /* Make nstring.h define strcaseeq() */
 
 #include "pm_c_util.h"
@@ -26,6 +27,7 @@
 #include "nstring.h"
 #include "mallocvar.h"
 #include "g3.h"
+#include "g3ttable.h"
 #include "bitreverse.h"
 #include "bitarith.h"
 
@@ -43,11 +45,37 @@
 
 #define HASHSIZE 1021
 
-static g3TableEntry * whash[HASHSIZE];
-static g3TableEntry * bhash[HASHSIZE];
+#define MAXFILLBITS (5 * 9600)
 
+/*
+Fill bits are for flow control.  This was important when DRAM was
+expensive and fax machines came with small buffers.
 
-struct cmdlineInfo {
+If data arrives too quickly it may overflow the buffer of the
+receiving device.  On sending devices transmission time of compressed
+data representing a single row can be shorter than the time required
+to scan and encode.  The CCITT standard allows sending devices to
+insert fill bits to put communication on hold in these cases.
+
+By the CCITT standard, the maximum transmission time for one row is:
+
+100 - 400 pixels/inch 13 seconds
+(standard mode: 200 pixels/inch)
+600 pixels/inch 19 seconds
+1200 pixels/inch 37 seconds
+
+If one row is not received within the above limits, the receiving
+machine must disconnect the line.
+
+The receiver may be less patient.  It may opt to disconnect if one row
+is not received within 5 seconds.
+*/
+
+static G3TableEntry * whash[HASHSIZE];
+static G3TableEntry * bhash[HASHSIZE];
+
+
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -62,8 +90,8 @@ struct cmdlineInfo {
 
 
 static void
-parseCommandLine(int argc, char ** const argv,
-                 struct cmdlineInfo * const cmdlineP) {
+parseCommandLine(int argc, const char ** const argv,
+                 struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that the file spec array we return is stored in the storage that
    was passed to us as the argv array.
@@ -84,20 +112,20 @@ parseCommandLine(int argc, char ** const argv,
             0);
     OPTENT3(0, "kludge",           OPT_FLAG,  NULL, &cmdlineP->kludge,
             0);
-    OPTENT3(0, "stretch",          OPT_FLAG,  NULL, &cmdlineP->stretch, 
+    OPTENT3(0, "stretch",          OPT_FLAG,  NULL, &cmdlineP->stretch,
             0);
-    OPTENT3(0, "stop_error",       OPT_FLAG,  NULL, &cmdlineP->stop_error, 
+    OPTENT3(0, "stop_error",       OPT_FLAG,  NULL, &cmdlineP->stop_error,
             0);
     OPTENT3(0, "width",            OPT_UINT,  &cmdlineP->expectedLineSize,
             &widthSpec,                0);
     OPTENT3(0, "paper_size",       OPT_STRING, &paperSize,
             &paper_sizeSpec,           0);
-    
+
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We may have parms that are negative numbers */
 
-    pm_optParseOptions3(&argc, 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 (widthSpec && paper_sizeSpec)
@@ -124,7 +152,7 @@ parseCommandLine(int argc, char ** const argv,
     } else
         cmdlineP->expectedLineSize = 0;
 
-    if (argc-1 == 0) 
+    if (argc-1 == 0)
         cmdlineP->inputFilespec = "-";
     else if (argc-1 != 1)
         pm_error("Program takes zero or one argument (filename).  You "
@@ -135,7 +163,7 @@ parseCommandLine(int argc, char ** const argv,
 
 
 
-struct bitStream {
+struct BitStream {
 
     FILE * fileP;
     bool reversebits;
@@ -155,7 +183,7 @@ struct bitStream {
 
 
 static void
-readBit(struct bitStream * const bitStreamP,
+readBit(struct BitStream * const bitStreamP,
         unsigned int *     const bitP,
         const char **      const errorP) {
 /*----------------------------------------------------------------------------
@@ -188,7 +216,7 @@ readBit(struct bitStream * const bitStreamP,
 
 
 static void
-readBitAndDetectEol(struct bitStream * const bitStreamP,
+readBitAndDetectEol(struct BitStream * const bitStreamP,
                     unsigned int *     const bitP,
                     bool *             const eolP,
                     const char **      const errorP) {
@@ -216,10 +244,10 @@ readBitAndDetectEol(struct bitStream * const bitStreamP,
 
 
 static void
-initBitStream(struct bitStream * const bitStreamP,
+initBitStream(struct BitStream * const bitStreamP,
               FILE *             const fileP,
               bool               const reversebits) {
-    
+
     bitStreamP->fileP        = fileP;
     bitStreamP->reversebits  = reversebits;
     bitStreamP->shbit        = 0x00;
@@ -229,17 +257,17 @@ initBitStream(struct bitStream * const bitStreamP,
 
 
 static void
-skipToNextLine(struct bitStream * const bitStreamP) {
+skipToNextLine(struct BitStream * const bitStreamP) {
 
     bool eol;
     const char * error;
 
     eol = FALSE;
     error = NULL;
-    
+
     while (!eol && !error) {
         unsigned int bit;
-        
+
         readBitAndDetectEol(bitStreamP, &bit, &eol, &error);
     }
 }
@@ -247,16 +275,16 @@ skipToNextLine(struct bitStream * const bitStreamP) {
 
 
 static void
-addtohash(g3TableEntry *     hash[], 
-          g3TableEntry       table[], 
-          unsigned int const n, 
-          int          const a, 
+addtohash(G3TableEntry *     hash[],
+          G3TableEntry       table[],
+          unsigned int const n,
+          int          const a,
           int          const b) {
-    
+
     unsigned int i;
 
     for (i = 0; i < n; ++i) {
-        g3TableEntry * const teP = &table[i*2];
+        G3TableEntry * const teP = &table[i*2];
         unsigned int const pos =
             ((teP->length + a) * (teP->code + b)) % HASHSIZE;
         if (hash[pos])
@@ -267,15 +295,15 @@ addtohash(g3TableEntry *     hash[],
 
 
 
-static g3TableEntry *
-hashfind(g3TableEntry *       hash[], 
-         int            const length, 
-         int            const code, 
-         int            const a, 
+static G3TableEntry *
+hashfind(G3TableEntry *       hash[],
+         int            const length,
+         int            const code,
+         int            const a,
          int            const b) {
 
     unsigned int pos;
-    g3TableEntry * te;
+    G3TableEntry * te;
 
     pos = ((length + a) * (code + b)) % HASHSIZE;
     te = hash[pos];
@@ -285,19 +313,19 @@ hashfind(g3TableEntry *       hash[],
 
 
 static void
-buildHashes(g3TableEntry * (*whashP)[HASHSIZE],
-            g3TableEntry * (*bhashP)[HASHSIZE]) {
+buildHashes(G3TableEntry * (*whashP)[HASHSIZE],
+            G3TableEntry * (*bhashP)[HASHSIZE]) {
 
     unsigned int i;
 
     for (i = 0; i < HASHSIZE; ++i)
         (*whashP)[i] = (*bhashP)[i] = NULL;
 
-    addtohash(*whashP, &ttable[0], 64, WHASHA, WHASHB);
-    addtohash(*whashP, &mtable[2], 40, WHASHA, WHASHB);
+    addtohash(*whashP, &g3ttable_table[0], 64, WHASHA, WHASHB);
+    addtohash(*whashP, &g3ttable_mtable[2], 40, WHASHA, WHASHB);
 
-    addtohash(*bhashP, &ttable[1], 64, BHASHA, BHASHB);
-    addtohash(*bhashP, &mtable[3], 40, BHASHA, BHASHB);
+    addtohash(*bhashP, &g3ttable_table[1], 64, BHASHA, BHASHB);
+    addtohash(*bhashP, &g3ttable_mtable[3], 40, BHASHA, BHASHB);
 
 }
 
@@ -314,7 +342,7 @@ makeRowWhite(unsigned char * const packedBitrow,
 
 
 
-static g3TableEntry *
+static G3TableEntry *
 g3code(unsigned int const curcode,
        unsigned int const curlen,
        bit          const color) {
@@ -325,7 +353,7 @@ g3code(unsigned int const curcode,
    Note that it is the _position_ in the table that determines the meaning
    of the code.  The contents of the table entry do not.
 -----------------------------------------------------------------------------*/
-    g3TableEntry * retval;
+    G3TableEntry * retval;
 
     switch (color) {
     case PBM_WHITE:
@@ -382,7 +410,7 @@ writeBlackBitSpan(unsigned char * const packedBitrow,
 enum g3tableId {TERMWHITE, TERMBLACK, MKUPWHITE, MKUPBLACK};
 
 static void
-processG3Code(const g3TableEntry * const teP,
+processG3Code(const G3TableEntry * const teP,
               unsigned char *      const packedBitrow,
               unsigned int *       const colP,
               bit *                const colorP,
@@ -393,15 +421,15 @@ processG3Code(const g3TableEntry * const teP,
    matters.
 -----------------------------------------------------------------------------*/
     enum g3tableId const teId =
-        (teP > mtable ? 2 : 0) + (teP - ttable) % 2;
+        (teP > g3ttable_mtable ? 2 : 0) + (teP - g3ttable_table) % 2;
 
     unsigned int teCount;
-    
+
     switch(teId) {
-    case TERMWHITE: teCount = (teP - ttable    ) / 2;      break;
-    case TERMBLACK: teCount = (teP - ttable - 1) / 2;      break;
-    case MKUPWHITE: teCount = (teP - mtable    ) / 2 * 64; break;
-    case MKUPBLACK: teCount = (teP - mtable - 1) / 2 * 64; break;
+    case TERMWHITE: teCount = (teP - g3ttable_table    ) / 2;      break;
+    case TERMBLACK: teCount = (teP - g3ttable_table - 1) / 2;      break;
+    case MKUPWHITE: teCount = (teP - g3ttable_mtable    ) / 2 * 64; break;
+    case MKUPBLACK: teCount = (teP - g3ttable_mtable - 1) / 2 * 64; break;
     }
 
     switch (teId) {
@@ -409,7 +437,7 @@ processG3Code(const g3TableEntry * const teP,
     case TERMBLACK: {
         unsigned int totalRunLength;
         unsigned int col;
-        
+
         col = *colP;
         totalRunLength = MIN(*countP + teCount, MAXCOLS - col);
 
@@ -451,13 +479,13 @@ formatBadCodeException(const char ** const exceptionP,
 
 
 static void
-readFaxRow(struct bitStream * const bitStreamP,
+readFaxRow(struct BitStream * const bitStreamP,
            unsigned char *    const packedBitrow,
            unsigned int *     const lineLengthP,
            const char **      const exceptionP,
            const char **      const errorP) {
 /*----------------------------------------------------------------------------
-  Read one line of G3 fax from the bit stream *bitStreamP into 
+  Read one line of G3 fax from the bit stream *bitStreamP into
   packedBitrow[].  Return the length of the line, in pixels, as *lineLengthP.
 
   If there's a problem with the line, return as much of it as we can,
@@ -468,15 +496,17 @@ readFaxRow(struct bitStream * const bitStreamP,
   We guarantee that we make progress through the input stream.
 
   Iff there is an error, return a text description of it in newly
-  malloc'ed storage at *errorP and all other specified behavior 
+  malloc'ed storage at *errorP and all other specified behavior
   (including return values) is unspecified.
 -----------------------------------------------------------------------------*/
     unsigned int col;
-    unsigned int curlen;  
-        /* Number of bits we've read so far for the code we're currently 
+    unsigned int curlen;
+        /* Number of bits we've read so far for the code we're currently
            reading
         */
-    unsigned int curcode; 
+    unsigned int fillbits;
+        /* Number of consecutive 0 bits.  Can precede EOL codes */
+    unsigned int curcode;
         /* What we've assembled so far of the code we're currently reading */
     unsigned int count;
         /* Number of consecutive pixels of the same color */
@@ -489,6 +519,7 @@ readFaxRow(struct bitStream * const bitStreamP,
     col = 0;
     curlen = 0;
     curcode = 0;
+    fillbits = 0;
     currentColor = PBM_WHITE;
     count = 0;
     *exceptionP = NULL;
@@ -520,21 +551,26 @@ readFaxRow(struct bitStream * const bitStreamP,
             else {
                 curcode = (curcode << 1) | bit;
                 ++curlen;
-            
-                if (curlen > 13) {
+
+		if (curlen > 11 && curcode == 0x00) {
+		    if (++fillbits > MAXFILLBITS)
+                pm_error("Encountered %u consecutive fill bits.  "
+                       "Aborting", fillbits);
+		}
+		else if (curlen - fillbits > 13) {
                     formatBadCodeException(exceptionP, col, curlen, curcode);
                     done = TRUE;
                 } else if (curcode != 0) {
-                    const g3TableEntry * const teP =
+                    const G3TableEntry * const teP =
                         g3code(curcode, curlen, currentColor);
-                        /* Address of structure that describes the 
+                        /* Address of structure that describes the
                            current G3 code.  Null means 'curcode' isn't
                            a G3 code yet (probably just the beginning of one)
                         */
                     if (teP) {
                         processG3Code(teP, packedBitrow,
                                       &col, &currentColor, &count);
-                        
+
                         curcode = 0;
                         curlen = 0;
                     }
@@ -562,7 +598,7 @@ freeBits(unsigned char ** const packedBits,
             /* This is just a pointer to the previous row; don't want to
                free it twice.
             */
-        } else 
+        } else
             pbm_freerow_packed(packedBits[row]);
     }
     free(packedBits);
@@ -675,11 +711,11 @@ analyzeLineSize(lineSizeAnalyzer * const analyzerP,
    line.  Starting in Netpbm 10.24 (August 2004), we assume there is
    no valid reason to have an empty line and recognize EOF as any
    empty line.  Alternatively, we could read off and ignore two empty
-   lines without a 3rd.  
+   lines without a 3rd.
 */
 
 static void
-readFax(struct bitStream * const bitStreamP,
+readFax(struct BitStream * const bitStreamP,
         bool               const stretch,
         unsigned int       const expectedLineSize,
         bool               const tolerateErrors,
@@ -692,7 +728,7 @@ readFax(struct bitStream * const bitStreamP,
     const char * error;
     bool eof;
     unsigned int row;
-    
+
     MALLOCARRAY_NOFAIL(packedBits, MAXROWS);
 
     initializeLineSizeAnalyzer(&lineSizeAnalyzer,
@@ -723,7 +759,7 @@ readFax(struct bitStream * const bitStreamP,
                     eof = TRUE;
                 } else {
                     analyzeLineSize(&lineSizeAnalyzer, lineSize);
-                    
+
                     if (stretch) {
                         ++row;
                         if (row >= MAXROWS)
@@ -746,15 +782,15 @@ readFax(struct bitStream * const bitStreamP,
 
 
 int
-main(int argc, char * argv[]) {
+main(int argc, const char * argv[]) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     FILE * ifP;
-    struct bitStream bitStream;
+    struct BitStream bitStream;
     unsigned int rows, cols;
     unsigned char ** packedBits;
 
-    pbm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
@@ -773,7 +809,7 @@ main(int argc, char * argv[]) {
     buildHashes(&whash, &bhash);
 
     readFax(&bitStream, cmdline.stretch, cmdline.expectedLineSize,
-            !cmdline.stop_error, 
+            !cmdline.stop_error,
             &packedBits, &cols, &rows);
 
     pm_close(ifP);
diff --git a/converter/pbm/g3ttable.c b/converter/pbm/g3ttable.c
new file mode 100644
index 00000000..6f9eb94f
--- /dev/null
+++ b/converter/pbm/g3ttable.c
@@ -0,0 +1,116 @@
+#include "g3ttable.h"
+
+struct G3TableEntry g3ttable_table[] = {
+/*    TERMWHITE           TERMBLACK   */
+    { 0x35, 8 },    { 0x37, 10 },       /* white 0 , black 0 */
+    { 0x07, 6 },    { 0x02,  3 },
+    { 0x07, 4 },    { 0x03,  2 },
+    { 0x08, 4 },    { 0x02,  2 },
+    { 0x0b, 4 },    { 0x03,  3 },
+    { 0x0c, 4 },    { 0x03,  4 },
+    { 0x0e, 4 },    { 0x02,  4 },
+    { 0x0f, 4 },    { 0x03,  5 },
+    { 0x13, 5 },    { 0x05,  6 },
+    { 0x14, 5 },    { 0x04,  6 },
+    { 0x07, 5 },    { 0x04,  7 },
+    { 0x08, 5 },    { 0x05,  7 },
+    { 0x08, 6 },    { 0x07,  7 },
+    { 0x03, 6 },    { 0x04,  8 },
+    { 0x34, 6 },    { 0x07,  8 },
+    { 0x35, 6 },    { 0x18,  9 },
+    { 0x2a, 6 },    { 0x17, 10 },
+    { 0x2b, 6 },    { 0x18, 10 },
+    { 0x27, 7 },    { 0x08, 10 },
+    { 0x0c, 7 },    { 0x67, 11 },
+    { 0x08, 7 },    { 0x68, 11 },
+    { 0x17, 7 },    { 0x6c, 11 },
+    { 0x03, 7 },    { 0x37, 11 },
+    { 0x04, 7 },    { 0x28, 11 },
+    { 0x28, 7 },    { 0x17, 11 },
+    { 0x2b, 7 },    { 0x18, 11 },
+    { 0x13, 7 },    { 0xca, 12 },
+    { 0x24, 7 },    { 0xcb, 12 },
+    { 0x18, 7 },    { 0xcc, 12 },
+    { 0x02, 8 },    { 0xcd, 12 },
+    { 0x03, 8 },    { 0x68, 12 },
+    { 0x1a, 8 },    { 0x69, 12 },
+    { 0x1b, 8 },    { 0x6a, 12 },
+    { 0x12, 8 },    { 0x6b, 12 },
+    { 0x13, 8 },    { 0xd2, 12 },
+    { 0x14, 8 },    { 0xd3, 12 },
+    { 0x15, 8 },    { 0xd4, 12 },
+    { 0x16, 8 },    { 0xd5, 12 },
+    { 0x17, 8 },    { 0xd6, 12 },
+    { 0x28, 8 },    { 0xd7, 12 },
+    { 0x29, 8 },    { 0x6c, 12 },
+    { 0x2a, 8 },    { 0x6d, 12 },
+    { 0x2b, 8 },    { 0xda, 12 },
+    { 0x2c, 8 },    { 0xdb, 12 },
+    { 0x2d, 8 },    { 0x54, 12 },
+    { 0x04, 8 },    { 0x55, 12 },
+    { 0x05, 8 },    { 0x56, 12 },
+    { 0x0a, 8 },    { 0x57, 12 },
+    { 0x0b, 8 },    { 0x64, 12 },
+    { 0x52, 8 },    { 0x65, 12 },
+    { 0x53, 8 },    { 0x52, 12 },
+    { 0x54, 8 },    { 0x53, 12 },
+    { 0x55, 8 },    { 0x24, 12 },
+    { 0x24, 8 },    { 0x37, 12 },
+    { 0x25, 8 },    { 0x38, 12 },
+    { 0x58, 8 },    { 0x27, 12 },
+    { 0x59, 8 },    { 0x28, 12 },
+    { 0x5a, 8 },    { 0x58, 12 },
+    { 0x5b, 8 },    { 0x59, 12 },
+    { 0x4a, 8 },    { 0x2b, 12 },
+    { 0x4b, 8 },    { 0x2c, 12 },
+    { 0x32, 8 },    { 0x5a, 12 },
+    { 0x33, 8 },    { 0x66, 12 },
+    { 0x34, 8 },    { 0x67, 12 },       /* white 63 , black 63 */
+
+/* mtable */
+/*    MKUPWHITE           MKUPBLACK   */
+    { 0x00, 0 },    { 0x00,  0 },   /* dummy to simplify pointer math */
+    { 0x1b, 5 },    { 0x0f, 10 },   /* white 64 , black 64 */
+    { 0x12, 5 },    { 0xc8, 12 },
+    { 0x17, 6 },    { 0xc9, 12 },
+    { 0x37, 7 },    { 0x5b, 12 },
+    { 0x36, 8 },    { 0x33, 12 },
+    { 0x37, 8 },    { 0x34, 12 },
+    { 0x64, 8 },    { 0x35, 12 },
+    { 0x65, 8 },    { 0x6c, 13 },
+    { 0x68, 8 },    { 0x6d, 13 },
+    { 0x67, 8 },    { 0x4a, 13 },
+    { 0xcc, 9 },    { 0x4b, 13 },
+    { 0xcd, 9 },    { 0x4c, 13 },
+    { 0xd2, 9 },    { 0x4d, 13 },
+    { 0xd3, 9 },    { 0x72, 13 },
+    { 0xd4, 9 },    { 0x73, 13 },
+    { 0xd5, 9 },    { 0x74, 13 },
+    { 0xd6, 9 },    { 0x75, 13 },
+    { 0xd7, 9 },    { 0x76, 13 },
+    { 0xd8, 9 },    { 0x77, 13 },
+    { 0xd9, 9 },    { 0x52, 13 },
+    { 0xda, 9 },    { 0x53, 13 },
+    { 0xdb, 9 },    { 0x54, 13 },
+    { 0x98, 9 },    { 0x55, 13 },
+    { 0x99, 9 },    { 0x5a, 13 },
+    { 0x9a, 9 },    { 0x5b, 13 },
+    { 0x18, 6 },    { 0x64, 13 },
+    { 0x9b, 9 },    { 0x65, 13 },
+    { 0x08, 11 },   { 0x08, 11 },        /* extable len = 1792 */
+    { 0x0c, 11 },   { 0x0c, 11 },
+    { 0x0d, 11 },   { 0x0d, 11 },
+    { 0x12, 12 },   { 0x12, 12 },
+    { 0x13, 12 },   { 0x13, 12 },
+    { 0x14, 12 },   { 0x14, 12 },
+    { 0x15, 12 },   { 0x15, 12 },
+    { 0x16, 12 },   { 0x16, 12 },
+    { 0x17, 12 },   { 0x17, 12 },
+    { 0x1c, 12 },   { 0x1c, 12 },
+    { 0x1d, 12 },   { 0x1d, 12 },
+    { 0x1e, 12 },   { 0x1e, 12 },
+    { 0x1f, 12 },   { 0x1f, 12 },
+};
+
+
+
diff --git a/converter/pbm/g3ttable.h b/converter/pbm/g3ttable.h
new file mode 100644
index 00000000..2ae2bda4
--- /dev/null
+++ b/converter/pbm/g3ttable.h
@@ -0,0 +1,13 @@
+#ifndef G3TTABLE_H_INCLUDED
+#define G3TTABLE_H_INCLUDED
+
+typedef struct G3TableEntry {
+    unsigned short int code;
+    unsigned short int length;
+} G3TableEntry;
+
+extern struct G3TableEntry g3ttable_table[];
+
+#define g3ttable_mtable ((g3ttable_table)+64*2)
+
+#endif
diff --git a/converter/pbm/pbmtoascii.c b/converter/pbm/pbmtoascii.c
index 976b188f..0305a47b 100644
--- a/converter/pbm/pbmtoascii.c
+++ b/converter/pbm/pbmtoascii.c
@@ -83,15 +83,15 @@ BSQ,D04, D04,D05, D04,'L', D05,'[', '<','Z', '/','Z', 'c','k',D06,'R',/*D0-DF*/
 
 
 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) {
+makeRowOfSignatures(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.
 
@@ -183,23 +183,30 @@ pbmtoascii(FILE *       const ifP,
            unsigned int const cellHeight,
            const char * const carr) {
 
-    int cols, rows, format;
+    int format;
+    int cols, rows;
+        /* Dimensions of the input in pixels */
     unsigned int ccols;
+        /* Width of the output in characters */
     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.
+    unsigned int * signatureRow;  /* malloc'ed array */
+        /* This is the cell signatures of a row of cells.
+           signatureRow[0] is the signature for the first (leftmost) cell
+           in the row, signatureRow[1] is the signature for the next one,
+           etc.  A signature is an encoding of the pixels of a cell as
+           an integer, as described above.
         */
-    assert(cellWidth * cellHeight <= sizeof(sig[0])*8);
+    assert(cellWidth * cellHeight <= sizeof(signatureRow[0])*8);
 
     pbm_readpbminit(ifP, &cols, &rows, &format);
 
     ccols = (cols + cellWidth - 1) / cellWidth;
 
-    MALLOCARRAY(sig, ccols);
-    if (sig == NULL)
+    MALLOCARRAY(signatureRow, ccols);
+    if (signatureRow == 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);
@@ -207,16 +214,16 @@ pbmtoascii(FILE *       const ifP,
     for (row = 0; row < rows; row += cellHeight) {
         unsigned int endCol;
 
-        makeRowOfSigs(ifP, cols, rows, format, cellWidth, cellHeight,
-                      row, sig, ccols);
+        makeRowOfSignatures(ifP, cols, rows, format, cellWidth, cellHeight,
+                            row, signatureRow, ccols);
 
-        findRightMargin(sig, ccols, carr, &endCol);
+        findRightMargin(signatureRow, ccols, carr, &endCol);
 
-        assembleCellRow(sig, endCol, carr, line);
+        assembleCellRow(signatureRow, endCol, carr, line);
 
         puts(line);
     }
-    free(sig);
+    free(signatureRow);
     free(line);
 }
 
diff --git a/converter/pbm/pbmtoepson.c b/converter/pbm/pbmtoepson.c
index bb36791d..122a438f 100644
--- a/converter/pbm/pbmtoepson.c
+++ b/converter/pbm/pbmtoepson.c
@@ -11,6 +11,7 @@
 ** implied warranty.
 */
 
+#define _DEFAULT_SOURCE /* New name for SVID & BSD source defines */
 #define _BSD_SOURCE    /* Make sure strcaseeq() is in nstring.h */
 #include <stdio.h>
 
diff --git a/converter/pbm/pbmtog3.c b/converter/pbm/pbmtog3.c
index f0fd1252..f034b466 100644
--- a/converter/pbm/pbmtog3.c
+++ b/converter/pbm/pbmtog3.c
@@ -1,84 +1,54 @@
 /* pbmtog3.c - read a PBM image and produce a Group 3 FAX file
-**
-** Copyright (C) 1989 by Paul Haeberli <paul@manray.sgi.com>.
-**
-** 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.
-*/
 
-/*
-   For specifications for Group 3 (G3) fax MH coding see ITU-T T.4
-   This program generates only MH.  It is coded with future expansion for
-   MR and MMR in mind.
+   For specifications for Group 3 (G3) fax MH coding see ITU-T T.4:
+   Standardization of Group 3 facsimile terminals for document transmission
+   https://www.itu.int/rec/T-REC-T.4/en
+
+   This program generates only MH.
 */
 
+
 #include <assert.h>
 
 #include "pm_c_util.h"
 #include "shhopt.h"
 #include "mallocvar.h"
 #include "bitreverse.h"
-#include "wordaccess.h"
-#include "wordintclz.h"
+#include "intcode.h"
 #include "g3.h"
+#include "g3ttable.h"
+#include "g3prefab.h"
 #include "pbm.h"
 
-#define TC_MC 64
-
-static bool const pbmtorl = 
-#ifdef PBMTORL
-    TRUE;
-#else
-    FALSE;
-#endif
-
+enum G3eol {EOL, ALIGN8, ALIGN16, NO_EOL, NO_RTC, NO_EOLRTC};
 
-struct bitString {
-    /* A string of bits, up to as many fit in a word. */
-    unsigned int bitCount;
-        /* The length of the bit string */
-    wordint intBuffer;
-        /* The bits are in the 'bitCount' least significant bit positions 
-           of this number.  The rest of the bits of this number are always 
-           zero.
-        */
+struct OutStream;
 
-    /* Example:  The bit string 010100, on a machine with a 32 bit word,
-       would be represented by bitCount = 6, intBuffer = 20
-       (N.B. 20 = 00000000 00000000 00000000 00010100 in binary)
-    */
+struct OutStream {
+    FILE * fp;
+    struct BitString buffer;
+    bool reverseBits;    /* Reverse bit order */
+    enum G3eol eolAlign; /* Omit EOL and/or RTC; align EOL to 8/16 bits */
+    void * data;         /* Reserved for future expansion */
 };
 
 
 
-struct outStream {
-    struct bitString buffer;
-
-    bool reverseBits;
-};
-
-/* This is a global variable for speed. */
-static struct outStream out;
-
-
 struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
     const char * inputFileName;
     unsigned int reversebits;
-    unsigned int nofixedwidth;
+    enum G3eol   align;
+    unsigned int desiredWidth;
     unsigned int verbose;
 };
 
 
 
 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
@@ -87,6 +57,8 @@ parseCommandLine(int argc, char ** const argv,
     optEntry * option_def;
         /* Instructions to OptParseOptions2 on how to parse our options.  */
     optStruct3 opt;
+    unsigned int nofixedwidth;
+    unsigned int align8, align16;
 
     unsigned int option_def_index;
 
@@ -95,9 +67,13 @@ parseCommandLine(int argc, char ** const argv,
     option_def_index = 0;   /* incremented by OPTENTRY */
     OPTENT3(0,   "reversebits",      OPT_FLAG,  NULL, &cmdlineP->reversebits,
             0);
-    OPTENT3(0,   "nofixedwidth",     OPT_FLAG,  NULL, &cmdlineP->nofixedwidth,
+    OPTENT3(0,   "nofixedwidth",     OPT_FLAG,  NULL, &nofixedwidth,
             0);
-    OPTENT3(0,   "verbose",          OPT_FLAG,  NULL, &cmdlineP->verbose, 
+    OPTENT3(0,   "align8",           OPT_FLAG,  NULL, &align8,
+            0);
+    OPTENT3(0,   "align16",          OPT_FLAG,  NULL, &align16,
+            0);
+    OPTENT3(0,   "verbose",          OPT_FLAG,  NULL, &cmdlineP->verbose,
             0);
 
     /* TODO
@@ -105,15 +81,30 @@ parseCommandLine(int argc, char ** const argv,
     */
 
     opt.opt_table = option_def;
-    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
-    opt.allowNegNum = TRUE;  /* We may have parms that are negative numbers */
+    opt.short_allowed = false;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = true;  /* We may have parms that are negative numbers */
 
-    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     free(option_def);
 
-    if (argc-1 == 0) 
+    if (align8) {
+        if (align16)
+            pm_error("You can't specify both -align8 and -align16");
+        else
+            cmdlineP->align = ALIGN8;
+    } else if (align16)
+        cmdlineP->align = ALIGN16;
+    else
+        cmdlineP->align = EOL;
+
+    if (nofixedwidth)
+        cmdlineP->desiredWidth = 0;
+    else
+        cmdlineP->desiredWidth = 1728;
+
+    if (argc-1 == 0)
         cmdlineP->inputFileName = "-";
     else if (argc-1 != 1)
         pm_error("Program takes zero or one argument (filename).  You "
@@ -125,31 +116,79 @@ parseCommandLine(int argc, char ** const argv,
 
 
 static void
-reversebuffer(unsigned char * const p, 
+reversebuffer(unsigned char * const p,
               unsigned int    const n) {
 
     unsigned int i;
+
     for (i = 0; i < n; ++i)
         p[i] = bitreverse[p[i]];
 }
 
 
 
-static struct bitString
-makeBs(wordint      const bits, 
-       unsigned int const bitCount) {
+static void
+flushBuffer(struct OutStream * const outP) {
+/*----------------------------------------------------------------------------
+  Flush the contents of the bit buffer
+-----------------------------------------------------------------------------*/
+    struct BitString const buffer = outP->buffer;
 
-    struct bitString retval;
-    retval.intBuffer = bits;
-    retval.bitCount  = bitCount;
+    assert (buffer.bitCount <= 32);
 
-    return retval;
+    if (buffer.bitCount > 0) {
+        unsigned int const fullBuffer = sizeof(buffer.intBuffer) * 8;
+        unsigned int const bytesToWrite = (buffer.bitCount+7)/8;
+        bigend32 outbytes;
+        size_t rc;
+
+        outbytes = pm_bigendFromUint32(
+                   buffer.intBuffer << (fullBuffer - buffer.bitCount));
+        if (outP->reverseBits)
+    	reversebuffer((unsigned char *)&outbytes, bytesToWrite);
+        rc = fwrite((unsigned char *)&outbytes, 1, bytesToWrite, outP->fp);
+        if (rc != bytesToWrite)
+            pm_error("Output error");
+    }
 }
 
 
+#if 1==0
+static void
+putbitsDump(struct OutStream * const outP,
+            struct BitString   const newBits) {
+/*----------------------------------------------------------------------------
+  Print the content of the bit put request, in human readable text form
+  For debugging.  Also good for studying how the coding scheme works.
+
+  By default the compiler ignores this function.
+  To turn on, remove the "#if" - "#endif" lines enclosing the function and
+  edit the output function name in putbits().
+-----------------------------------------------------------------------------*/
+    unsigned int const bitCount = newBits.bitCount;
+
+    unsigned int i;
+    char charBuff[128];
+
+    assert (bitCount >= 0 && bitCount < 32);
+    assert (sizeof(newBits.intBuffer) + 2 < 128);
+
+    for (i = 0; i < bitCount; ++i) {
+        unsigned int const n = bitCount - i - 1;
+        charBuff[i] = ((newBits.intBuffer >> n) & 0x01) + '0';
+    }
+
+    charBuff[bitCount]   = '\n';
+    charBuff[bitCount+1] = '\0';
+    fwrite(charBuff, 1, bitCount+1, outP->fp);
+}
+#endif
+
+
 
-static __inline__ void
-putbits(struct bitString const newBits) {
+static void
+putbitsBinary(struct OutStream * const outP,
+              struct BitString   const newBits) {
 /*----------------------------------------------------------------------------
    Push the bits 'newBits' onto the right end of output buffer
    out.buffer (moving the bits already in the buffer left).
@@ -158,334 +197,462 @@ putbits(struct bitString const newBits) {
 
    'newBits' must be shorter than a whole word.
 
-   N.B. the definition of struct bitString requires upper bits to be zero.
+   N.B. the definition of struct BitString requires upper bits to be zero.
 -----------------------------------------------------------------------------*/
-    unsigned int const spaceLeft = 
-        sizeof(out.buffer.intBuffer)*8 - out.buffer.bitCount;
+    unsigned int const fullBuffer = sizeof(outP->buffer.intBuffer) * 8;
+    unsigned int const spaceLeft = fullBuffer - outP->buffer.bitCount;
         /* Number of bits of unused space (at the high end) in buffer */
 
-    assert(newBits.bitCount < sizeof(out.buffer.intBuffer) * 8);
+    assert(newBits.bitCount < fullBuffer);
     assert(newBits.intBuffer >> newBits.bitCount == 0);
 
     if (spaceLeft > newBits.bitCount) {
         /* New bits fit with bits to spare */
-        out.buffer.intBuffer = 
-            out.buffer.intBuffer << newBits.bitCount | newBits.intBuffer;
-        out.buffer.bitCount += newBits.bitCount;
-    } else { 
+        outP->buffer.intBuffer =
+            outP->buffer.intBuffer << newBits.bitCount | newBits.intBuffer;
+        outP->buffer.bitCount += newBits.bitCount;
+    } else {
         /* New bits fill buffer.  We'll have to flush the buffer to stdout
            and put the rest of the bits in the new buffer.
         */
         unsigned int const nextBufBitCount = newBits.bitCount - spaceLeft;
+        unsigned int const bitMask = ((1<<nextBufBitCount) - 1);
 
-        wordintBytes outbytes;
-        size_t rc;
+        outP->buffer.intBuffer = ( (outP->buffer.intBuffer << spaceLeft)
+                                 | (newBits.intBuffer >> nextBufBitCount));
+        outP->buffer.bitCount  = fullBuffer;
+        flushBuffer(outP);
 
-        wordintToBytes(&outbytes, 
-                       (out.buffer.intBuffer << spaceLeft) 
-                       | (newBits.intBuffer >> nextBufBitCount));
-        if (out.reverseBits)
-            reversebuffer(outbytes, sizeof(outbytes));
+        outP->buffer.intBuffer = newBits.intBuffer & bitMask;
+        outP->buffer.bitCount = nextBufBitCount;
+    }
+}
 
-        rc = fwrite(outbytes, 1, sizeof(outbytes), stdout);
-        if (rc != sizeof(outbytes))
-            pm_error("Output error.  Unable to fwrite() to stdout");
 
-        out.buffer.intBuffer = newBits.intBuffer & ((1<<nextBufBitCount) - 1); 
-        out.buffer.bitCount = nextBufBitCount;
-    }
+
+static void
+initOutStream(struct OutStream * const outP,
+              bool               const reverseBits,
+              enum G3eol         const eolAlign) {
+
+    outP->buffer.intBuffer = 0;
+    outP->buffer.bitCount  = 0;
+    outP->reverseBits      = reverseBits;
+    outP->fp               = stdout;
+    outP->eolAlign         = eolAlign;
+}
+
+
+
+static struct BitString
+tableEntryToBitString(G3TableEntry const tableEntry) {
+
+    struct BitString retval;
+
+    retval.intBuffer = tableEntry.code;
+    retval.bitCount  = tableEntry.length;
+
+    return retval;
 }
 
 
 
-static void 
-initOutStream(bool const reverseBits) {
-    out.buffer.intBuffer = 0;
-    out.buffer.bitCount  = 0;
-    out.reverseBits = reverseBits;
+static void
+putbits(struct OutStream * const outP,
+        struct BitString   const newBits) {
+
+    putbitsBinary(outP, newBits);
+    /* Change to putbitsDump() for human readable output */
 }
 
 
 
-static __inline__ void
-putcode(unsigned int const clr, 
-        unsigned int const ix) {
+static void
+putcodeShort(struct OutStream * const outP,
+             bit                const color,
+             unsigned int       const runLength) {
 
-    /* Note that this requires ttable to be aligned white entry, black
-       entry, white, black, etc.  
+    /* Note that this requires g3ttable_table to be aligned white entry, black
+       entry, white, black, etc.
     */
-    putbits(makeBs(ttable[ix * 2 + clr].code, ttable[ix * 2 + clr].length));
+    unsigned int index = runLength * 2 + color;
+    putbits(outP, tableEntryToBitString(g3ttable_table[index]));
 }
 
 
 
-static __inline__ void
-putcode2(int const clr,
-         int const ix) {
+static void
+putcodeLong(struct OutStream * const outP,
+            bit                const color,
+            unsigned int       const runLength) {
 /*----------------------------------------------------------------------------
    Output Make-up code and Terminating code at once.
 
-   For run lengths above TC_MC threshold (usually 64).
+   For run lengths which require both: length 64 and above
 
    The codes are combined here to avoid calculations in putbits()
-   wordint is usually wide enough, with 32 or 64 bits.
-   Provisions are made for 16 bit wordint (for debugging).
 
    Terminating code is max 12 bits, Make-up code is max 13 bits.
-   (See ttable, mtable entries in pbmtog3.h)
+   (See g3ttable_table, g3ttable_mtable entries in g3ttable.h)
 
    Also reduces object code size when putcode is compiled inline.
 -----------------------------------------------------------------------------*/
-    unsigned int const loIndex = ix % 64 * 2 + clr;
-    unsigned int const hiIndex = ix / 64 * 2 + clr;
-
-    if (sizeof(wordint) * 8 > 24) {
-        unsigned int const l1 = ttable[loIndex].length;
-
-        putbits(
-            makeBs(mtable[hiIndex].code << l1 | ttable[loIndex].code,
-                   mtable[hiIndex].length + l1)
-            );
-    } else { /* typically 16 bit wordint used for debugging */
-        putbits(makeBs(mtable[hiIndex].code, mtable[hiIndex].length));
-        putbits(makeBs(ttable[loIndex].code, ttable[loIndex].length));
-    }
+    unsigned int const loIndex = runLength % 64 * 2 + color;
+    unsigned int const hiIndex = runLength / 64 * 2 + color;
+    unsigned int const loLength = g3ttable_table[loIndex].length;
+    unsigned int const hiLength = g3ttable_mtable[hiIndex].length;
+
+    struct BitString combinedCode;
+
+    combinedCode.intBuffer = g3ttable_mtable[hiIndex].code << loLength |
+                             g3ttable_table[loIndex].code;
+    combinedCode.bitCount  = hiLength + loLength;
+
+    putbits(outP, combinedCode);
 }
 
 
 
-static __inline__ void
-putspan_normal(bit          const color, 
-               unsigned int const len) {
+static  void
+putcodeExtra(struct OutStream * const outP,
+             int                const color,
+             int                const runLength) {
+/*----------------------------------------------------------------------------
+   Lengths over 2560.  This is rare.
+   According to the standard, the mark-up code for 2560 can be issued as
+   many times as necessary without terminal codes.
+   --------------------------------------------------------------------------*/
+    G3TableEntry const markUp2560 = g3ttable_mtable[2560/64*2];
+                              /* Same code for black and white */
 
-    if (len < TC_MC)
-        putcode(color, len);
-    else if (len < 2624)
-        putcode2(color, len);
-    else {  /* len >= 2624 : rare */
-        unsigned int remainingLen;
+    unsigned int remainingLen;
 
-        for (remainingLen = len;
-             remainingLen >= 2624;
-             remainingLen -= 2623) {
+    for (remainingLen = runLength; remainingLen > 2560; remainingLen -= 2560)
+      putbits(outP, tableEntryToBitString(markUp2560));
+    /* after the above: 0 < remainingLen <= 2560 */
 
-            putcode2(color, 2560+63);
-            putcode(!color, 0);
-        }
-        if (remainingLen < TC_MC)
-            putcode(color, remainingLen);
-        else  /* TC_MC <= len < 2624 */
-            putcode2(color, remainingLen);
-    }
+    if (remainingLen >= 64)
+        putcodeLong(outP, color, remainingLen);
+    else
+        putcodeShort(outP, color, remainingLen);
 }
 
 
 
-static __inline__ void
-putspan(bit          const color, 
-        unsigned int const len) {
-/*----------------------------------------------------------------------------
-   Put a span of 'len' pixels of color 'color' in the output.
------------------------------------------------------------------------------*/
-    if (pbmtorl) {
-        if (len > 0) 
-            printf("%c %d\n", color == PBM_WHITE ? 'W' : 'B', len);
-    } else 
-        putspan_normal(color, len);
+static void
+putspan(struct OutStream * const outP,
+        bit                const color,
+        unsigned int       const runLength) {
+
+    if (runLength < 64)
+        putcodeShort(outP, color, runLength);
+    else if (runLength < 2560)
+        putcodeLong (outP, color, runLength);
+    else  /* runLength > 2560 : rare */
+        putcodeExtra(outP, color, runLength);
 }
 
 
 
 static void
-puteol(void) {
+puteol(struct OutStream * const outP) {
+
+    switch (outP->eolAlign) {
+    case EOL: {
+        struct BitString const eol = { 1, 12 };
+
+        putbits(outP, eol);
+    } break;
+    case ALIGN8:  case ALIGN16: {
+        unsigned int const bitCount = outP->buffer.bitCount;
+        unsigned int const fillbits =
+            (outP->eolAlign == ALIGN8) ? (44 - bitCount) % 8
+            : (52 - bitCount) % 16;
+
+        struct BitString eol;
+
+        eol.bitCount = 12 + fillbits;     eol.intBuffer = 1;
+        putbits(outP, eol);
+    } break;
+    case NO_EOL: case NO_EOLRTC:
+        break;
+    case NO_RTC:
+        pm_error("INTERNAL ERROR: no-RTC EOL treatment not implemented");
+        break;
+    }
+}
 
-    if (pbmtorl)
-        puts("EOL");
-    else {
-        struct bitString const eol = {12, 1};
 
-        putbits(eol);
+
+static void
+putrtc(struct OutStream * const outP) {
+
+    switch (outP->eolAlign) {
+    case NO_RTC: case NO_EOLRTC:
+        break;
+    default:
+        puteol(outP);    puteol(outP);    puteol(outP);
+        puteol(outP);    puteol(outP);    puteol(outP);
     }
 }
 
 
 
-/*
-  PBM raw bitrow to inflection point array
+static void
+readOffSideMargins(unsigned char * const bitrow,
+                   unsigned int    const colChars,
+                   unsigned int  * const firstNonWhiteCharP,
+                   unsigned int  * const lastNonWhiteCharP,
+                   bool          * const blankRowP) {
+/*----------------------------------------------------------------------------
+  Determine the white margins on the left and right side of a row.
+  This is an enhancement: convertRowToG3() works without this.
+-----------------------------------------------------------------------------*/
+    unsigned int charCnt;
+    unsigned int firstChar;
+    unsigned int lastChar;
+    bool         blankRow;
 
-  Write inflection (=color change) points into array milepost[].  
-  It is easy to calculate run length from this.
+    assert(colChars > 0);
 
-  In milepost, a white-to-black (black-to-white) inflection point
-  always has an even (odd) index.  A line starting with black is
-  indicated by bitrow[0] == 0.
+    for (charCnt = 0; charCnt < colChars && bitrow[charCnt] == 0; ++charCnt);
 
-  WWWWWWWBBWWWWWWW ... = 7,2,7, ...
-  BBBBBWBBBBBWBBBB ... = 0,5,1,5,1,4, ...
+    if (charCnt >= colChars) {
+        /* Reached end of bitrow with no black pixels encountered */
+        firstChar = lastChar = 0;
+        blankRow  = true;
+    } else {
+        /* There is at least one black pixel in the row */
+        firstChar = charCnt;
+        blankRow = false;
 
-  Return the number of milepost elements written.
-  Note that max number of entries into milepost = cols+1 .
+        charCnt = colChars - 1;
 
-  The inflection points are calculated like this:
+        while (bitrow[charCnt--] == 0x00)
+            ;
+        lastChar = charCnt + 1;
+    }
 
-   r1: 00000000000111111110011111000000
-   r2: c0000000000011111111001111100000 0->carry
-  xor: ?0000000000100000001010000100000
+    *firstNonWhiteCharP = firstChar;
+    *lastNonWhiteCharP  = lastChar;
+    *blankRowP          = blankRow;
+}
 
-  The 1 bits in the xor above are the inflection points.
-*/
 
-static __inline__ void
-convertRowToRunLengths(unsigned char * const bitrow, 
-                       int             const cols, 
-                       unsigned int *  const milepost,
-                       unsigned int *  const lengthP) {
-
-    unsigned int   const bitsPerWord  = sizeof(wordint) * 8;
-    wordint      * const bitrowByWord = (wordint *) bitrow;
-    int            const wordCount    = (cols + bitsPerWord - 1)/bitsPerWord; 
-        /* Number of full and partial words in the row */
-
-
-    if (cols % bitsPerWord != 0) {
-        /* Clean final word in row.  For loop simplicity */
-        wordint r1;
-        r1 = bytesToWordint((unsigned char *)&bitrowByWord[wordCount - 1]);
-        r1 >>= bitsPerWord - cols % bitsPerWord;
-        r1 <<= bitsPerWord - cols % bitsPerWord;
-        wordintToBytes((wordintBytes *)&bitrowByWord[wordCount - 1], r1);
+
+static void
+setBlockBitsInFinalChar(unsigned char * const finalByteP,
+                        unsigned int    const cols) {
+/*----------------------------------------------------------------------------
+   If the char in the row is fractional, set it up so that the don't care
+   bits are the opposite color of the last valid pixel.
+----------------------------------------------------------------------------*/
+    unsigned char const finalByte  = *finalByteP;
+    unsigned int const silentBitCnt = 8 - cols % 8;
+    bit const rowEndColor = (finalByte >> silentBitCnt) & 0x01;
+
+    if (rowEndColor == PBM_WHITE) {
+        unsigned char const blackMask = (0x01 << silentBitCnt) - 1;
+
+        *finalByteP = finalByte | blackMask;
     }
-    {
-
-        wordint carry;
-        wordint r1, r2;
-        unsigned int n;
-        int i,c,k;
-
-        for (i = carry = n = 0; i < wordCount; ++i) {
-            r1 = r2 = bytesToWordint((unsigned char *)&bitrowByWord[i]);
-            r2 = r1 ^ (carry << (bitsPerWord-1) | r2 >> 1);
-            carry = r1 & 0x1;  k = 0;
-            while (r2 != 0) {
-                /* wordintClz(r2) reports most significant "1" bit of r2
-                   counting from MSB = position 0.
-                */
-                c = wordintClz(r2);
-                milepost[n++] = i * bitsPerWord + k + c;
-                r2 <<= c++; r2 <<= 1;  k += c; 
-            } 
+    /* No adjustment required if the row ends with a black pixel.
+       pbm_cleanrowend_packed() takes care of this.
+    */
+}
+
+
+
+static void
+trimFinalChar(struct OutStream * const outP,
+              bit                const color,
+              int                const carryLength,
+              int                const existingCols,
+              int                const desiredWidth) {
+/*---------------------------------------------------------------------------
+   If the carry value from the last char in the row represents a valid
+   sequence, output it.
+
+   (1) If input row width is not a whole multiple of 8 and -nofixwidth
+       was specified, the final carry value represents inactive bits
+       at the row end.  Emit no code.  See setBlockBitsInFinalChar().
+
+   (2) If there is white margin on the right side, the final carry value
+       is valid.  We add to it the margin width.  Right-side margin may
+       be added in main() to a narrow input image, detected in the
+       input row by readOffSideMargins() or both.  The same treatment
+       applies regardless of the nature of the right-side margin.
+----------------------------------------------------------------------------*/
+    if (existingCols == desiredWidth) {
+        if (existingCols % 8 == 0)
+            putspan(outP, color, carryLength);  /* Code up to byte boundary */
+        /* Emit nothing if existingCols is not a whole multiple of 8 */
+    } else if (existingCols < desiredWidth) {
+        if (color == 0) {       /* Last bit sequence in final char: white */
+            unsigned int const totalLength =
+                carryLength + (desiredWidth - existingCols);
+            putspan(outP, 0, totalLength);
+        } else {                 /* Black */
+            unsigned int const padLength = desiredWidth - existingCols;
+            putspan(outP, 1, carryLength);
+            putspan(outP, 0, padLength);
         }
-        if (n == 0 || milepost[n - 1] != cols) 
-            milepost[n++] = cols;
-        *lengthP = n;
     }
 }
 
 
 
 static void
-padToDesiredWidth(unsigned int * const milepost,
-                  unsigned int * const nRunP,
-                  int            const existingCols,
-                  int            const desiredCols) {
-
-    if (existingCols < desiredCols) {
-        /* adjustment for narrow input in fixed width mode
-           nRun % 2 == 1 (0) means last (=rightmost) pixel is white (black)
-           if white, extend the last span to outwidth
-           if black, fill with a white span len (outwidth - readcols)
-        */
-        if (*nRunP % 2 == 0)
-            ++*nRunP;
-        milepost[*nRunP - 1] = desiredCols;
+convertRowToG3(struct OutStream * const outP,
+               unsigned char    * const bitrow,
+               unsigned int       const existingCols,
+               unsigned int       const desiredWidth) {
+/*----------------------------------------------------------------------------
+   Table based Huffman coding
+
+   Normally Huffman code encoders count sequences of ones and zeros
+   and convert them to binary codes as they terminate.  This program
+   recognizes chains of pixels and converts them directly, reading
+   prefabricated code chains from an indexed table.
+
+   For example the 8-bit sequence 01100110 translates to
+   Huffman code: 000111 11 0111 11 000111.
+
+   In reality things are more complicated.  The leftmost 0 (MSB) may be
+   part of a longer sequence starting in the adjacent byte or perhaps
+   spanning several bytes.  Likewise for the rightmost 0.
+
+   So we first remove the sequence on the left side and compare its
+   color with the leftmost pixel of the adjacent byte and emit either
+   one code for a single sequence if they agree or two if they disagree.
+   Next the composite code for the central part (in the above example
+   110011 -> 11 0111 11) is emitted.  Finally we save the length and
+   color of the sequence on the right end as carry-over for the next
+   byte cycle.  Some 8-bit input sequences (00000000, 01111111,
+   00111111, etc.) have no central part: these are special cases.
+---------------------------------------------------------------------------*/
+    unsigned int const colChars = pbm_packed_bytes(existingCols);
+
+    unsigned int charCnt;
+    unsigned int firstActiveChar;
+    unsigned int lastActiveChar;
+    bool         blankRow;
+    bit          borderColor;
+
+    borderColor = PBM_WHITE; /* initial value */
+
+    if (existingCols == desiredWidth && (desiredWidth % 8) > 0)
+        setBlockBitsInFinalChar(&bitrow[colChars-1], desiredWidth);
+
+    readOffSideMargins(bitrow, colChars,
+                       &firstActiveChar, &lastActiveChar, &blankRow);
+
+    if (blankRow)
+        putspan(outP, PBM_WHITE, desiredWidth);
+    else {
+        unsigned int carryLength;
+
+        for (charCnt = firstActiveChar, carryLength = firstActiveChar * 8;
+             charCnt <=lastActiveChar;
+             ++charCnt) {
+
+            unsigned char const byte = bitrow[charCnt];
+            bit const rColor = !borderColor;
+
+            if (byte == borderColor * 0xFF) {
+                carryLength += 8;
+            } else if (byte == (unsigned char) ~(borderColor * 0xFF)) {
+                putspan(outP, borderColor, carryLength);
+                carryLength = 8;
+                borderColor = rColor;
+            } else {
+                struct PrefabCode const code = g3prefab_code[byte];
+                unsigned int const activeLength =
+                    8 - code.leadBits - code.trailBits;
+
+                if (borderColor == (byte >> 7)) {
+                    putspan(outP, borderColor, carryLength + code.leadBits);
+                } else {
+                    putspan(outP, borderColor, carryLength);
+                    putcodeShort(outP, rColor, code.leadBits);
+                }
+                if (activeLength > 0)
+                    putbits(outP, code.activeBits);
+
+                borderColor = byte & 0x01;
+                carryLength = code.trailBits;
+            }
+        }
+        trimFinalChar(outP, borderColor, carryLength,
+                      (lastActiveChar + 1) * 8, desiredWidth);
     }
+    puteol(outP);
 }
 
 
 
 int
-main(int    argc,
-     char * argv[]) {
+main(int          argc,
+     const char * argv[]) {
 
     struct CmdlineInfo cmdline;
     FILE * ifP;
     unsigned char * bitrow;
        /* This is the bits of the current row, as read from the input and
-           modified various ways at various points in the program.  It has
-           a word of zero padding on the high (right) end for the convenience
-           of code that accesses this buffer in word-size bites.
+          modified various ways at various points in the program.  It has
+          a word of zero padding on the high (right) end for the convenience
+          of code that accesses this buffer in word-size bites.
         */
 
     int rows;
     int cols;
-    int readcols;
-    int outwidth;
     int format;
-    int row;
-    unsigned int * milepost;
+    unsigned int existingCols;
+    unsigned int desiredWidth;
+    unsigned int row;
+    struct OutStream out;
 
-    pbm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
     ifP = pm_openr(cmdline.inputFileName);
 
     pbm_readpbminit(ifP, &cols, &rows, &format);
-    if (cmdline.nofixedwidth)
-        readcols = outwidth = cols;
+
+    if (cmdline.desiredWidth == 0)
+        desiredWidth = existingCols = cols;
     else {
-        readcols = MIN(cols, 1728);
-        outwidth = 1728;
+        if (cmdline.desiredWidth < cols)
+            existingCols = desiredWidth = cmdline.desiredWidth;
+        else {
+            existingCols = pbm_packed_bytes(cols) * 8;
+            desiredWidth = cmdline.desiredWidth;
+        }
     }
 
-    MALLOCARRAY_NOFAIL(bitrow, pbm_packed_bytes(cols) + sizeof(wordint));
+    MALLOCARRAY(bitrow, pbm_packed_bytes(cols) + sizeof(uint32_t));
 
-    MALLOCARRAY_NOFAIL(milepost, readcols + 2);
+    if (!bitrow)
+        pm_error("Failed to allocate a row buffer for %u columns", cols);
 
-    initOutStream(cmdline.reversebits);
-    puteol();
+    initOutStream(&out, cmdline.reversebits, cmdline.align);
 
-    for (row = 0; row < rows; ++row) {
-        unsigned int nRun;  /* Number of runs in milepost[] */
-        unsigned int p;
-        unsigned int i;
+    puteol(&out);
 
+    for (row = 0; row < rows; ++row) {
         pbm_readpbmrow_packed(ifP, bitrow, cols, format);
-
-        convertRowToRunLengths(bitrow, readcols, milepost, &nRun);
-
-        padToDesiredWidth(milepost, &nRun, readcols, outwidth);
-
-        for (i = p = 0; i < nRun; p = milepost[i++])
-            putspan(i%2 == 0 ? PBM_WHITE : PBM_BLACK, milepost[i] - p);
-        /* TODO 2-dimensional coding MR, MMR */
-        puteol();
+        pbm_cleanrowend_packed(bitrow, cols);
+        convertRowToG3(&out, bitrow, existingCols, desiredWidth);
     }
 
-    free(milepost);
     pbm_freerow_packed(bitrow);
-
-    {
-        unsigned int i;  
-        for( i = 0; i < 6; ++i)
-            puteol();
-    }
-    if (out.buffer.bitCount > 0) {
-        /* flush final partial buffer */
-        unsigned int const bytesToWrite = (out.buffer.bitCount+7)/8;
-
-        unsigned char outbytes[sizeof(wordint)];
-        size_t rc;
-        wordintToBytes(&outbytes, 
-                       out.buffer.intBuffer << (sizeof(out.buffer.intBuffer)*8 
-                                                - out.buffer.bitCount));
-        if (out.reverseBits)
-            reversebuffer(outbytes, bytesToWrite);
-        rc = fwrite(outbytes, 1, bytesToWrite, stdout);
-        if (rc != bytesToWrite)
-            pm_error("Output error");
-    }
+    putrtc(&out);
+    flushBuffer(&out);
     pm_close(ifP);
 
     return 0;
 }
+
+
+
diff --git a/converter/pbm/pbmtolj.c b/converter/pbm/pbmtolj.c
index 0cceb4fe..3cd76703 100644
--- a/converter/pbm/pbmtolj.c
+++ b/converter/pbm/pbmtolj.c
@@ -1,14 +1,14 @@
 /* pbmtolj.c - read a portable bitmap and produce a LaserJet bitmap file
-**  
+**
 **  based on pbmtops.c
 **
 **  Michael Haberler HP Vienna mah@hpuviea.uucp
 **                 mcvax!tuvie!mah
-**  misfeatures: 
+**  misfeatures:
 **      no positioning
 **
 **      Bug fix Dec 12, 1988 :
-**              lines in putbit() reshuffled 
+**              lines in putbit() reshuffled
 **              now runs OK on HP-UX 6.0 with X10R4 and HP Laserjet II
 **      Bo Thide', Swedish Institute of Space Physics, Uppsala <bt@irfu.se>
 **
@@ -75,7 +75,7 @@ parseCommandLine(int argc, char ** argv,
     MALLOCARRAY(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENTRY */
-    OPTENT3(0,   "resolution",  OPT_UINT, &cmdlineP->dpi, 
+    OPTENT3(0,   "resolution",  OPT_UINT, &cmdlineP->dpi,
             &dpiSpec, 0);
     OPTENT3(0,   "copies",      OPT_UINT, &cmdlineP->copies,
             &copiesSpec, 0);
@@ -97,7 +97,7 @@ parseCommandLine(int argc, char ** argv,
     pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
-    if (argc-1 == 0) 
+    if (argc-1 == 0)
         cmdlineP->inputFilename = "-";
     else if (argc-1 != 1)
         pm_error("Program takes zero or one argument (filename).  You "
@@ -246,7 +246,7 @@ packbits(void) {
           We drop out here after having found a [possibly empty]
           literal, followed by a [possibly degenerate] run of repeated
           bytes.  Degenerate runs can occur at the end of the scan line...
-          there may be a "repeat" of 1 byte (which can't actually be 
+          there may be a "repeat" of 1 byte (which can't actually be
           represented as a repeat) so we simply fold it into the previous
           literal.
         */
@@ -320,11 +320,11 @@ deltarow(void) {
             skip = 1;
         }
         if (mustBurst) {
-            burstCode = burstEnd - burstStart; 
+            burstCode = burstEnd - burstStart;
                 /* 0-7, means 1-8 bytes follow */
             code = (burstCode << 5) | skipped;
             deltaBuffer[deltaBufferIndex++] = (char) code;
-            memcpy(deltaBuffer+deltaBufferIndex, rowBuffer+burstStart, 
+            memcpy(deltaBuffer+deltaBufferIndex, rowBuffer+burstStart,
                    burstCode + 1);
             deltaBufferIndex += burstCode + 1;
             burstStart = -1;
@@ -369,7 +369,7 @@ convertRow(const bit *    const bitrow,
            bool *         const rowIsBlankP) {
 
     unsigned int rightmostBlackCol;
-        
+
     findRightmostBlackCol(bitrow, cols, rowIsBlankP, &rightmostBlackCol);
 
     if (!*rowIsBlankP) {
@@ -377,7 +377,7 @@ convertRow(const bit *    const bitrow,
             /* Number of columns excluding white right margin */
         unsigned int const rucols = ((nzcol + 7) / 8) * 8;
             /* 'nzcol' rounded up to nearest multiple of 8 */
-        
+
         unsigned int col;
 
         memset(rowBuffer, 0, rowBufferSize);
@@ -404,7 +404,7 @@ convertRow(const bit *    const bitrow,
 
         if (delta) {
             /* May need to temporarily bump the row buffer index up to
-               whatever the previous line's was - if this line is shorter 
+               whatever the previous line's was - if this line is shorter
                than the previous would otherwise leave dangling cruft.
             */
             unsigned int const savedRowBufferIndex = rowBufferIndex;
@@ -421,7 +421,7 @@ convertRow(const bit *    const bitrow,
 }
 
 
-    
+
 static void
 printBlankRows(unsigned int const count) {
 
@@ -430,12 +430,12 @@ printBlankRows(unsigned int const count) {
         /* The code used to be this, but Charles Howes reports that
            this escape sequence does not exist on his HP Laserjet IIP
            plus, so we use the following less elegant code instead.
-           
-           printf("\033*b%dY", (*blankRowsP)); 
+
+           printf("\033*b%dY", (*blankRowsP));
         */
-        for (x = 0; x < count; ++x) 
+        for (x = 0; x < count; ++x)
             printf("\033*b0W");
-        
+
         memset(prevRowBuffer, 0, rowBufferSize);
     }
 }
@@ -494,7 +494,7 @@ printRow(void) {
 
 
 static void
-doPage(FILE *             const ifP, 
+doPage(FILE *             const ifP,
        struct cmdlineInfo const cmdline) {
 
     bit * bitrow;
@@ -525,10 +525,10 @@ doPage(FILE *             const ifP,
         else {
             printBlankRows(blankRows);
             blankRows = 0;
-            
+
             printRow();
         }
-    }    
+    }
     printBlankRows(blankRows);
     blankRows = 0;
 
@@ -563,3 +563,6 @@ main(int argc, char * argv[]) {
 
     return 0;
 }
+
+
+
diff --git a/converter/pbm/pbmtoln03.c b/converter/pbm/pbmtoln03.c
index f7cf53c7..235429cd 100644
--- a/converter/pbm/pbmtoln03.c
+++ b/converter/pbm/pbmtoln03.c
@@ -40,116 +40,130 @@ work.
  */
 
 #include <stdio.h>
-#include "pbm.h"
-
-FILE *input ;
-
-#ifndef print
-#define print(s)        fputs (s, stdout)
-#define fprint(f, s)    fputs (s, f)
-#endif
 
+#include "mallocvar.h"
+#include "pbm.h"
 
-static void 
-output_sixel_record (unsigned char * record, int width) {
 
-   int i, j, k ;
-   unsigned char last_char ;
-   int start_repeat = 0 ;
-   int repeated ;
-   char repeated_str[16] ;
-   char *p ;
 
-   /* Do RLE */
-   last_char = record[0] ;
-   j = 0 ;
+static void
+outputSixelRecord(unsigned char * const record,
+                  unsigned int    const width) {
 
-   /* This will make the following loop complete */
-   record[width] = '\0' ;
+    unsigned int i, j;
+    unsigned char lastChar;
+    int startRepeat;
+    char repeatedStr[16];
 
-   for (i = 1 ; i <= width ; i++) {
+    /* Do RLE */
+    lastChar = record[0];
+    j = 0;
 
-      repeated = i - start_repeat ;
+    /* This will make the following loop complete */
+    record[width] = '\0' ;
 
-      if (record[i] != last_char || repeated >= 32766) {
+    for (i = 1, startRepeat = 0; i <= width; ++i) {
+        unsigned int const repeated = i - startRepeat;
 
-         /* Repeat has ended */
+        if (record[i] != lastChar || repeated >= 32766) {
 
-         if (repeated > 3) {
+            /* Repeat has ended */
 
-            /* Do an encoding */
-            record[j++] = '!' ;
-            sprintf (repeated_str, "%d", i - start_repeat) ;
-            for (p = repeated_str ; *p ; p++)
-               record[j++] = *p ;
-               record[j++] = last_char ; }
+            if (repeated > 3) {
+                /* Do an encoding */
+                char * p;
+                record[j++] = '!' ;
+                sprintf(repeatedStr, "%u", i - startRepeat);
+                for (p = repeatedStr; *p; ++p)
+                    record[j++] = *p;
+                record[j++] = lastChar;
+            } else {
+                unsigned int k;
 
-         else {
-            for (k = 0 ; k < repeated ; k++)
-               record[j++] = last_char ; }
+                for (k = 0; k < repeated; ++k)
+                    record[j++] = lastChar;
+            }
 
-         start_repeat = i ;
-         last_char = record[i] ; }
-      }
+            startRepeat = i ;
+            lastChar = record[i];
+        }
+    }
 
-   fwrite ((char *) record, j, 1, stdout) ;
-   putchar ('-') ;      /* DECGNL (graphics new-line) */
-   putchar ('\n') ;
-   }
+    fwrite((char *) record, j, 1, stdout) ;
+    putchar('-') ;      /* DECGNL (graphics new-line) */
+    putchar('\n') ;
+}
 
 
-static void 
-convert (int width, int height, int format) {
-
-   int i ;
-   unsigned char *sixel ;               /* A row of sixels */
-   int sixel_row ;
-
-   bit *row = pbm_allocrow (width) ;
-
-   sixel = (unsigned char *) malloc (width + 2) ;
-
-   sixel_row = 0 ;
-   while (height--) {
-      pbm_readpbmrow (input, row, width, format) ;
-      switch (sixel_row) {
-         case 0 :
-           for (i = 0 ; i < width ; i++)
-              sixel[i] = row[i] ;
-           break ;
-         case 1 :
-           for (i = 0 ; i < width ; i++)
-              sixel[i] += row[i] << 1 ;
-           break ;
-         case 2 :
-           for (i = 0 ; i < width ; i++)
-              sixel[i] += row[i] << 2 ;
-           break ;
-         case 3 :
-           for (i = 0 ; i < width ; i++)
-              sixel[i] += row[i] << 3 ;
-           break ;
-         case 4 :
-           for (i = 0 ; i < width ; i++)
-              sixel[i] += row[i] << 4 ;
-           break ;
-         case 5 :
-           for (i = 0 ; i < width ; i++)
-              sixel[i] += (row[i] << 5) + 077 ;
-           output_sixel_record (sixel, width) ;
-           break ; }
-      if (sixel_row == 5)
-         sixel_row = 0 ;
-      else
-         sixel_row++ ;
-      }
 
-   if (sixel_row > 0) {
-      /* Incomplete sixel record needs to be output */
-      for (i = 0 ; i < width ; i++)
-         sixel[i] += 077 ;
-      output_sixel_record (sixel, width) ; }
-   }
+static void
+convert(FILE *       const ifP,
+        unsigned int const width,
+        unsigned int const height,
+        unsigned int const format) {
+
+    unsigned char * sixel;  /* A row of sixels */
+    unsigned int sixelRow;
+    bit * bitrow;
+    unsigned int remainingHeight;
+
+    bitrow = pbm_allocrow(width);
+
+    MALLOCARRAY(sixel, width + 2);
+    if (!sixel)
+        pm_error("Unable to allocation %u bytes for a row buffer", width + 2);
+
+    for (remainingHeight = height, sixelRow = 0;
+         remainingHeight > 0;
+         --remainingHeight) {
+
+        unsigned int i;
+
+        pbm_readpbmrow(ifP, bitrow, width, format);
+
+        switch (sixelRow) {
+        case 0 :
+            for (i = 0; i < width; ++i)
+                sixel[i] = bitrow[i] ;
+            break ;
+        case 1 :
+            for (i = 0; i < width; ++i)
+                sixel[i] += bitrow[i] << 1;
+            break ;
+        case 2 :
+            for (i = 0; i < width; ++i)
+                sixel[i] += bitrow[i] << 2;
+            break ;
+        case 3 :
+            for (i = 0; i < width; ++i)
+                sixel[i] += bitrow[i] << 3;
+            break ;
+        case 4 :
+            for (i = 0; i < width; ++i)
+                sixel[i] += bitrow[i] << 4;
+            break ;
+        case 5 :
+            for (i = 0; i < width; ++i)
+                sixel[i] += (bitrow[i] << 5) + 077;
+            outputSixelRecord(sixel, width);
+            break ; }
+        if (sixelRow == 5)
+            sixelRow = 0;
+        else
+            ++sixelRow;
+    }
+
+    if (sixelRow > 0) {
+        /* Incomplete sixel record needs to be output */
+        unsigned int i;
+        for (i = 0; i < width; ++i)
+            sixel[i] += 077;
+        outputSixelRecord(sixel, width);
+    }
+
+    pbm_freerow(bitrow);
+    free(sixel);
+}
 
 
 
@@ -169,6 +183,7 @@ main (int argc, char **argv) {
    const char *opt_bottom_margin = "3400";
    const char *opt_form_length = opt_bottom_margin;
 
+   FILE * ifP;
    int width, height, format ;
 
    pbm_init (&argc_copy, argv_copy) ;
@@ -210,16 +225,16 @@ main (int argc, char **argv) {
    }
 
    if( argn < argc ) {
-      input = pm_openr( argv[argn] );
+      ifP = pm_openr( argv[argn] );
       argn++;
    }
    else
-      input = stdin;
+      ifP = stdin;
 
    if( argn != argc )
       pm_usage(usage);
 
-   pbm_readpbminit (input, &width, &height, &format) ;
+   pbm_readpbminit (ifP, &width, &height, &format) ;
 
 /*
  * In explanation of the sequence below:
@@ -241,10 +256,10 @@ main (int argc, char **argv) {
       opt_form_length);
 
    /* Convert data */
-   convert (width, height, format) ;
+   convert (ifP, width, height, format) ;
 
    /* Terminate sixel data */
-   print ("\033\\\n") ;
+   puts ("\033\\") ;
 
    /* If the program failed, it previously aborted with nonzero completion
       code, via various function calls.
diff --git a/converter/pbm/pbmtomacp.c b/converter/pbm/pbmtomacp.c
index df5cbb0c..e02f5559 100644
--- a/converter/pbm/pbmtomacp.c
+++ b/converter/pbm/pbmtomacp.c
@@ -177,7 +177,7 @@ calculateCropPad(struct CmdlineInfo         const cmdline,
             pm_message("Specified -bottom value %u is beyond edge of "
                        "input image", cmdline.bottom);
 
-            bottom = MIN3(cmdline.bottom, rows - 1, top + MACP_ROWS - 1);
+        bottom = MIN3(cmdline.bottom, rows - 1, top + MACP_ROWS - 1);
     } else
         bottom = MIN(rows - 1, top + MACP_ROWS - 1);
 
@@ -234,7 +234,7 @@ writeMacpRowUnpacked(const bit  * const imageBits,
     char const marginByte = 0x00;  /* White bits for margin */
     unsigned int const rightMarginCharCt =
         MACP_COLCHARS - leftMarginCharCt - imageColCharCt;
-    
+
     unsigned int i;
 
     fputc(MACP_COLCHARS - 1, ofP);
@@ -361,7 +361,7 @@ encodeRowsWithShift(bit *                    const bitrow,
 
     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;
diff --git a/converter/pbm/pbmtomgr.c b/converter/pbm/pbmtomgr.c
index e8e30148..0e529740 100644
--- a/converter/pbm/pbmtomgr.c
+++ b/converter/pbm/pbmtomgr.c
@@ -40,7 +40,7 @@ putinit(unsigned int const rows,
 
 int
 main(int argc,
-     char * argv[]) {
+     const char * argv[]) {
 
     FILE * ifP;
     unsigned char * bitrow;
@@ -50,15 +50,11 @@ main(int argc,
     unsigned int row;
     unsigned int bytesPerRow;
         /* Number of packed bytes (8 columns per byte) in a row. */
-    unsigned int padright;
-        /* Number of columns added to the right of each row to get up to
-           a multiple of 8, i.e. an integral number of packed bytes.
-        */
     const char * inputFileName;
     unsigned int const maxDimension = 4095;
         /* Dimensions are 2 characters of the header -- 12 bits */
 
-    pbm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     if (argc-1 > 1)
         pm_error("Too many arguments (%u).  "
@@ -78,7 +74,6 @@ main(int argc,
     
     bitrow = pbm_allocrow_packed(cols);
     bytesPerRow = pbm_packed_bytes(cols);
-    padright = bytesPerRow * 8 - cols;
 
     putinit(rows, cols);
     
diff --git a/converter/pbm/pbmtonokia.c b/converter/pbm/pbmtonokia.c
index bf3b9e41..73b62b96 100644
--- a/converter/pbm/pbmtonokia.c
+++ b/converter/pbm/pbmtonokia.c
@@ -4,6 +4,7 @@
    Copyright information is at end of file.
 */
 
+#define _DEFAULT_SOURCE /* New name for SVID & BSD source defines */
 #define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
 #define _BSD_SOURCE    /* Make sure strcaseeq() is in nstring.h */
 #include <string.h>
@@ -321,10 +322,8 @@ convertToNol(bit **       const image,
     /* image */
     for (row = 0; row < rows; ++row) {
         unsigned int col;
-        unsigned int p;
-        unsigned int c;
 
-        for (p = 0, c = 0, col = 0; col < cols; ++col) {
+        for (col = 0; col < cols; ++col) {
             char const output = image[row][col] == PBM_BLACK ? '1' : '0';
 
             putc(output, ofP);
@@ -374,10 +373,8 @@ convertToNgg(bit **       const image,
 
     for (row = 0; row < rows; ++row) {
         unsigned int col;
-        unsigned int p;
-        unsigned int c;
 
-        for (p = 0, c = 0, col = 0; col < cols; ++col) {
+        for (col = 0; col < cols; ++col) {
             char const output = image[row][col] == PBM_BLACK ? '1' : '0';
 
             putc(output, ofP);
diff --git a/converter/pbm/pbmtopk.c b/converter/pbm/pbmtopk.c
index 3948ae0d..2f05d449 100644
--- a/converter/pbm/pbmtopk.c
+++ b/converter/pbm/pbmtopk.c
@@ -9,6 +9,7 @@
   https://www.tug.org/TUGboat/tb06-1/tb11gf.pdf
 */
 
+#define _DEFAULT_SOURCE 1  /* New name for SVID & BSD source defines */
 #define _BSD_SOURCE 1      /* Make sure strdup() is in string.h */
 #define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
 
diff --git a/converter/pbm/pbmtoppa/pbm.c b/converter/pbm/pbmtoppa/pbm.c
index 2f8a42b1..ae36e0d2 100644
--- a/converter/pbm/pbmtoppa/pbm.c
+++ b/converter/pbm/pbmtoppa/pbm.c
@@ -11,126 +11,185 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <limits.h>
 
+#include "pm.h"
+#include "nstring.h"
 #include "ppapbm.h"
 
-int make_pbm_stat(pbm_stat* pbm,FILE* fptr)
-{
-  char line[1024];
-
-  pbm->fptr=fptr;
-  pbm->version=none;
-  pbm->current_line=0;
-  pbm->unread = 0;
+int
+make_pbm_stat(pbm_stat * const pbmStatP,
+              FILE *     const ifP) {
+
+    char line[1024];
+    char * rc;
+    int retval;
+
+    pbmStatP->fptr         = ifP;
+    pbmStatP->version      = none;
+    pbmStatP->current_line = 0;
+    pbmStatP->unread       = 0;
+
+    rc = fgets(line, 1024, ifP);
+    if (rc == NULL)
+        retval = 0;
+    else {
+        line[strlen(line)-1] = 0;
+
+        if (streq(line,"P1"))
+            pbmStatP->version=P1;
+        if (streq(line,"P4"))
+            pbmStatP->version=P4;
+
+        if (pbmStatP->version == none) {
+            pm_message("unknown PBM magic '%s'", line);
+            retval = 0;
+        } else {
+            do {
+                char * rc;
+                rc = fgets(line, 1024, ifP);
+                if (rc == NULL)
+                    return 0;
+            } while (line[0] == '#');
+            {
+                int rc;
+                rc = sscanf(line, "%d %d",
+                            &pbmStatP->width, &pbmStatP->height);
+                if (rc != 2)
+                    retval = 0;
+                else {
+                    if (pbmStatP->width < 0) {
+                        pm_message("Image has negative width");
+                        retval = 0;
+                    } else if (pbmStatP->width > INT_MAX/2) {
+                        pm_message("Uncomputeably large width: %d",
+                                   pbmStatP->width);
+                        retval = 0;
+                    } else if (pbmStatP->height < 0) {
+                        pm_message("Image has negative height");
+                        retval = 0;
+                    } else if (pbmStatP->height > INT_MAX/2) {
+                        pm_message("Uncomputeably large height: %d",
+                                   pbmStatP->height);
+                        retval = 0;
+                    } else
+                        retval = 1;
+                }
+            }
+        }
+    }
+    return retval;
+}
 
-  if (fgets (line, 1024, fptr) == NULL)
-    return 0;
-  line[strlen(line)-1] = 0;
 
-  if(!strcmp(line,"P1")) pbm->version=P1;
-  if(!strcmp(line,"P4")) pbm->version=P4;
-  if(pbm->version == none)
-  {
-    fprintf(stderr,"pbm_readheader(): unknown PBM magic '%s'\n",line);
-    return 0;
-  }
 
-  do
-    if (fgets (line, 1024, fptr) == NULL)
-      return 0;
-  while (line[0] == '#');
+static int
+getbytes(FILE *          const ifP,
+         unsigned int    const width,
+         unsigned char * const data) {
+
+    unsigned char mask;
+    unsigned char acc;
+    unsigned char * place;
+    unsigned int num;
+    int retval;
+
+    if (width == 0)
+        retval = 0;
+    else {
+        for (mask = 0x80, acc = 0, num = 0, place = data; num < width; ) {
+            switch (getc(ifP)) {
+            case EOF:
+                return 0;
+            case '1':
+                acc |= mask;
+                /* fall through */
+            case '0':
+                mask >>= 1;
+                ++num;
+                if (mask == 0x00) { /* if (num % 8 == 0) */
+                    *place++ = acc;
+                    acc = 0;
+                    mask = 0x80;
+                }
+            }
+        }
+        if (width % 8 != 0)
+            *place = acc;
+
+        retval = 1;
+    }
+    return retval;
+}
 
-  if (2 != sscanf (line, "%d %d", &pbm->width, &pbm->height))
-    return 0;
 
-  return 1;
-}
 
-static int getbytes(FILE *fptr,int width,unsigned char* data)
-{
-  unsigned char mask,acc,*place;
-  int num;
-
-  if(!width) return 0;
-  for(mask=0x80, acc=0, num=0, place=data; num<width; )
-  {
-    switch(getc(fptr))
-    {
-    case EOF:      
-      return 0;
-    case '1':
-      acc|=mask;
-      /* fall through */
-    case '0':
-      mask>>=1;
-      num++;
-      if(!mask) /* if(num%8 == 0) */
-      {
-	*place++ = acc;
-	acc=0;
-	mask=0x80;
-      }
+int
+pbm_readline(pbm_stat *      const pbmStatP,
+             unsigned char * const data) {
+/*----------------------------------------------------------------------------
+  Read a single line into data which must be at least (pbmStatP->width+7)/8
+  bytes of storage.
+-----------------------------------------------------------------------------*/
+    int retval;
+
+    if (pbmStatP->current_line >= pbmStatP->height)
+        retval = 0;
+    else {
+        if (pbmStatP->unread) {
+            memcpy(data, pbmStatP->revdata, (pbmStatP->width+7)/8);
+            ++pbmStatP->current_line;
+            pbmStatP->unread = 0;
+            free(pbmStatP->revdata);
+            pbmStatP->revdata = NULL;
+            retval = 1;
+        } else {
+            switch (pbmStatP->version) {
+            case P1:
+                if (getbytes(pbmStatP->fptr, pbmStatP->width, data)) {
+                    pbmStatP->current_line++;
+                    retval = 1;
+                } else
+                    retval = 0;
+                break;
+            case P4: {
+                int tmp, tmp2;
+                tmp = (pbmStatP->width+7)/8;
+                tmp2 = fread(data,1,tmp,pbmStatP->fptr);
+                if (tmp2 == tmp) {
+                    ++pbmStatP->current_line;
+                    retval = 1;
+                } else {
+                    pm_message("error reading line data (%d)", tmp2);
+                    retval = 0;
+                }
+            } break;
+
+            default:
+                pm_message("unknown PBM version");
+                retval = 0;
+            }
+        }
     }
-  }
-  if(width%8)
-    *place=acc;
-  return 1;
+    return retval;
 }
 
-/* Reads a single line into data which must be at least (pbm->width+7)/8
-   bytes of storage */
-int pbm_readline(pbm_stat* pbm,unsigned char* data)
-{
-  int tmp,tmp2;
-
-  if(pbm->current_line >= pbm->height) return 0;
-
-  if (pbm->unread)
-    {
-      memcpy (data, pbm->revdata, (pbm->width+7)/8);
-      pbm->current_line++;
-      pbm->unread = 0;
-      free (pbm->revdata);
-      pbm->revdata = NULL;
-      return 1;
-    }
 
-  switch(pbm->version)
-  {
-  case P1:
-    if(getbytes(pbm->fptr,pbm->width,data))
-    {
-      pbm->current_line++;
-      return 1;
-    }
-    return 0;
-
-  case P4:
-    tmp=(pbm->width+7)/8;
-    tmp2=fread(data,1,tmp,pbm->fptr);
-    if(tmp2 == tmp)
-    {
-      pbm->current_line++;
-      return 1;
-    }
-    fprintf(stderr,"pbm_readline(): error reading line data (%d)\n",tmp2);
-    return 0;
 
-  default:
-    fprintf(stderr,"pbm_readline(): unknown PBM version\n");
-    return 0;
-  }
-}
+void
+pbm_unreadline(pbm_stat * const pbmStatP,
+               void *     const data) {
+/*----------------------------------------------------------------------------
+  Push a line back into the buffer; we read too much!
+-----------------------------------------------------------------------------*/
+    /* can store only one line in the unread buffer */
 
-/* push a line back into the buffer; we read too much! */
-void pbm_unreadline (pbm_stat *pbm, void *data)
-{
-  /* can only store one line in the unread buffer */
-  if (pbm->unread)
-    return;
-
-  pbm->unread = 1;
-  pbm->revdata = malloc ((pbm->width+7)/8);
-  memcpy (pbm->revdata, data, (pbm->width+7)/8);
-  pbm->current_line--;
+    if (!pbmStatP->unread) {
+        pbmStatP->unread = 1;
+        pbmStatP->revdata = malloc ((pbmStatP->width+7)/8);
+        memcpy(pbmStatP->revdata, data, (pbmStatP->width+7)/8);
+        --pbmStatP->current_line;
+    }
 }
+
+
diff --git a/converter/pbm/pbmtoppa/pbmtoppa.c b/converter/pbm/pbmtoppa/pbmtoppa.c
index f43c08a8..ff4a599e 100644
--- a/converter/pbm/pbmtoppa/pbmtoppa.c
+++ b/converter/pbm/pbmtoppa/pbmtoppa.c
@@ -4,6 +4,7 @@
  * 2-24-98
  */
 
+#define _DEFAULT_SOURCE /* New name for SVID & BSD source defines */
 #define _BSD_SOURCE
     /* This makes sure strcasecmp() is in string.h */
 #include <stdio.h>
diff --git a/converter/pbm/pbmtox10bm b/converter/pbm/pbmtox10bm
index 9a1a7286..deb3aeab 100644
--- a/converter/pbm/pbmtox10bm
+++ b/converter/pbm/pbmtox10bm
@@ -1,3 +1,27 @@
+#!/bin/sh
+
+##############################################################################
+# This is essentially a Perl program.  We exec the Perl interpreter specifying
+# this same file as the Perl program and use the -x option to cause the Perl
+# interpreter to skip down to the Perl code.  The reason we do this instead of
+# just making /usr/bin/perl the script interpreter (instead of /bin/sh) is
+# that the user may have multiple Perl interpreters and the one he wants to
+# use is properly located in the PATH.  The user's choice of Perl interpreter
+# may be crucial, such as when the user also has a PERL5LIB environment
+# variable and it selects modules that work with only a certain main
+# interpreter program.
+#
+# An alternative some people use is to have /usr/bin/env as the script
+# interpreter.  We don't do that because we think the existence and
+# compatibility of /bin/sh is more reliable.
+#
+# Note that we aren't concerned about efficiency because the user who needs
+# high efficiency can use directly the programs that this program invokes.
+#
+##############################################################################
+
+exec perl -w -x -S -- "$0" "$@"
+
 #! /usr/bin/perl
 
 #============================================================================
@@ -14,6 +38,19 @@ use strict;
 use File::Basename;
 use Cwd 'abs_path';
 
+sub doVersionHack($) {
+    my ($argvR) = @_;
+
+    my $arg1 = $argvR->[0];
+
+    if (defined($arg1) && (($arg1 eq "--version") || ($arg1 eq "-version"))) {
+        my $termStatus = system('pbmtoxbm', '--version');
+        exit($termStatus == 0 ? 0 : 1);
+    }
+}
+
+doVersionHack(\@ARGV);
+
 my $infile;
 
 foreach (@ARGV) {
diff --git a/converter/pbm/pbmtoxbm.c b/converter/pbm/pbmtoxbm.c
index 14c6b85e..ecb72b30 100644
--- a/converter/pbm/pbmtoxbm.c
+++ b/converter/pbm/pbmtoxbm.c
@@ -20,6 +20,7 @@
 
 */
 
+#define _DEFAULT_SOURCE 1  /* New name for SVID & BSD source defines */
 #define _BSD_SOURCE 1      /* Make sure strdup() is in string.h */
 #define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */