/*
 *   This program converts AFM files to TeX TFM files, retaining
 *   all kerning and ligature information.  We also make the other
 *   characters not normally encoded by TeX available by character
 *   codes greater than 256.
 */
#include <stdio.h>
#if SYSV || VAXC
#include <string.h>
#else
#include <strings.h>
#endif

#ifdef VAXC
#define GOOD_EXIT_STATUS 1
#define BAD_EXIT_STATUS 44
#else
#define GOOD_EXIT_STATUS 0
#define BAD_EXIT_STATUS 1
#endif

char *text[] = { "Gamma", "Delta", "Theta", "Lambda", "Xi", "Pi", "Sigma",
   "Upsilon", "Phi", "Psi", "Omega", "ff", "fi", "fl", "ffi", "ffl",
   "dotlessi", "dotlessj", "grave", "acute", "caron", "breve", "macron",
   "ring", "cedilla", "germandbls", "ae", "oe", "oslash", "AE", "OE", "Oslash",
   "space", "exclam", "quotedblright", "numbersign", "dollar", "percent",
   "ampersand", "quoteright", "parenleft", "parenright", "asterisk", "plus",
   "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four",
   "five", "six", "seven", "eight", "nine", "colon", "semicolon", "exclamdown",
   "equal", "questiondown", "question", "at", "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", "bracketleft", "quotedblleft", "bracketright",
   "circumflex", "dotaccent", "quoteleft", "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", "endash", "emdash", "hungarumlaut", "tilde", "dieresis"
   } ;
char *type[] = { "Gamma", "Delta", "Theta", "Lambda", "Xi", "Pi", "Sigma",
   "Upsilon", "Phi", "Psi", "Omega", "arrowup", "arrowdown", "quotesingle",
   "exclamdown", "questiondown", "dotlessi", "dotlessj", "grave", "acute",
   "caron", "breve", "macron", "ring", "cedilla", "germandbls", "ae", "oe",
   "oslash", "AE", "OE", "Oslash", "space", "exclam", "quotedbl", "numbersign",
   "dollar", "percent", "ampersand", "quoteright", "parenleft", "parenright",
   "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one",
   "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon",
   "semicolon", "less", "equal", "greater", "question", "at", "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", "bracketleft", "backslash",
   "bracketright", "circumflex", "underscore", "quoteleft", "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", "braceleft", "bar", "braceright",
   "tilde", "dieresis" } ;
/*
 *   We select which of the above to use depending on whether or not
 *   IsFixedPitch is true.
 */
char *interesting[] = { "FontName", "ItalicAngle", "IsFixedPitch",
   "XHeight", "C", "KPX", "CC", NULL} ;
#define FontName (0)
#define ItalicAngle (1)
#define IsFixedPitch (2)
#define XHeight (3)
#define C (4)
#define KPX (5)
#define CC (6)
#define NONE (-1)
/*
 *   This is what we store Adobe data in.
 */
struct adobeinfo {
   struct adobeinfo *next ;
   int adobenum, texnum, width ;
   char *adobename ;
   int llx, lly, urx, ury ;
   struct lig *ligs ;
   struct kern *kerns ;
   int wptr, hptr, dptr, iptr ;
} *adobechars, *texptrs[256] ;
struct lig {
   struct lig *next ;
   char *succ, *sub ;
} ;
struct kern {
   struct kern *next ;
   char *succ ;
   int delta ;
} ;
FILE *afmin, *tfmout ;
char buffer[255], obuffer[255] ;
char *param ;
char adobeknown[256] ;
char *fontname = "Unknown" ;
float italicangle = 0.0 ;
int fixedpitch ;
int smallcaps ;
int xheight = 400 ;
int bc, ec ;

void
error(s)
register char *s ;
{
   (void)fprintf(stderr, "%s\n", s) ;
   if (obuffer[0]) {
      (void)fprintf(stderr, "%s\n", obuffer) ;
      while (param > buffer) {
         (void)fprintf(stderr, " ") ;
         param-- ;
      }
      (void)fprintf(stderr, "^\n") ;
   }
   if (*s == '!')
#ifdef VAXC
      exit(BAD_EXIT_STATUS) ;
#else
      exit(1) ;
#endif
}

int
getline() {
   register char *p ;
   register int c ;

   param = buffer ;
   for (p=buffer; (c=getc(afmin)) != EOF && c != 10;)
      *p++ = c ;
   *p = 0 ;
   (void)strcpy(obuffer, buffer) ;
   if (p == buffer && c == EOF)
      return(0) ;
   else
      return(1) ;
}

int
interest(s)
char *s ;
{
   register char **p ;
   register int n ;

   for (p=interesting, n=0; *p; p++, n++)
      if (strcmp(s, *p)==0)
         return(n) ;
   return(NONE) ;
}

char *
mymalloc(len)
int len ;
{
   register char *p ;
   extern char *malloc() ;

   p = malloc((unsigned)len) ;
   if (p==NULL)
      error("! out of memory") ;
   return(p) ;
}

char *
paramnewstring() {
   register char *p, *q ;

   p = param ;
   while (*p > ' ')
      p++ ;
   q = mymalloc((int)(p-param+1)) ;
   if (*p != 0)
      *p++ = 0 ;
   (void)strcpy(q, param) ;
   while (*p && *p <= ' ')
      p++ ;
   param = p ;
   return(q) ;
}

char *
paramstring() {
   register char *p, *q ;

   p = param ;
   while (*p > ' ')
      p++ ;
   q = param ;
   if (*p != 0)
      *p++ = 0 ;
   while (*p && *p <= ' ')
      p++ ;
   param = p ;
   return(q) ;
}

int
paramnum() {
   register char *p ;
   int i ;

   p = paramstring() ;
   if (sscanf(p, "%d", &i) != 1)
      error("! number expected") ;
   return(i) ;
}

float
paramfloat() {
   register char *p ;
   float i ;

   p = paramstring() ;
   if (sscanf(p, "%f", &i) != 1)
      error("! number expected") ;
   return(i) ;
}

struct adobeinfo *
newchar() {
   register struct adobeinfo *ai ;

   ai = (struct adobeinfo *)mymalloc(sizeof(struct adobeinfo)) ;
   ai->adobenum = -1 ;
   ai->texnum = -1 ;
   ai->width = -1 ;
   ai->adobename = NULL ;
   ai->llx = -1 ;
   ai->lly = -1 ;
   ai->urx = -1 ;
   ai->ury = -1 ;
   ai->ligs = NULL ;
   ai->kerns = NULL ;
   ai->next = adobechars ;
   adobechars = ai ;
   return(ai) ;
}

struct kern *
newkern() {
   register struct kern *nk ;

   nk = (struct kern *)mymalloc(sizeof(struct kern)) ;
   nk->next = NULL ;
   nk->succ = NULL ;
   nk->delta = 0 ;
   return(nk) ;
}

struct lig *
newlig() {
   register struct lig *nl ;

   nl = (struct lig *)mymalloc(sizeof(struct lig)) ;
   nl->next = NULL ;
   nl->succ = NULL ;
   nl->sub = NULL ;
   return(nl) ;
}

void
expect(s)
char *s ;
{
   if (strcmp(paramstring(), s) != 0) {
      (void)fprintf(stderr, "%s expected: ", s) ;
      error("! syntax error") ;
   }
}

void
handlechar() {
   register struct adobeinfo *ai ;
   register struct lig *nl ;

   ai = newchar() ;
   ai->adobenum = paramnum() ;
   if (ai->adobenum >= 0)
      adobeknown[ai->adobenum] = 1 ;
   expect(";") ;
   expect("WX") ;
   ai->width = paramnum() ;
   expect(";") ;
   expect("N") ;
   ai->adobename = paramnewstring() ;
   expect(";") ;
   expect("B") ;
   ai->llx = paramnum() ;
   ai->lly = paramnum() ;
   ai->urx = paramnum() ;
   ai->ury = paramnum() ;
   expect(";") ;
/*
 *   We don't want the `fi' or `fl' ligatures in fixedpitch fonts.
 */
   if (! fixedpitch || strcmp(ai->adobename, "f") != 0) {
      while (*param == 'L') {
         expect("L") ;
         nl = newlig() ;
         nl->succ = paramnewstring() ;
         nl->sub = paramnewstring() ;
         nl->next = ai->ligs ;
         ai->ligs = nl ;
         expect(";") ;
      }
   }
   if (strcmp(ai->adobename, "space")==0) {
      nl = newlig() ;
      nl->succ = "l" ;
      nl->sub = "lslash" ;
      nl->next = ai->ligs ;
      ai->ligs = nl ;
      nl = newlig() ;
      nl->succ = "L" ;
      nl->sub = "Lslash" ;
      nl->next = ai->ligs ;
      ai->ligs = nl ;
   } else if (strcmp(ai->adobename, "question")==0) {
      nl = newlig() ;
      nl->succ = "quoteleft" ;
      nl->sub = "questiondown" ;
      nl->next = ai->ligs ;
      ai->ligs = nl ;
   } else if (strcmp(ai->adobename, "exclam")==0) {
      nl = newlig() ;
      nl->succ = "quoteleft" ;
      nl->sub = "exclamdown" ;
      nl->next = ai->ligs ;
      ai->ligs = nl ;
   } else if (! fixedpitch) {
      if (strcmp(ai->adobename, "hyphen")==0) {
         nl = newlig() ;
         nl->succ = "hyphen" ;
         nl->sub = "endash" ;
         nl->next = ai->ligs ;
         ai->ligs = nl ;
      } else if (strcmp(ai->adobename, "endash")==0) {
         nl = newlig() ;
         nl->succ = "hyphen" ;
         nl->sub = "emdash" ;
         nl->next = ai->ligs ;
         ai->ligs = nl ;
      } else if (strcmp(ai->adobename, "quoteleft")==0) {
         nl = newlig() ;
         nl->succ = "quoteleft" ;
         nl->sub = "quotedblleft" ;
         nl->next = ai->ligs ;
         ai->ligs = nl ;
      } else if (strcmp(ai->adobename, "quoteright")==0) {
         nl = newlig() ;
         nl->succ = "quoteright" ;
         nl->sub = "quotedblright" ;
         nl->next = ai->ligs ;
         ai->ligs = nl ;
      }
   }
}

struct adobeinfo *
findadobe(p)
char *p ;
{
   register struct adobeinfo *ai ;

   for (ai=adobechars; ai; ai = ai->next)
      if (strcmp(p, ai->adobename)==0)
         return(ai) ;
   return(NULL) ;
}

struct adobeinfo *prev ;

struct adobeinfo *
findprev(p)
char *p ;
{
   register struct adobeinfo *ai ;

   for (ai=adobechars; ai; prev = ai, ai = ai->next)
      if (strcmp(p, ai->adobename)==0)
         return(ai) ;
   return(NULL) ;
}

void
handlekpx() {
   register struct adobeinfo *ai ;
   register char *p ;
   register struct kern *nk ;

   p = paramstring() ;
   ai = findadobe(p) ;
   if (ai == NULL)
      error("! kern char not found") ;
   nk = newkern() ;
   nk->succ = paramnewstring() ;
   nk->delta = paramnum() ;
   nk->next = ai->kerns ;
   ai->kerns = nk ;
}

void
blowaway(p)
char *p ;
{
   register struct adobeinfo *ai ;

   ai = findprev(p) ;
   if (ai==NULL)
      error("! composite character not found") ;
   if (ai==adobechars)
      adobechars = ai->next ;
   else
      prev->next = ai->next ;
}

void
readadobe() {
   while (getline()) {
      switch(interest(paramstring())) {
case FontName:
         fontname = paramnewstring() ;
         break ;
case ItalicAngle:
         italicangle = paramfloat() ;
         break ;
case IsFixedPitch:
         if (*param == 't' || *param == 'T')
            fixedpitch = 1 ;
         else
            fixedpitch = 0 ;
         break ;
case XHeight:
         xheight = paramnum() ;
         break ;
case C:
         handlechar() ;
         break ;
case KPX:
         handlekpx() ;
         break ;
case CC:
         blowaway(paramstring()) ;
         break ;
default:
         break ;
      }
   }
}

void
assignchars() {
   char **texencoding ;
   register char **p ;
   register int i ;
   register struct adobeinfo *ai, *Ai ;
   int nextfree = 128 ;

   texencoding = (fixedpitch ? type : text) ;
/*
 *   First, we assign all those that match perfectly.
 */
   for (i=0, p=texencoding; i<128; i++, p++)
      if (ai=findadobe(*p)) {
         ai->texnum = i ;
         texptrs[i] = ai ;
      }
/*
 *   Next, if we are a smallcaps font, we *smash* the lowercase
 *   letters with smaller versions of the uppercase letters.
 */
#define scscale(n) (((n)*4+2)/5)
   if (smallcaps) {
      for (i=97; i<123; i++) {
         ai = texptrs[i] ;
         Ai = texptrs[i-32] ;
         ai->ligs = NULL ;
         ai->kerns = NULL ;
         ai->adobename = "SmallCapsHack" ;
         ai->width = scscale(Ai->width) ;
         ai->llx = scscale(Ai->llx) ;
         ai->lly = scscale(Ai->lly) ;
         ai->urx = scscale(Ai->urx) ;
         ai->ury = scscale(Ai->ury) ;
      }
   }
/*
 *   Next, we assign all those whose adobe positions aren't
 *   assigned.  Note that we might duplicate things here.
 *   We also move any characters that were displaced above to
 *   128 and above, if these positions are free.
 */
   for (ai=adobechars; ai; ai=ai->next)
      if (ai->adobenum >= 0) {
         if (texptrs[ai->adobenum]==NULL) {
            if (ai->texnum == -1)
               ai->texnum = ai->adobenum ;
            texptrs[ai->adobenum] = ai ;
         } else if (adobeknown[nextfree]==0 && ai->texnum == -1) {
            ai->texnum = nextfree++ ;
            texptrs[ai->texnum] = ai ;
         }
       }
/*
 *   Now we calculate `bc' and `ec'.
 */
   for (i=0; i<256 && texptrs[i]==NULL; i++) ;
   bc = i ;
   for (i=255; i>=0 && texptrs[i]==NULL; i--) ;
   ec = i ;
   if (ec < bc)
      error("! no TeX characters") ;
}

int lf, lh, nw, nh, nd, ni, nl, nk, ne, np ;

void
write16(what)
register short what ;
{
   (void)fputc(what >> 8, tfmout) ;
   (void)fputc(what & 255, tfmout) ;
}

void
writearr(p, n)
register long *p ;
register int n ;
{
   while (n) {
      write16((int)(*p >> 16)) ;
      write16((int)(*p & 65535)) ;
      p++ ;
      n-- ;
   }
}

void
makebcpl(p, s, n)
register long *p ;
register char *s ;
register int n ;
{
   register long t ;
   register long sc ;

   if (strlen(s) < n)
      n = strlen(s) ;
   t = ((long)n) << 24 ;
   sc = 16 ;
   while (n > 0) {
      t |= ((long)(*(unsigned char *)s++)) << sc ;
      sc -= 8 ;
      if (sc < 0) {
         *p++ = t ;
         t = 0 ;
         sc = 24 ;
      }
      n-- ;
   }
   *p++ = t ;
}

int remaparr[257] ;
int unsort[257] ;
int delta[256] ;

/*
 *   Here we want to create newn `clusters', where the maximum size of any
 *   cluster is a minimum.  To do this, we repeatedly iterate through the
 *   list, combining elements until we are done.  But first, we sort the
 *   old elements.
 */
void
remap(what, oldn, newn)
long *what ;
int oldn, newn ;
{
   register int i, j ;
   register int best, bestpos ;
   int old ;

   for (i=0; i<oldn; i++) {
      delta[i] = 0 ;
      remaparr[i] = i ;
   }
   for (i=oldn-1; i>0; i--)
      for (j=0; j<i; j++)
         if (what[j] > what[j+1]) {
            best = remaparr[j] ;
            remaparr[j] = remaparr[j+1] ;
            remaparr[j+1] = best ;
            best = what[j] ;
            what[j] = what[j+1] ;
            what[j+1] = best ;
         }
   for (i=0; i<oldn; i++)
      unsort[remaparr[i]] = i ;
   old = oldn ;
   while (old > newn) {
      best = 32767 ;
      for (i=1; i<old-1; i++) {
         j = what[i+1] + delta[i+1] - what[i] ;
         if (j < best) {
            best = j ;
            bestpos = i ;
         }
      }
      delta[bestpos] = best ;
      for (i=0; i<oldn; i++)
         if (unsort[i] > bestpos)
            unsort[i]-- ;
      while (bestpos < old) {
         bestpos++ ;
         delta[bestpos] = delta[bestpos+1] ;
         what[bestpos] = what[bestpos+1] ;
      }
      old-- ;
   }
   for (i=0; i<newn; i++)
      what[i] += delta[i] / 2 ;
}

/*
 *   Scales something.  Input is in 1000ths of an em.  Output is in
 *   FIXFACTORths of 1000.
 */
long
scale(what)
long what ;
{
   return(((what / 1000) << 20) +
          (((what % 1000) << 20) + 500) / 1000) ;
}

long *header, *charinfo, *width, *height, *depth, *ligkern, *kern, *tparam,
     *italic ;
long tfmdata[2048] ;
#define FIXFACTOR (0x100000L)

void
buildtfm() {
   register int i, j, k ;
   register struct adobeinfo *ai ;
   register struct lig *nlig ;
   register struct kern *nkern ;
   struct adobeinfo *succ, *sub ;
   double tan() ;

   header = tfmdata ;
   header[0] = 0 ;
   header[1] = 0xa00000 ;
   if (fixedpitch)
      makebcpl(header+2, "TeX typewriter text", 39) ;
   else
      makebcpl(header+2, "TeX text", 39) ;
   makebcpl(header+12, fontname, 19) ;
   lh = 18 ;
   charinfo = header + lh ;
   width = charinfo + (ec - bc + 1) ;
   width[0] = 0 ;
   nw++ ;
   for (i=bc; i<=ec; i++)
      if (ai=texptrs[i]) {
         ai->wptr = 0 ;
         for (j=1; j<nw; j++)
            if (width[j] == ai->width) {
               ai->wptr = j ;
               break ;
            }
         if (ai->wptr == 0) {
            width[nw] = ai->width ;
            ai->wptr = nw ;
            nw++ ;
         }
      }
   depth = width + nw ;
   depth[0] = 0 ;
   nd = 1 ;
   for (i=bc; i<=ec; i++)
      if (ai=texptrs[i]) {
         ai->dptr = -1 ;
         k = - ai->lly ;
         if (k < 0)
            k = 0 ;
         for (j=0; j<nd; j++)
            if (depth[j] == k) {
               ai->dptr = j ;
               break ;
            }
         if (ai->dptr == -1) {
            depth[nd] = k ;
            ai->dptr = nd ;
            nd++ ;
         }
      }
   if (nd > 16) {
      remap(depth, nd, 16) ;
      nd = 16 ;
      for (i=bc; i<=ec; i++)
         if ((ai=texptrs[i]) && ai->texnum==i)
            ai->dptr = unsort[ai->dptr] ;
   }
   height = depth + nd ;
   height[0] = 0 ;
   nh = 1 ;
   for (i=bc; i<=ec; i++)
      if (ai=texptrs[i]) {
         ai->hptr = -1 ;
         k = ai->ury ;
         if (k < 0)
            k = 0 ;
         for (j=0; j<nh; j++)
            if (height[j] == k) {
               ai->hptr = j ;
               break ;
            }
         if (ai->hptr == -1) {
            height[nh] = k ;
            ai->hptr = nh ;
            nh++ ;
         }
      }
   if (nh > 16) {
      remap(height, nh, 16) ;
      for (i=bc; i<=ec; i++)
         if ((ai=texptrs[i]) && ai->texnum==i)
            ai->hptr = unsort[ai->hptr] ;
      nh = 16 ;
   }
   italic  = height + nh ;
   italic[0] = 0 ;
   ni = 1 ;
   for (i=bc; i<=ec; i++)
      if (ai=texptrs[i]) {
         ai->iptr = -1 ;
         k = ai->urx - ai->width ;
         if (k < 0)
            k = 0 ;
         for (j=0; j<ni; j++)
            if (italic[j] == k) {
               ai->iptr = j ;
               break ;
            }
         if (ai->iptr == -1) {
            italic[ni] = k ;
            ai->iptr = ni ;
            ni++ ;
         }
      }
   if (ni > 64) {
      remap(italic, ni, 64) ;
      for (i=bc; i<=ec; i++)
         if ((ai=texptrs[i]) && ai->texnum==i)
            ai->iptr = unsort[ai->iptr] ;
      ni = 64 ;
   }
   ligkern = italic + ni ;
   kern = ligkern + 300 ;
   for (i=bc; i<=ec; i++) {
      if (ai=texptrs[i]) {
         j = -1 ;
         charinfo[i-bc] = ((long)(ai->wptr) << 24) + ((long)(ai->hptr) << 20) +
                  ((long)(ai->dptr) << 16) + ((long)(ai->iptr) << 10) + nl ;
         for (nlig = ai->ligs; nlig; nlig = nlig->next) {
            succ = findadobe(nlig->succ) ;
            sub = findadobe(nlig->sub) ;
            if (succ && succ->texnum != -1 && sub && sub->texnum != -1) {
               ligkern[nl] = ((long)(succ->texnum) << 16) + sub->texnum ;
               j = nl ;
               nl++ ;
            }
         }
         for (nkern = ai->kerns; nkern; nkern = nkern->next) {
            succ = findadobe(nkern->succ) ;
/*
 *   Note that we don't want to kern number pairs, even if Adobe wants to,
 *   because otherwise our nice tables will break.
 */
            if (succ && succ->texnum != -1 && (i < '0' || i > '9'
                         || succ->texnum < '0' || succ->texnum > '9' )) {
               for (k=0; k<nk; k++)
                  if (kern[k] == nkern->delta)
                     break ;
               if (k >= nk) {
                  kern[nk] = nkern->delta ;
                  nk++ ;
                  if (nk > 255)
                     error("! too many kerns") ;
               }
               ligkern[nl] = ((long)(succ->texnum) << 16) + 32768L + k ;
               j = nl ;
               nl++ ;
            }
         }
         if (j != -1) {
            ligkern[j] |= 0x80000000 ;
            charinfo[i-bc] |= 256 ;
         }
         if (nl > 255)
            error("! Too many lig-kerns") ;
      }
   }
   tparam = kern + nk ;
   ai = findadobe("space") ;
   if (ai == NULL)
      error("! no space character?") ;
   tparam[0] = (long)(FIXFACTOR * - tan(italicangle * (3.1415926535/180.0))) ;
   tparam[1] = scale((long)ai->width) ;
   tparam[2] = (fixedpitch ? 0 : (FIXFACTOR * 3 + 5) / 10) ;
   tparam[3] = (fixedpitch ? 0 : (FIXFACTOR + 5) / 10) ;
   tparam[4] = scale((long)xheight) ;
   tparam[5] = scale((long)1000) ;
   tparam[6] = scale((long)(fixedpitch ? ai->width : (ai->width / 2))) ;
   np = 7 ;
}

void
writesarr(what, len)
long *what ;
int len ;
{
   register long *p ;
   int i ;

   p = what ;
   i = len ;
   while (i) {
      *p = scale(*p) ;
      p++ ;
      i-- ;
   }
   writearr(what, len) ;
}

void
writetfm() {
   lf = 6 + lh + (ec - bc + 1) + nw + nh + nd + ni + nl + nk + ne + np ;
   write16(lf) ;
   write16(lh) ;
   write16(bc) ;
   write16(ec) ;
   write16(nw) ;
   write16(nh) ;
   write16(nd) ;
   write16(ni) ;
   write16(nl) ;
   write16(nk) ;
   write16(ne) ;
   write16(np) ;
   writearr(header, lh) ;            /* done */
   writearr(charinfo, ec-bc+1) ;     /* done */
   writesarr(width, nw) ;            /* done */
   writesarr(height, nh) ;           /* done */
   writesarr(depth, nd) ;            /* done */
   writesarr(italic, ni) ;           /* done */
   writearr(ligkern, nl) ;           /* done */
   writesarr(kern, nk) ;             /* done */
   writearr(tparam, np) ;           /* done */
}

void
openfiles(argc, argv)
int argc ;
char *argv[] ;
{
   char outname[200] ;
   register int lastext = -1 ;
   register int i ;

   if (argc == 1) {
      (void)printf("afm2tfm 0.9, Copyright 1989 by Radical Eye Software\n") ;
#ifdef VAXC
      exit(GOOD_EXIT_STATUS) ;
#else
      exit(0) ;
#endif
   }
   if (strcmp(argv[1], "-c")==0) {
      argv++ ;
      argc-- ;
      smallcaps = 1 ;
   }
   if (argc < 2 || argc > 3)
      error("! Usage: afm2tfm [-c] foo[.afm] [bar[.tfm]]") ;
   (void)strcpy(outname, argv[1]) ;
   for (i=0; outname[i]; i++)
      if (outname[i] == '.')
         lastext = i ;
      else if (outname[i] == '/' || outname[i] == ':')
         lastext = -1 ;
   if (lastext == -1) {
      lastext = strlen(outname) ;
      (void)strcat(outname, ".afm") ;
   }
   if ((afmin=fopen(outname, "r"))==NULL)
      error("! can't open input file") ;
   if (argc == 3) {
      (void)strcpy(outname, argv[2]) ;
      for (i=0; outname[i]; i++)
         if (outname[i] == '.')
            lastext = i ;
         else if (outname[i] == '/' || outname[i] == ':')
            lastext = -1 ;
      if (lastext == -1)
         (void)strcat(outname, ".tfm") ;
   } else {
      (void)strcpy(outname+lastext, ".tfm") ;
   }
   if ((tfmout=fopen(outname, "w"))==NULL)
      error("! can't open output file") ;
}

main(argc, argv)
int argc ;
char *argv[] ;
{
   openfiles(argc, argv) ;
   readadobe() ;
   assignchars() ;
   buildtfm() ;
   writetfm() ;
#ifdef VAXC
   exit(GOOD_EXIT_STATUS) ;
#else
   exit(0) ;
#endif
   /*NOTREACHED*/
}
