/*
  pbmtopk, adapted from "pxtopk.c by tomas rokicki" by AJCD 1/8/90
  
  compile with: cc -o pbmtopk pbmtopk.c -lm -lpbm
  */

/*
  Modified by David Fong so as to be compilable by Amiga GCC.

  Line changed from...

    if (sscanf(here,"%s%n",str,&n) != 1))

  to...

    a=sscanf(here,"%s%n",str,&n);
    if (a != 1)

  For some strange reason, the first version ALWAYS fails, even
  if the .opt file line is valid.

  */

/*
  Further modified by David Fong to accept separate x and y resolutions 20-Jan-95

  designunits(p) replaced by xdesignunits(p) and ydesignunits(p)
  resolutions    replaced by xresolution     and yresolution
  hppp           replaced by xhppp           and yhppp

  */

#include <stdio.h>
#include <math.h>
#include <ctype.h>
#include "pbm.h"
#include "libpbm1.c"
#include "libpbm2.c"
#include "libpbm3.c"
#include "libpbm4.c"
#include "libpbm5.c"

#define MAXPKCHAR 256
#define MAXOPTLINE 200
#define MAXWIDTHTAB 256
#define MAXHEIGHTTAB 16
#define MAXDEPTHTAB 16
#define MAXITALICTAB 64
#define MAXPARAMS 30
#define NAMELENGTH 80

#define round(a) ((int)(a+.5))
#define fixword(d) ((int)((double)(d)*1048576))
#define unfixword(f) ((double)(f) / 1048576)
#define fixrange(f) ((f) < 16777216 && (f) > -16777216)
#define xdesignunits(p) ((p)*72.27/(double)xresolution/unfixword(designsize))
#define ydesignunits(p) ((p)*72.27/(double)yresolution/unfixword(designsize))

/* character flags: in order of appearance in option files. */
#define XOFFSET     1
#define YOFFSET     2
#define HORZESC     4
#define VERTESC     8
#define TFMWIDTH   16
#define TFMHEIGHT  32
#define TFMDEPTH   64
#define TFMITALIC 128

typedef int integer ;
typedef char quarterword ;
typedef char boolean ;
typedef quarterword ASCIIcode ;
typedef quarterword eightbits ;
typedef unsigned char byte ;

integer xresolution, yresolution, designsize ;
char *filename[MAXPKCHAR] ;

integer xoffset[MAXPKCHAR] ;
integer yoffset[MAXPKCHAR] ;
integer horzesc[MAXPKCHAR] ;
integer vertesc[MAXPKCHAR] ;

byte tfmindex[MAXPKCHAR] ;
byte hgtindex[MAXPKCHAR] ;
byte depindex[MAXPKCHAR] ;
byte italindex[MAXPKCHAR] ;
byte charflags[MAXPKCHAR] ;

bit **bitmap ;
integer smallestch = MAXPKCHAR ;
integer largestch = -1;
integer emwidth  = 0;
integer checksum ;
char *codingscheme = "GRAPHIC" ;
char *familyname = "PBM" ;

integer widthtab[MAXWIDTHTAB] = {0}; /* TFM widths */
integer numwidth = 1;      /* number of entries in width table */
integer heighttab[MAXHEIGHTTAB]  = {0};
integer numheight = 1;
integer depthtab[MAXDEPTHTAB] = {0};
integer numdepth = 1;
integer italictab[MAXITALICTAB] = {0};
integer numitalic = 1;
integer parameters[MAXPARAMS] = {0};
integer numparam = 0;

static ASCIIcode xord[128] ;
static char xchr[256] = {
   '?', '?', '?', '?', '?', '?', '?', '?',
   '?', '?', '?', '?', '?', '?', '?', '?',
   '?', '?', '?', '?', '?', '?', '?', '?',
   '?', '?', '?', '?', '?', '?', '?', '?',
   ' ', '!', '"', '#', '$', '%', '&', '\'',
   '(', ')', '*', '+', ',', '-', '.', '/',
   '0', '1', '2', '3', '4', '5', '6', '7',
   '8', '9', ':', ';', '<', '=', '>', '?',
   '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
   'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
   'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
   'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
   '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
   'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
   'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
   'x', 'y', 'z', '{', '|', '}', '~', '?' };

static FILE *tfmfile, *pkfile ;
static char tfmname[NAMELENGTH+1], pkname[NAMELENGTH+1] ;
static integer pbmtopk_pkloc = 0 ;
static integer bitweight ;
static integer outputbyte ;
static integer car ;
static integer xhppp, yhppp ;
static integer width ;
static integer height ;

/* checksum not computed at the moment
static integer compute_checksum()
{
     begin
     c0:=bc; c1:=ec; c2:=bc; c3:=ec;
     for c:=bc to ec do if char_wd[c]>0 then
     begin
     temp_width:=memory[char_wd[c]];
     if design_units<>unity then
     temp_width:=round((temp_width/design_units)*1048576.0);
     temp_width:=temp_width + (c+4)*@'20000000; {this should be positive}
     c0:=(c0+c0+temp_width) mod 255;
     c1:=(c1+c1+temp_width) mod 253;
     c2:=(c2+c2+temp_width) mod 251;
     c3:=(c3+c3+temp_width) mod 247;
     end;
     header_bytes[check_sum_loc]:=c0;
     header_bytes[check_sum_loc+1]:=c1;
     header_bytes[check_sum_loc+2]:=c2;
     header_bytes[check_sum_loc+3]:=c3;
     end
}
*/

#define add_tfmwidth(v) (add_tfmtable(widthtab, &numwidth, v, MAXWIDTHTAB,\
                                      "TFM width"))
#define add_tfmheight(v) (add_tfmtable(heighttab, &numheight, v, MAXHEIGHTTAB,\
                                       "TFM height"))
#define add_tfmdepth(v) (add_tfmtable(depthtab, &numdepth, v, MAXDEPTHTAB,\
                                      "TFM depth"))
#define add_tfmitalic(v) (add_tfmtable(italictab, &numitalic, v, MAXITALICTAB,\
                                       "Italic correction"))
static byte
add_tfmtable(table, count, value, max_count, name)
     integer *table, *count, value, max_count;
     char *name;
{
   integer i;
   for (i = 0; i < *count; i++) /* search for value in tfm table */
      if (table[i] == value) return (byte)i;
   if (*count >= max_count)
      pm_error("too many values in %s table", name) ;
   if (!fixrange(value))
      pm_error("%s %f for char %d out of range",
               name, unfixword(value), car);
   table[*count] = value ;
   return (*count)++ ;
}

/* add a suffix to a filename in an allocated space */
static void pbmtopk_add_suffix(name, suffix)
     char *name, *suffix ;
{
   char *slash = rindex(name, '/');
   char *dot = rindex(name, '.');

   if ((dot && slash ? dot < slash : !dot) && strcmp(name, "-"))
      strcat(name, suffix);
}

/* initialize the PK parameters */
static void initialize_pk()
{
   integer i ;
   pm_message("This is PBMtoPK, version 2.4, modified by David Fong 20-Jan-95.") ;
   for (i = 127 ; i <= 255 ; i ++) xchr[i] = '?' ;
   for (i = 0 ; i <= 127 ; i ++) xord[i] = 32 ;
   for (i = 32 ; i < 127 ; i ++) xord[(int)xchr[i]] = i ;
   for (i = 0; i < MAXPKCHAR; i++) {
      filename[i] = NULL;
      charflags[i] = 0;
   }
   designsize = fixword(1.0) ;
}

/* write a single byte to the PK file */
static void pbmtopk_pkbyte(b)
     integer b ;
{
   if (b < 0) b += 256 ;
   putc(b, pkfile) ;
   pbmtopk_pkloc++ ;
}

/* write two bytes to the PK file */
static void pkhalfword(a)
     integer a ;
{
   if (a < 0) a += 65536 ;
   pbmtopk_pkbyte(a >> 8) ;
   pbmtopk_pkbyte(a & 255) ;
}

/* write three bytes to the PK file */
static void pkthreebytes(a)
     integer a ;
{
   pbmtopk_pkbyte((a>>16) & 255) ;
   pbmtopk_pkbyte((a>>8) & 255) ;
   pbmtopk_pkbyte(a & 255) ;
}

/* write four bytes to the PK file */
static void pkword(a)
     integer a ;
{
   pbmtopk_pkbyte((a>>24) & 255) ;
   pbmtopk_pkbyte((a>>16) & 255) ;
   pbmtopk_pkbyte((a>>8) & 255) ;
   pbmtopk_pkbyte(a & 255) ;
}

/* write a nibble to the PK file */
static void pknyb(a)
     integer a ;
{
   if (bitweight == 16) {
      outputbyte = (a<<4) ;
      bitweight = 1 ;
   } else {
      pbmtopk_pkbyte(outputbyte + a) ;
      bitweight = 16 ;
   }
}

/* write preamble to PK file */
static void writepreamble()
{
   integer i ;
   char *comment = "PBMtoPK 2.4 output" ;
   
   pbmtopk_pkbyte(247) ;                                /* PRE command */
   pbmtopk_pkbyte(89) ;                         /* PK file type */
   pbmtopk_pkbyte(strlen(comment)) ;                    /* output comment */
   for (i = 0 ; i < strlen(comment); i++) pbmtopk_pkbyte(xord[(int)comment[i]]) ;
   pkword(designsize) ;                         /* write designsize */
   pkword(checksum) ;           /* write checksum; calculate if possible */
   pkword(xhppp) ;                              /* write H pixels per point */
   pkword(yhppp) ;                              /* write V pixels per point */
}

/* write postamble to PK file, padded to word length */
static void writepostamble()
{
   pbmtopk_pkbyte(245) ;                                /* POST command */
   while (pbmtopk_pkloc % 4)
      pbmtopk_pkbyte(246) ;                             /* pad with no-ops */
   pm_message("%d bytes written to packed file.", pbmtopk_pkloc) ;
}

/* write a byte to the TFM file */
static void tfmbyte(b)
     integer b ;
{
   if (b < 0) b += 256 ;
   putc(b, tfmfile) ;
}

/* write a half word to the TFM file */
static void tfmhalfword(a)
     integer a ;
{
   if (a < 0) a += 65536 ;
   tfmbyte(a >> 8) ;
   tfmbyte(a & 255) ;
}

/* write a word to the TFM file */
static void tfmword(a)
     integer a ;
{
   tfmbyte((a>>24) & 255) ;
   tfmbyte((a>>16) & 255) ;
   tfmbyte((a>>8) & 255) ;
   tfmbyte(a & 255) ;
}

/* write the whole TFM file for the font */
static void writetfmfile()
{
   integer totallength ;
   integer headersize = 17;
   integer i ;
   
   if (largestch - smallestch < 0) {
      largestch = 0;
      smallestch = 1;
   }
   if (numparam < 7) /* set default parameters */
      switch (numparam) {
      case 0: /* slant */
         parameters[numparam++] = 0 ;
      case 1: /* space */
         parameters[numparam++] = fixword(xdesignunits(emwidth/3.0));
      case 2: /* space_stretch */
         parameters[numparam++] = fixword(unfixword(parameters[1])/2.0) ;
      case 3: /* space_shrink */
         parameters[numparam++] = fixword(unfixword(parameters[1])/3.0) ;
      case 4: /* x_height */
         parameters[numparam++] = fixword(0.45);
      case 5: /* quad */
         parameters[numparam++] = fixword(xdesignunits(emwidth)) ;
      case 6: /* extra_space */
         parameters[numparam++] = fixword(unfixword(parameters[1])/3.0) ;
      }
   totallength = 6 + headersize + (largestch+1-smallestch) +
      numwidth + numheight + numdepth + numitalic + numparam ;
   /* lengths */
   tfmhalfword(totallength) ;                   /* write file TFM length */
   tfmhalfword(headersize) ;                    /* write TFM header length */
   tfmhalfword(smallestch) ;                    /* write lowest char index */
   tfmhalfword(largestch) ;                     /* write highest char index */
   tfmhalfword(numwidth) ;                      /* write number of widths */
   tfmhalfword(numheight) ;                     /* write number of heights */
   tfmhalfword(numdepth) ;                      /* write number of depths */
   tfmhalfword(numitalic) ;                     /* write number of italcorrs */
   tfmhalfword(0) ;                             /* lig/kern table */
   tfmhalfword(0) ;                             /* kern table */
   tfmhalfword(0) ;                             /* extensible char table */
   tfmhalfword(numparam) ;                      /* number of fontdimens */
   /* header */
   tfmword(checksum) ;                          /* write checksum */
   tfmword(designsize) ;                        /* write designsize */
   if (strlen(codingscheme) > 39) tfmbyte(39) ; /* write coding scheme len */
   else tfmbyte(strlen(codingscheme)) ;
   for (i = 0; i < 39; i++)                     /* write coding scheme */
      if (*codingscheme) tfmbyte(xord[(int)(*codingscheme++)]) ;
      else tfmbyte(0) ;
   if (strlen(familyname) > 19) tfmbyte(19) ;   /* write family length */
   else tfmbyte(strlen(familyname)) ;
   for (i = 0; i < 19; i++)                     /* write family */
      if (*familyname) tfmbyte(xord[(int)(*familyname++)]) ;
      else tfmbyte(0) ;
   /* char_info */
   for (car = smallestch; car <= largestch; car++)
      if (filename[car]) {                      /* write character info */
         tfmbyte(tfmindex[car]) ;
         tfmbyte((hgtindex[car]<<4) + depindex[car]) ;
         tfmbyte(italindex[car]<<2) ;
         tfmbyte(0) ;
      } else tfmword(0) ;
   /* width table */
   for (i = 0; i < numwidth; i++) tfmword(widthtab[i]) ;
   /* height table */
   for (i = 0; i < numheight; i++) tfmword(heighttab[i]) ;
   /* depth table */
   for (i = 0; i < numdepth; i++) tfmword(depthtab[i]) ;
   /* italic correction table */
   for (i = 0; i < numitalic; i++) tfmword(italictab[i]) ;
   /* no lig_kern, kern, or exten tables */
   /* fontdimen table */
   for (i = 0; i < numparam; i++)
      if (i && !fixrange(parameters[i]))
         pm_error("parameter %d out of range (-p)", i);
      else
         tfmword(parameters[i]) ;
   pm_message("%d bytes written to tfm file.", totallength*4) ;
}

/* read a character from a PBM file */
static void readcharacter()
{
   FILE *fp;
   
   fp = pm_openr(filename[car]);
   bitmap = pbm_readpbm(fp, &width, &height) ;
   pm_close(fp) ;
   
   if ((charflags[car] & HORZESC) == 0) horzesc[car] = width ;
   if ((charflags[car] & VERTESC) == 0) vertesc[car] = 0;
   if ((charflags[car] & XOFFSET) == 0) xoffset[car] = 0;
   if ((charflags[car] & YOFFSET) == 0) yoffset[car] = height-1;
   if ((charflags[car] & TFMWIDTH) == 0)
      tfmindex[car] = add_tfmwidth(fixword(xdesignunits(width)));
   if ((charflags[car] & TFMHEIGHT) == 0)
      hgtindex[car] = add_tfmheight(fixword(ydesignunits(yoffset[car]+1)));
   if ((charflags[car] & TFMDEPTH) == 0)
      depindex[car] = add_tfmdepth(fixword(ydesignunits(height-1-yoffset[car])));
   if ((charflags[car] & TFMITALIC) == 0) italindex[car] = 0;
   
   if (car < smallestch) smallestch = car;
   if (car > largestch) largestch = car;
   if (width > emwidth) emwidth = width ;
}

/* test if two rows of the PBM are the same */
static int equal(row1, row2)
     bit *row1, *row2 ;
{
   integer i ;
   
   for (i = 0; i < width; i++)
      if (row1[i] != row2[i]) return (0) ;
   return(1) ;
}

static void shipcharacter()
{
   integer compsize ;
   integer i, j, k ;
   bit *zerorow, *onesrow ;
   integer *repeatptr, *bitcounts ;
   integer count ;
   integer test ;
   integer curptr, rowptr ;
   integer bitval ;
   integer repeatflag ;
   integer colptr ;
   integer currepeat ;
   integer dynf ;
   integer deriv[14] ;
   integer bcompsize ;
   boolean firston ;
   integer flagbyte ;
   boolean state ;
   boolean on ;
   integer hbit ;
   integer pbit ;
   boolean ron, son ;
   integer rcount, scount ;
   integer ri, si ;
   integer max2 ;
   integer predpkloc ;
   integer buff ;
   
   integer tfwid = widthtab[tfmindex[car]] ;
   integer hesc = horzesc[car] ;
   integer vesc = vertesc[car] ;
   integer xoff = xoffset[car] ;
   integer yoff = yoffset[car] ;
   
   repeatptr =
      (integer *)malloc((unsigned int)((height+1)*sizeof(integer))) ;
   bitcounts =
      (integer *)malloc((unsigned int)((height*width)*sizeof(integer))) ;
   if (repeatptr == NULL || bitcounts == NULL)
      pm_error("out of memory while allocating bit counts");
   zerorow = pbm_allocrow(width) ;              /* initialise plain rows */
   onesrow = pbm_allocrow(width) ;
   for (i = 0 ; i < width ; i++) {
      zerorow[i] = PBM_WHITE ;
      onesrow[i] = PBM_BLACK ;
   }
   for (i=0; i < height; i = k) {               /* set repeat pointers */
      k = i + 1;
      if (!equal(bitmap[i], zerorow) && !equal(bitmap[i], onesrow)) {
         while (k < height && equal(bitmap[i], bitmap[k]))
            k++;
         repeatptr[i] = k - i - 1;
      } else {
         repeatptr[i] = 0;
      }
   }
   repeatptr[height] = 0 ;
   colptr = width - 1 ;
   repeatflag = currepeat = curptr = count = rowptr = 0 ;
   test = PBM_WHITE ;
   do {
      colptr++ ;
      if (colptr == width) {                    /* end of row, get next row */
         colptr = 0 ;
         rowptr = currepeat ;
         if (repeatptr[currepeat] > 0) {
            repeatflag = repeatptr[currepeat] ;
            currepeat += repeatflag ;
            rowptr += repeatflag ;
         }
         currepeat++ ;
      }
      if (rowptr >= height) bitval = -1 ;
      else bitval = bitmap[rowptr][colptr] ;
      if (bitval == test) count++ ;             /* count repeated pixels */
      else {                                    /* end of pixel run */
         bitcounts[curptr++] = count ;
         if (curptr+3 >= height*width)
            pm_error("out of memory while saving character counts");
         count = 1 ;
         test = bitval ;
         if (repeatflag > 0) {
            bitcounts[curptr++] = -repeatflag ;
            repeatflag = 0 ;
         }
      }
   } while (test != -1) ;
   bitcounts[curptr] = 0 ;
   bitcounts[curptr + 1] = 0 ;
   for (i = 1 ; i <= 13 ; i ++) deriv[i] = 0 ;
   i = firston = (bitcounts[0] == 0) ;
   compsize = 0 ;
   while (bitcounts[i] != 0) {                  /* calculate dyn_f */
      j = bitcounts[i] ;
      if (j == -1) compsize++ ;
      else {
         if (j < 0) {
            compsize++ ;
            j = -j ;
         }
         if (j < 209) compsize += 2 ;
         else {
            k = j - 193 ;
            while (k >= 16) {
               k >>= 4 ;
               compsize += 2 ;
            }
            compsize++ ;
         }
         if (j < 14) (deriv[j])-- ;
         else if (j < 209) (deriv[(223 - j) / 15])++ ;
         else {
            k = 16 ;
            while (((k<<4) < j + 3)) k <<= 4 ;
            if (j - k <= 192)
               deriv[(207 - j + k) / 15] += 2 ;
         }
      }
      i++ ;
   }
   bcompsize = compsize ;
   dynf = 0 ;
   for (i = 1 ; i <= 13 ; i ++) {
      compsize += deriv[i] ;
      if (compsize <= bcompsize) {
         bcompsize = compsize ;
         dynf = i ;
      }
   }
   compsize = ((bcompsize + 1)>>1) ;
   if ((compsize > ((height*width+7)>>3)) || (height*width == 0)) {
      compsize = ((height*width+7)>>3) ;
      dynf = 14 ;
   }
   flagbyte = (dynf<<4) ;
   if (firston) flagbyte |= 8 ;
   if (tfwid > 16777215 || tfwid < 0 || hesc < 0 || vesc != 0 ||
       compsize > 196579 || width > 65535 || height > 65535 ||
       xoff > 32767 || yoff > 32767 || xoff < -32768 || yoff < -32768) {
      flagbyte |= 7 ;                           /* long form preamble */
      pbmtopk_pkbyte(flagbyte) ;
      compsize += 28 ;
      pkword(compsize) ;                        /* char packet size */
      pkword(car) ;                             /* character number */
      predpkloc = pbmtopk_pkloc + compsize ;
      pkword(tfwid) ;                           /* TFM width */
      pkword(hesc<<16) ;                        /* horiz escapement */
      pkword(vesc<<16) ;                        /* vert escapement */
      pkword(width) ;                           /* bounding box width */
      pkword(height) ;                          /* bounding box height */
      pkword(xoff) ;                            /* horiz offset */
      pkword(yoff) ;                            /* vert offset */
   } else if (hesc > 255 || width > 255 || height > 255 ||
              xoff > 127 || yoff > 127 || xoff < -128 ||
              yoff < -128 || compsize > 1016) {
      compsize += 13 ;                          /* extended short preamble */
      flagbyte += (compsize>>16) + 4 ;
      pbmtopk_pkbyte(flagbyte) ;
      pkhalfword(compsize & 65535) ;            /* char packet size */
      pbmtopk_pkbyte(car) ;                             /* character number */
      predpkloc = pbmtopk_pkloc + compsize ;
      pkthreebytes(tfwid) ;                     /* TFM width */
      pkhalfword(hesc) ;                        /* horiz escapement */
      pkhalfword(width) ;                       /* bounding box width */
      pkhalfword(height) ;                      /* bounding box height */
      pkhalfword(xoff) ;                        /* horiz offset */
      pkhalfword(yoff) ;                        /* vert offset */
   } else {
      compsize += 8 ;                           /* short form preamble */
      flagbyte = flagbyte + (compsize>>8) ;
      pbmtopk_pkbyte(flagbyte) ;
      pbmtopk_pkbyte(compsize & 255) ;                  /* char packet size */
      pbmtopk_pkbyte(car) ;                             /* character number */
      predpkloc = pbmtopk_pkloc + compsize ;
      pkthreebytes(tfwid) ;                     /* TFM width */
      pbmtopk_pkbyte(hesc) ;                            /* horiz escapement */
      pbmtopk_pkbyte(width) ;                           /* bounding box width */
      pbmtopk_pkbyte(height) ;                          /* bounding box height */
      pbmtopk_pkbyte(xoff) ;                            /* horiz offset */
      pbmtopk_pkbyte(yoff) ;                            /* vert offset */
   }
   if (dynf != 14) {                            /* write packed character */
      bitweight = 16 ;
      max2 = 208 - 15 * dynf ;
      i = firston ;
      while (bitcounts[i] != 0) {
         j = bitcounts[i] ;
         if (j == - 1) pknyb(15) ;
         else {
            if (j < 0) {
               pknyb(14) ;
               j = -j ;
            }
            if (j <= dynf) pknyb(j) ;
            else if (j <= max2) {
               j -= dynf + 1 ;
               pknyb((j >> 4) + dynf + 1) ;
               pknyb((j & 15)) ;
            } else {
               j -= max2 - 15 ;
               k = 16 ;
               while (k <= j) {
                  k <<= 4 ;
                  pknyb(0) ;
               }
               while (k > 1) {
                  k >>= 4 ;
                  pknyb(j / k) ;
                  j = j % k ;
               }
            }
         }
         i++ ;
      }
      if (bitweight != 16) pbmtopk_pkbyte(outputbyte) ;
   } else {                                     /* write bitmap character */
      buff = 0 ;
      pbit = 8 ;
      i = firston ;
      hbit = width ;
      on = ! firston ;
      state = 0 ;
      count = repeatflag = 0 ;
      while ((bitcounts[i] != 0) || state || (count > 0)) {
         if (state) {
            count = rcount ;
            i = ri ;
            on = ron ;
            repeatflag-- ;
         } else {
            rcount = count ;
            ri = i ;
            ron = on ;
         }
         do {
            if (count == 0) {
               if (bitcounts[i] < 0) {
                  if (! state) repeatflag = -bitcounts[i] ;
                  i++ ;
               }
               count = bitcounts[i] ;
               i++ ;
               on = !on ;
            }
            if ((count >= pbit) && (pbit < hbit)) {
               if (on) buff += (1 << pbit) - 1 ;
               pbmtopk_pkbyte(buff) ;
               buff = 0 ;
               hbit -= pbit ;
               count -= pbit ;
               pbit = 8 ;
            } else if ((count < pbit) && (count < hbit)) {
               if (on) buff += (1 << pbit) - (1 << (pbit - count)) ;
               pbit -=  count ;
               hbit -= count ;
               count = 0 ;
            } else {
               if (on) buff += (1 << pbit) - (1 << (pbit - hbit)) ;
               count -= hbit ;
               pbit -= hbit ;
               hbit = width ;
               if (pbit == 0) {
                  pbmtopk_pkbyte(buff) ;
                  buff = 0 ;
                  pbit = 8 ;
               }
            }
         } while (hbit != width) ;
         if (state && (repeatflag == 0)) {
            count = scount ;
            i = si ;
            on = son ;
            state = 0 ;
         } else if (! state && (repeatflag > 0)) {
            scount = count ;
            si = i ;
            son = on ;
            state = 1 ;
         }
      }
      if (pbit != 8) pbmtopk_pkbyte(buff) ;
   }
   if (predpkloc != pbmtopk_pkloc)
      pm_error("bad predicted character length: character %d", car);
   pbm_freerow(zerorow); 
   pbm_freerow(onesrow); 
   free((char *)repeatptr);
   free((char *)bitcounts);
}

/* check that character is in valid range */
static void checkchar()
{
   if (car < 0 || car >= MAXPKCHAR)
      pm_error("character must be in range 0 to %d", MAXPKCHAR-1) ;
}

/* read character information from an option file */
static void optionfile(name)
     char *name ;
{
   FILE *fp ;
   char buffer[MAXOPTLINE] ;
   long a;
   
   fp = pm_openr(name);
   while (!feof(fp)) {
      char *here = buffer;
      
      if (fgets(buffer, MAXOPTLINE, fp) == NULL) break ;
      while (isspace(*here)) here++ ;
      if (*here && *here == '=') {
         if (sscanf(here+1, "%d", &car) != 1)
            pm_error("bad no option file line %s", buffer) ;
      } else if (*here && *here != '%' && *here != '#') {
         char str[NAMELENGTH] ;
         integer i, n;
         
         checkchar() ;
          a=sscanf(here,"%s%n",str,&n);
          if (a != 1)
             pm_error("bad sp option file line %s,%s,%n", buffer, str, a) ;
         filename[car] =
            (char *)malloc((unsigned int)(sizeof(char)*(strlen(str)+1))) ;
         if (filename[car] == NULL)
            pm_error("out of memory allocating filename %s", str);
         strcpy(filename[car], str) ;
         for (i = 1; i < 256; i<<=1) {
            here += n;
            if (sscanf(here, "%s%n", str, &n) != 1) break ;
            if (strcmp(str, "*")) {
               charflags[car] |= i ;
               switch (i) {
               case XOFFSET:
                  xoffset[car] = atoi(str) ;
                  break ;
               case YOFFSET:
                  yoffset[car] = atoi(str) ;
                  break ;
               case HORZESC:
                  horzesc[car] = atoi(str) ;
                  break ;
               case VERTESC:
                  vertesc[car] = atoi(str) ;
                  break ;
               case TFMWIDTH:
                  tfmindex[car] = add_tfmwidth(fixword(atof(str))) ;
                  break ;
               case TFMHEIGHT:
                  hgtindex[car] = add_tfmheight(fixword(atof(str))) ;
                  break ;
               case TFMDEPTH:
                  depindex[car] = add_tfmdepth(fixword(atof(str))) ;
                  break ;
               case TFMITALIC:
                  italindex[car] = add_tfmitalic(fixword(atof(str))) ;
                  break ;
               }
            }
         }
         car++ ;
      }
   }
   pm_close(fp) ;
}

int
main(argc, argv)
     int argc ;
     char *argv[] ;
{
   integer i, hesc, vesc, xoff, yoff, tfwid, tfdep, tfhgt, tfital ;
   byte flags ;
   char *usage = "pkfile[.pk] tfmfile[.tfm] xdpi ydpi [-s designsize]\n\
        [-p num param...] [-C codingscheme ] [-F family] [-c num | <char>]...\n\
   <char> is:\n\
        [-W tfmwidth] [-H tfmheight] [-D tfmdepth] [-I ital_corr] [-h horiz]\n\
        [-v vert] [-x xoffset] [-y yoffset] file\n\
    or:\n\
        -f optfile\n" ;

   pbm_init(&argc, argv);
   initialize_pk() ;
   
   if (--argc < 1) pm_usage(usage) ;
   strcpy(pkname, *++argv) ;
   pbmtopk_add_suffix(pkname, ".pk") ;
   
   if (--argc < 1) pm_usage(usage) ;
   strcpy(tfmname, *++argv) ;
   pbmtopk_add_suffix(tfmname, ".tfm") ;

   /* following few lines changed variable `resolution'
      to `xresolution' */
   
   if (--argc < 1) pm_usage(usage) ;
   xresolution = atoi(*++argv) ;
   if (xresolution < 1 || xresolution > 32767)
      pm_error("unlikely x-resolution %d dpi", xresolution);
  
   /* following lines added by David Fong to allow separate
      x and y resolution.  As a result, the y resolution is a new
      obligatory argument when calling pbmtopk */

   if (--argc < 1) pm_usage(usage) ;
   yresolution = atoi(*++argv) ;
   if (yresolution < 1 || yresolution > 32767)
      pm_error("unlikely y-resolution %d dpi", yresolution);

   car = flags = hesc = vesc = xoff = yoff = tfwid = 0;
   while (++argv, --argc) {
      if (argv[0][0] == '-' && argv[0][1]) {
         char c, *p;
         c = argv[0][1] ;
         if (argv[0][2]) p = *argv + 2 ;        /* set argument pointer */
         else if (++argv, --argc) p = *argv ;
         else pm_usage(usage) ;
         switch (c) {
         case 'C':
            codingscheme = p;
            break ;
         case 'F':
            familyname = p;
            break ;
         case 'c':
            car = atoi(p) ;
            break ;
         case 's':
            designsize = fixword(atof(p));
            if (designsize < 1048576)
               pm_error("design size %f out of range", unfixword(designsize));
         case 'h':
            hesc = atoi(p) ;
            flags |= HORZESC ;
            break ;
         case 'v':
            vesc = atoi(p) ;
            flags |= VERTESC ;
            break ;
         case 'x':
            xoff = atoi(p) ;
            flags |= XOFFSET ;
            break ;
         case 'y':
            yoff = atoi(p) ;
            flags |= YOFFSET ;
            break ;
         case 'W':
            tfwid = fixword(atof(p)) ;
            flags |= TFMWIDTH ;
            break ;
         case 'H':
            tfhgt = fixword(atof(p)) ;
            flags |= TFMHEIGHT ;
            break ;
         case 'D':
            tfdep = fixword(atof(p)) ;
            flags |= TFMDEPTH ;
            break ;
         case 'I':
            tfital = fixword(atof(p)) ;
            flags |= TFMITALIC ;
            break ;
         case 'f':
            optionfile(p) ;
            break ;
         case 'p':
            numparam = atoi(p);
            if (numparam < 1 || numparam > MAXPARAMS)
               pm_error("parameter count %d out of range", numparam);
            for (i=0; i<numparam; i++)
               if (++argv,--argc)
                  parameters[i] = fixword(atof(*argv)) ;
               else
                  pm_error("not enough parameters (-p)");
            break ;
         default:
            pm_usage(usage) ;
         }
      } else  {
         checkchar() ;
         if (flags & TFMWIDTH)
            tfmindex[car] = add_tfmwidth(tfwid);
         if (flags & TFMDEPTH)
            depindex[car] = add_tfmdepth(tfdep);
         if (flags & TFMHEIGHT)
            hgtindex[car] = add_tfmheight(tfhgt);
         if (flags & TFMITALIC)
            italindex[car] = add_tfmitalic(tfital);
         horzesc[car] = hesc ;
         vertesc[car] = vesc ;
         xoffset[car] = xoff ;
         yoffset[car] = yoff ;
         filename[car] = *argv ;
         charflags[car] = flags ;
         car++ ;
         flags = 0;
      }
   }
   /* following two lines changed to allow separate
      x and y resolutions.  variable hppp replaced
      by variables xhppp and yhppp */

   xhppp = round((xresolution<<16) / 72.27) ;
   yhppp = round((yresolution<<16) / 72.27) ;
   pkfile = pm_openw(pkname);
   tfmfile = pm_openw(tfmname);
   writepreamble() ;
   for (car = 0 ; car < MAXPKCHAR ; car++)
      if (filename[car]) {
         readcharacter() ;
         shipcharacter() ;
      }
   writepostamble() ;
   writetfmfile() ;
   pm_close(pkfile) ;
   pm_close(tfmfile) ;
   exit(0);
}

