home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / d / dvips549.zip / DVIPS / AFM2TFM.C < prev    next >
C/C++ Source or Header  |  1992-10-14  |  51KB  |  1,791 lines

  1. /*
  2.  *   This program converts AFM files to TeX TFM files, and optionally
  3.  *   to TeX VPL files that retain all kerning and ligature information.
  4.  *   Both files make the characters not normally encoded by TeX available
  5.  *   by character codes greater than 127.
  6.  */
  7.  
  8. /*   (Modified by Don Knuth from Tom Rokicki's pre-VPL version.) */
  9. /*   VM/CMS port by J. Hafner (hafner@almaden.ibm.com), based on
  10.  *   the port by Alessio Guglielmi (guglielmi@ipisnsib.bitnet)
  11.  *   and Marco Prevedelli (prevedelli@ipisnsva.bitnet).
  12.  *   This port is still in test state.  No guarantees.
  13.  *
  14. */
  15.  
  16. #include <stdio.h>
  17. #ifdef SYSV
  18. #include <string.h>
  19. #else
  20. #ifdef VMS
  21. #include <string.h>
  22. #else
  23. #ifdef __THINK__
  24. #include <string.h>
  25. #else
  26. #include <strings.h>
  27. #endif
  28. #endif
  29. #endif
  30. #include <math.h>
  31.  
  32. #ifdef VMCMS
  33. #define interesting lookstr  /* for 8 character truncation conflicts */
  34. #include "dvipscms.h"
  35. extern FILE *cmsfopen() ;
  36. extern char ebcdic2ascii[] ;
  37. #ifdef fopen
  38. #undef fopen
  39. #endif
  40. #define fopen cmsfopen
  41. #endif
  42.  
  43. #ifdef MSDOS
  44. #define WRITEBIN "wb"
  45. #else
  46. #ifdef VMCMS
  47. #define WRITEBIN "wb, lrecl=1024, recfm=f"
  48. #else
  49. #define WRITEBIN "w"
  50. #endif
  51. #endif
  52.  
  53. #ifdef __TURBOC__
  54. #define SMALLMALLOC
  55. #endif
  56.  
  57. struct encoding {
  58.    char *name ;
  59.    char *vec[256] ;
  60. } ;
  61. struct encoding staticencoding = {
  62.   "TeX text",
  63.   {"Gamma", "Delta", "Theta", "Lambda", "Xi", "Pi", "Sigma",
  64.    "Upsilon", "Phi", "Psi", "Omega", "arrowup", "arrowdown", "quotesingle",
  65.    "exclamdown", "questiondown", "dotlessi", "dotlessj", "grave", "acute",
  66.    "caron", "breve", "macron", "ring", "cedilla", "germandbls", "ae", "oe",
  67.    "oslash", "AE", "OE", "Oslash", "space", "exclam", "quotedbl", "numbersign",
  68.    "dollar", "percent", "ampersand", "quoteright", "parenleft", "parenright",
  69.    "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one",
  70.    "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon",
  71.    "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C",
  72.    "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
  73.    "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash",
  74.    "bracketright", "circumflex", "underscore", "quoteleft", "a", "b", "c", "d",
  75.    "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
  76.    "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright",
  77.    "tilde", "dieresis", "", "", "", "", "", "", "", "", "", "", "", "", "",
  78.     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  79.     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  80.     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  81.     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  82.     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  83.     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  84.     "", "", "", "", "", "", "" } } ;
  85. /*
  86.  *   It's easier to put this in static storage and parse it as we go
  87.  *   than to build the structures ourselves.
  88.  */
  89. char *staticligkern[] = {
  90.    "% LIGKERN space l =: lslash ; space L =: Lslash ;",
  91.    "% LIGKERN question quoteleft =: questiondown ;",
  92.    "% LIGKERN exclam quoteleft =: exclamdown ;",
  93.    "% LIGKERN hyphen hyphen =: endash ; endash hyphen =: emdash ;",
  94.    "% LIGKERN quoteleft quoteleft =: quotedblleft ;",
  95.    "% LIGKERN quoteright quoteright =: quotedblright ;",
  96.    "% LIGKERN space {} * ; * {} space ; zero {} * ; * {} zero ;",
  97.    "% LIGKERN one {} * ; * {} one ; two {} * ; * {} two ;",
  98.    "% LIGKERN three {} * ; * {} three ; four {} * ; * {} four ;",
  99.    "% LIGKERN five {} * ; * {} five ; six {} * ; * {} six ;",
  100.    "% LIGKERN seven {} * ; * {} seven ; eight {} * ; * {} eight ;",
  101.    "% LIGKERN nine {} * ; * {} nine ;",
  102.    0 } ;
  103. /*
  104.  *   The above layout corresponds to TeX Typewriter Type and is compatible
  105.  *   with TeX Text because the position of ligatures is immaterial.
  106.  */
  107. struct encoding *outencoding = 0 ;
  108. struct encoding *inencoding = 0 ;
  109. char *outenname, *inenname ;/* the file names for input and output encodings */
  110. int boundarychar = -1 ;     /* the boundary character */
  111. int ignoreligkern ;         /* do we look at ligkern info in the encoding? */
  112. /*
  113.  *   This is what we store Adobe data in.
  114.  */
  115. struct adobeinfo {
  116.    struct adobeinfo *next ;
  117.    int adobenum, texnum, width ;
  118.    char *adobename ;
  119.    int llx, lly, urx, ury ;
  120.    struct lig *ligs ;
  121.    struct kern *kerns ;
  122.    struct pcc *pccs ;
  123.    int wptr, hptr, dptr, iptr ;
  124. } *adobechars, *adobeptrs[256], *texptrs[256],
  125.   *uppercase[256], *lowercase[256] ;
  126. int nexttex[256] ; /* for characters encoded multiple times in output */
  127. /*
  128.  *   These are the eight ligature ops, in VPL terms and in METAFONT terms.
  129.  */
  130. char *vplligops[] = {
  131.    "LIG", "/LIG", "/LIG>", "LIG/", "LIG/>", "/LIG/", "/LIG/>", "/LIG/>>", 0
  132. } ;
  133. char *encligops[] = {
  134.    "=:", "|=:", "|=:>", "=:|", "=:|>", "|=:|", "|=:|>", "|=:|>>", 0
  135. } ;
  136. struct lig {
  137.    struct lig *next ;
  138.    char *succ, *sub ;
  139.    short op, boundleft ;
  140. } ;
  141. struct kern {
  142.    struct kern *next ;
  143.    char *succ ;
  144.    int delta ;
  145. } ;
  146. struct pcc {
  147.    struct pcc *next ;
  148.    char * partname ;
  149.    int xoffset, yoffset ;
  150. } ;
  151.  
  152. FILE *afmin, *vplout, *tfmout ;
  153. char inname[200], outname[200] ; /* names of input and output files */
  154. char buffer[255]; /* input buffer (modified while parsing) */
  155. char obuffer[255] ; /* unmodified copy of input buffer */
  156. char *param ; /* current position in input buffer */
  157. char *fontname = "Unknown" ;
  158. char *codingscheme = "Unspecified" ;
  159. #ifdef VMCMS
  160. char *ebcodingscheme = "Unspecified" ;
  161. #endif
  162. float italicangle = 0.0 ;
  163. char fixedpitch ;
  164. char makevpl ;
  165. int xheight = 400 ;
  166. int fontspace ;
  167. int bc, ec ;
  168. long cksum ;
  169. float efactor = 1.0, slant = 0.0 ;
  170. char *efactorparam, *slantparam ;
  171. double newslant ;
  172. char titlebuf[100] ;
  173.  
  174. void
  175. error(s)
  176. register char *s ;
  177. {
  178.    extern void exit() ;
  179.  
  180.    (void)fprintf(stderr, "%s\n", s) ;
  181.    if (obuffer[0]) {
  182.       (void)fprintf(stderr, "%s\n", obuffer) ;
  183.       while (param > buffer) {
  184.          (void)fprintf(stderr, " ") ;
  185.          param-- ;
  186.       }
  187.       (void)fprintf(stderr, "^\n") ;
  188.    }
  189.    if (*s == '!')
  190.       exit(1) ;
  191. }
  192.  
  193. int
  194. transform(x,y)
  195.    register int x,y ;
  196. {
  197.    register double acc ;
  198.    acc = efactor * x + slant *y ;
  199.    return (int)(acc>=0? acc+0.5 : acc-0.5 ) ;
  200. }
  201.  
  202. int
  203. getline() {
  204.    register char *p ;
  205.    register int c ;
  206.  
  207.    param = buffer ;
  208.    for (p=buffer; (c=getc(afmin)) != EOF && c != '\n';)/* changed 10 to '\n' */
  209.       *p++ = c ;
  210.    *p = 0 ;
  211.    (void)strcpy(obuffer, buffer) ;
  212.    if (p == buffer && c == EOF)
  213.       return(0) ;
  214.    else
  215.       return(1) ;
  216. }
  217.  
  218. char *interesting[] = { "FontName", "ItalicAngle", "IsFixedPitch",
  219.    "XHeight", "C", "KPX", "CC", "EncodingScheme", NULL} ;
  220. #define FontName (0)
  221. #define ItalicAngle (1)
  222. #define IsFixedPitch (2)
  223. #define XHeight (3)
  224. #define C (4)
  225. #define KPX (5)
  226. #define CC (6)
  227. #define EncodingScheme (7)
  228. #define NONE (-1)
  229. int
  230. interest(s)
  231. char *s ;
  232. {
  233.    register char **p ;
  234.    register int n ;
  235.  
  236.    for (p=interesting, n=0; *p; p++, n++)
  237.       if (strcmp(s, *p)==0)
  238.          return(n) ;
  239.    return(NONE) ;
  240. }
  241.  
  242. char *
  243. mymalloc(len)
  244. unsigned long len ;
  245. {
  246.    register char *p ;
  247.    int i ;
  248. #ifndef IBM6000
  249. #ifdef MSDOS
  250.    extern void *malloc() ;
  251. #else
  252.    extern char *malloc() ;
  253. #endif
  254. #endif
  255.  
  256. #ifdef SMALLMALLOC
  257.    if (len > 65500L)
  258.       error("! can't allocate more than 64K!") ;
  259. #endif
  260.    p = malloc((unsigned)len) ;
  261.    if (p==NULL)
  262.       error("! out of memory") ;
  263.    for (i=0; i<len; i++)
  264.       p[i] = 0 ;
  265.    return(p) ;
  266. }
  267.  
  268. char *
  269. newstring(s)
  270. char *s ;
  271. {
  272.    char *q = mymalloc((unsigned long)(strlen(s) + 1)) ;
  273.    (void)strcpy(q, s) ;
  274.    return q ;
  275. }
  276.  
  277. char *
  278. paramnewstring() {
  279.    register char *p, *q ;
  280.  
  281.    p = param ;
  282.    while (*p > ' ')
  283.       p++ ;
  284.    if (*p != 0)
  285.       *p++ = 0 ;
  286.    q = newstring(param) ;
  287.    while (*p && *p <= ' ')
  288.       p++ ;
  289.    param = p ;
  290.    return(q) ;
  291. }
  292.  
  293. char *
  294. paramstring() {
  295.    register char *p, *q ;
  296.  
  297.    p = param ;
  298.    while (*p > ' ')
  299.       p++ ;
  300.    q = param ;
  301.    if (*p != 0)
  302.       *p++ = 0 ;
  303.    while (*p && *p <= ' ')
  304.       p++ ;
  305.    param = p ;
  306.    return(q) ;
  307. }
  308.  
  309. int
  310. paramnum() {
  311.    register char *p ;
  312.    int i ;
  313.  
  314.    p = paramstring() ;
  315.    if (sscanf(p, "%d", &i) != 1)
  316.       error("! integer expected") ;
  317.    return(i) ;
  318. }
  319.  
  320. float
  321. paramfloat() {
  322.    register char *p ;
  323.    float i ;
  324.  
  325.    p = paramstring() ;
  326.    if (sscanf(p, "%f", &i) != 1)
  327.       error("! number expected") ;
  328.    return(i) ;
  329. }
  330.  
  331. struct adobeinfo *
  332. newchar() {
  333.    register struct adobeinfo *ai ;
  334.  
  335.    ai = (struct adobeinfo *)mymalloc((unsigned long)sizeof(struct adobeinfo)) ;
  336.    ai->adobenum = -1 ;
  337.    ai->texnum = -1 ;
  338.    ai->width = -1 ;
  339.    ai->adobename = NULL ;
  340.    ai->llx = -1 ;
  341.    ai->lly = -1 ;
  342.    ai->urx = -1 ;
  343.    ai->ury = -1 ;
  344.    ai->ligs = NULL ;
  345.    ai->kerns = NULL ;
  346.    ai->pccs = NULL ;
  347.    ai->next = adobechars ;
  348.    adobechars = ai ;
  349.    return(ai) ;
  350. }
  351.  
  352. struct kern *
  353. newkern() {
  354.    register struct kern *nk ;
  355.  
  356.    nk = (struct kern *)mymalloc((unsigned long)sizeof(struct kern)) ;
  357.    nk->next = NULL ;
  358.    nk->succ = NULL ;
  359.    nk->delta = 0 ;
  360.    return(nk) ;
  361. }
  362.  
  363. struct pcc *
  364. newpcc() {
  365.    register struct pcc *np ;
  366.  
  367.    np = (struct pcc *)mymalloc((unsigned long)sizeof(struct pcc)) ;
  368.    np->next = NULL ;
  369.    np->partname = NULL ;
  370.    np->xoffset = 0 ;
  371.    np->yoffset = 0 ;
  372.    return(np) ;
  373. }
  374.  
  375. struct lig *
  376. newlig() {
  377.    register struct lig *nl ;
  378.  
  379.    nl = (struct lig *)mymalloc((unsigned long)sizeof(struct lig)) ;
  380.    nl->next = NULL ;
  381.    nl->succ = NULL ;
  382.    nl->sub = NULL ;
  383.    nl->op = 0 ; /* the default =: op */
  384.    nl->boundleft = 0 ;
  385.    return(nl) ;
  386. }
  387.  
  388. void
  389. expect(s)
  390. char *s ;
  391. {
  392.    if (strcmp(paramstring(), s) != 0) {
  393.       (void)fprintf(stderr, "%s expected: ", s) ;
  394.       error("! syntax error") ;
  395.    }
  396. }
  397.  
  398. void
  399. handlechar() { /* an input line beginning with C */
  400.    register struct adobeinfo *ai ;
  401.    register struct lig *nl ;
  402.  
  403.    ai = newchar() ;
  404.    ai->adobenum = paramnum() ;
  405.    expect(";") ;
  406.    expect("WX") ;
  407.    ai->width = transform(paramnum(),0) ;
  408.    if (ai->adobenum >= 0 && ai->adobenum < 256) {
  409.       adobeptrs[ai->adobenum] = ai ;
  410.    }
  411.    expect(";") ;
  412.    expect("N") ;
  413.    ai->adobename = paramnewstring() ;
  414.    expect(";") ;
  415.    expect("B") ;
  416.    ai->llx = paramnum() ;
  417.    ai->lly = paramnum() ;
  418.    ai->llx = transform(ai->llx, ai->lly) ;
  419.    ai->urx = paramnum() ;
  420.    ai->ury = paramnum() ;
  421.    ai->urx = transform(ai->urx, ai->ury) ;
  422. /* We need to avoid negative heights or depths. They break accents in
  423.    math mode, among other things.  */
  424.    if (ai->lly > 0)
  425.       ai->lly = 0 ;
  426.    if (ai->ury < 0)
  427.       ai->ury = 0 ;
  428.    expect(";") ;
  429. /* Now look for ligatures (which aren't present in fixedpitch fonts) */
  430.    while (*param == 'L' && !fixedpitch) {
  431.       expect("L") ;
  432.       nl = newlig() ;
  433.       nl->succ = paramnewstring() ;
  434.       nl->sub = paramnewstring() ;
  435.       nl->next = ai->ligs ;
  436.       ai->ligs = nl ;
  437.       expect(";") ;
  438.    }
  439. }
  440.  
  441. struct adobeinfo *
  442. findadobe(p)
  443. char *p ;
  444. {
  445.    register struct adobeinfo *ai ;
  446.  
  447.    for (ai=adobechars; ai; ai = ai->next)
  448.       if (strcmp(p, ai->adobename)==0)
  449.          return(ai) ;
  450.    return(NULL) ;
  451. }
  452.  
  453. /*
  454.  *   The following comment no longer applies; we rely on the LIGKERN
  455.  *   entries to kill space kerns.  Also, the same applies to numbers.
  456.  *
  457.  * We ignore kerns before and after space characters, because (1) TeX
  458.  * is using the space only for Polish ligatures, and (2) TeX's
  459.  * boundarychar mechanisms are not oriented to kerns (they apply
  460.  * to both spaces and punctuation) so we don't want to use them.
  461.  */
  462. void
  463. handlekern() { /* an input line beginning with KPX */
  464.    register struct adobeinfo *ai ;
  465.    register char *p ;
  466.    register struct kern *nk ;
  467.  
  468.    p = paramstring() ;
  469.    ai = findadobe(p) ;
  470.    if (ai == NULL)
  471.       error("kern char not found") ;
  472.    else {
  473.       nk = newkern() ;
  474.       nk->succ = paramnewstring() ;
  475.       nk->delta = transform(paramnum(),0) ;
  476.       nk->next = ai->kerns ;
  477.       ai->kerns = nk ;
  478.     }
  479. }
  480.  
  481. void
  482. handleconstruct() { /* an input line beginning with CC */
  483.    register struct adobeinfo *ai ;
  484.    register char *p ;
  485.    register struct pcc *np ;
  486.    register int n ;
  487.    struct pcc *npp = NULL;
  488.  
  489.    p = paramstring() ;
  490.    ai = findadobe(p) ;
  491.    if (ai == NULL)
  492.       error("! composite character name not found") ;
  493.    n = paramnum() ;
  494.    expect(";") ;
  495.    while (n--) {
  496.       if (strcmp(paramstring(),"PCC") != 0) return ;
  497.         /* maybe I should expect("PCC") instead, but I'm playing it safe */
  498.       np = newpcc() ;
  499.       np->partname = paramnewstring() ;
  500.       if (findadobe(np->partname)==NULL) return ;
  501.       np->xoffset = paramnum() ;
  502.       np->yoffset = paramnum() ;
  503.       np->xoffset = transform(np->xoffset, np->yoffset) ;
  504.       if (npp) npp->next = np ;
  505.       else ai->pccs = np ;
  506.       npp = np ;
  507.       expect(";") ;
  508.    }
  509. }
  510.  
  511. struct encoding *readencoding() ;
  512.  
  513. void
  514. makeaccentligs() {
  515.    register struct adobeinfo *ai, *aci ;
  516.    register char *p ;
  517.    register struct lig *nl ;
  518.    for (ai=adobechars; ai; ai=ai->next) {
  519.       p = ai->adobename ;
  520.       if (strlen(p)>2)
  521.          if ((aci=findadobe(p+1)) && (aci->adobenum > 127)) {
  522.             nl = newlig() ;
  523.             nl->succ = mymalloc((unsigned long)2) ;
  524.             *(nl->succ + 1) = 0 ;
  525.             *(nl->succ) = *p ;
  526.             nl->sub = ai->adobename ;
  527.             nl->next = aci->ligs ;
  528.             aci->ligs = nl ;
  529.          }
  530.    }
  531. }
  532.  
  533. void
  534. readadobe() {
  535.    struct adobeinfo *ai ;
  536. #ifdef VMCMS
  537.     int i;
  538. #endif
  539.  
  540. /*
  541.  *   We allocate a placeholder boundary char.
  542.  */
  543.    ai = newchar() ;
  544.    ai->adobenum = -1 ;
  545.    ai->adobename = "||" ; /* boundary character name */
  546.    while (getline()) {
  547.       switch(interest(paramstring())) {
  548. case FontName:
  549.          fontname = paramnewstring() ;
  550. #ifdef VMCMS
  551.    i=0;
  552.    while(fontname[i] != '\0') {
  553.       fontname[i]=ebcdic2ascii[toupper(fontname[i])];
  554.       i++;
  555.    };
  556. #endif
  557.          break ;
  558. case EncodingScheme:
  559.          codingscheme = paramnewstring() ;
  560. #ifdef VMCMS
  561.    strcpy(ebcodingscheme, codingscheme);
  562.    i=0;
  563.    while(codingscheme[i] != '\0') {
  564.       codingscheme[i]=ebcdic2ascii[toupper(codingscheme[i])];
  565.       i++;
  566.    }
  567. #endif
  568.          break ;
  569. case ItalicAngle:
  570.          italicangle = paramfloat() ;
  571.          break ;
  572. case IsFixedPitch:
  573.          if (*param == 't' || *param == 'T')
  574.             fixedpitch = 1 ;
  575.          else
  576.             fixedpitch = 0 ;
  577.          break ;
  578. case XHeight:
  579.          xheight = paramnum() ;
  580.          break ;
  581. case C:
  582.          handlechar() ;
  583.          break ;
  584. case KPX:
  585.          handlekern() ;
  586.          break ;
  587. case CC:
  588.          handleconstruct() ;
  589.          break ;
  590. default:
  591.          break ;
  592.       }
  593.    }
  594.    fclose(afmin) ;
  595.    afmin = 0 ;
  596. }
  597. /*
  598.  *   Re-encode the adobe font.  Assumes that the header file will
  599.  *   also contain the appropriate instructions!
  600.  */
  601. void
  602. handlereencoding() {
  603.    if (inenname) {
  604.       int i ;
  605.       struct adobeinfo *ai ;
  606.       char *p ;
  607.  
  608.       ignoreligkern = 1 ;
  609.       inencoding = readencoding(inenname) ;
  610.       for (i=0; i<256; i++)
  611.          if (ai=adobeptrs[i]) {
  612.             ai->adobenum = -1 ;
  613.             adobeptrs[i] = NULL ;
  614.          }
  615.       for (i=0; i<256; i++) {
  616.          p = inencoding->vec[i] ;
  617.          if (p && *p && (ai = findadobe(p))) {
  618.             ai->adobenum = i ;
  619.             adobeptrs[i] = ai ;
  620.          }
  621.       }
  622.       codingscheme = inencoding->name ;
  623.    }
  624.    ignoreligkern = 0 ;
  625.    if (outenname) {
  626.       outencoding = readencoding(outenname) ;
  627.    } else {
  628.       outencoding = readencoding((char *)0) ;
  629.    }
  630. }
  631.  
  632. /*
  633.  *   This routine reverses a list.  We use it because we accumulate the
  634.  *   adobeinfo list in reverse order, but when we go to map the
  635.  *   characters, we would prefer to use the original ordering.  It just
  636.  *   makes more sense.
  637.  */
  638. struct adobeinfo *revlist(p)
  639. struct adobeinfo *p ;
  640. {
  641.    struct adobeinfo *q = 0, *t ;
  642.  
  643.    while (p) {
  644.       t = p->next ;
  645.       p->next = q ;
  646.       q = p ;
  647.       p = t ;
  648.    }
  649.    return (void *)q ;
  650. }
  651.  
  652. void
  653. assignchars() {
  654.    register char **p ;
  655.    register int i, j ;
  656.    register struct adobeinfo *ai ;
  657.    int nextfree = 128 ;
  658.  
  659. /*
  660.  *   First, we assign all those that match perfectly.
  661.  */
  662.    for (i=0, p=outencoding->vec; i<256; i++, p++)
  663.       if ((ai=findadobe(*p)) && (ai->adobenum >= 0 || ai->pccs != NULL)) {
  664.          if (ai->texnum >= 0)
  665.             nexttex[i] = ai->texnum ; /* linked list */
  666.          ai->texnum = i ;
  667.          texptrs[i] = ai ;
  668.       }
  669. /*
  670.  *   Next, we assign all the others, retaining the adobe positions, possibly
  671.  *   multiply assigning characters.
  672.  */
  673.    for (ai=adobechars; ai; ai=ai->next)
  674.       if (ai->adobenum >= 0 && ai->texnum < 0 && texptrs[ai->adobenum]==0) {
  675.          ai->texnum = ai->adobenum ;
  676.          texptrs[ai->adobenum] = ai ;
  677.       }
  678. /*
  679.  *   Finally, we map all remaining characters into free locations beginning
  680.  *   with 128, if we know how to construct those characters.
  681.  */
  682.    adobechars = revlist(adobechars) ;
  683.    for (ai=adobechars; ai; ai=ai->next)
  684.       if (ai->texnum<0 && (ai->adobenum>=0 || ai->pccs !=NULL)) {
  685.          while (texptrs[nextfree]) {
  686.             nextfree=(nextfree+1)&255 ;
  687.             if (nextfree==128) return ; /* all slots full */
  688.          }
  689.          ai->texnum = nextfree ;
  690.          texptrs[nextfree] = ai ;
  691.       }
  692. /*
  693.  *   Now, if any of the characters are encoded multiple times, we want
  694.  *   ai->texnum to be the first one assigned, since that is most likely
  695.  *   to be the most important one.  So we reverse the above lists.
  696.  */
  697.    for (ai=adobechars; ai; ai=ai->next)
  698.       if (ai->texnum >= 0) {
  699.          j = -1 ;
  700.          while (nexttex[ai->texnum] >= 0) {
  701.             i = nexttex[ai->texnum] ;
  702.             nexttex[ai->texnum] = j ;
  703.             j = ai->texnum ;
  704.             ai->texnum = i ;
  705.          }
  706.          nexttex[ai->texnum] = j ;
  707.       }
  708. }
  709.  
  710. void
  711. upmap() { /* Compute uppercase mapping, when making a small caps font */
  712.    register struct adobeinfo *ai, *Ai ;
  713.    register char *p, *q ;
  714.    register struct pcc *np, *nq ;
  715.    int i ;
  716.    char lwr[50] ;
  717.  
  718.    for (Ai=adobechars; Ai; Ai=Ai->next) {
  719.       p = Ai->adobename ;
  720.       if (*p>='A' && *p<='Z') {
  721.          q = lwr ;
  722.          for (; *p; p++)
  723.             *q++ = ((*p>='A' && *p<='Z') ? *p+32 : *p) ;
  724.          *q = 0;
  725.          if (ai=findadobe(lwr)) {
  726.             for (i = ai->texnum; i >= 0; i = nexttex[i])
  727.                uppercase[i] = Ai ;
  728.             for (i = Ai->texnum; i >= 0; i = nexttex[i])
  729.                lowercase[i] = ai ;
  730.          }
  731.       }
  732.    }
  733. /* Note that, contrary to the normal true/false conventions,
  734.  * uppercase[i] is NULL and lowercase[i] is non-NULL when i is the
  735.  * ASCII code of an uppercase letter; and vice versa for lowercase letters */
  736.  
  737.    if (ai=findadobe("germandbls"))
  738.       if (Ai=findadobe("S")) { /* we also construct SS */
  739.          for (i=ai->texnum; i >= 0; i = nexttex[i])
  740.             uppercase[i] = ai ;
  741.          ai->adobenum = -1 ;
  742.          ai->width = Ai->width << 1 ;
  743.          ai->llx = Ai->llx ;
  744.          ai->lly = Ai->lly ;
  745.          ai->urx = Ai->width + Ai->urx ;
  746.          ai->ury = Ai->ury ;
  747.          ai->kerns = Ai->kerns ;
  748.          np = newpcc() ;
  749.          np->partname = "S" ;
  750.          nq = newpcc() ;
  751.          nq->partname = "S" ;
  752.          nq->xoffset = Ai->width ;
  753.          np->next = nq ;
  754.          ai->pccs = np ;
  755.       }
  756.    if ((ai=findadobe("dotlessi")))
  757.       for (i=ai->texnum; i >= 0; i = nexttex[i])
  758.          uppercase[i] = findadobe("I") ;
  759.    if ((ai=findadobe("dotlessj")))
  760.       for (i=ai->texnum; i >= 0; i = nexttex[i])
  761.          uppercase[i] = findadobe("J") ;
  762. }
  763. /* The logic above seems to work well enough, but it leaves useless characters
  764.  * like `fi' and `fl' in the font if they were present initially,
  765.  * and it omits characters like `dotlessj' if they are absent initially */
  766.  
  767. /* Now we turn to computing the TFM file */
  768.  
  769. int lf, lh, nw, nh, nd, ni, nl, nk, ne, np ;
  770.  
  771. void
  772. write16(what)
  773. register short what ;
  774. {
  775.    (void)fputc(what >> 8, tfmout) ;
  776.    (void)fputc(what & 255, tfmout) ;
  777. }
  778.  
  779. void
  780. writearr(p, n)
  781. register long *p ;
  782. register int n ;
  783. {
  784.    while (n) {
  785.       write16((short)(*p >> 16)) ;
  786.       write16((short)(*p & 65535)) ;
  787.       p++ ;
  788.       n-- ;
  789.    }
  790. }
  791.  
  792. void
  793. makebcpl(p, s, n)
  794. register long *p ;
  795. register char *s ;
  796. register int n ;
  797. {
  798.    register long t ;
  799.    register long sc ;
  800.  
  801.    if (strlen(s) < n)
  802.       n = strlen(s) ;
  803.    t = ((long)n) << 24 ;
  804.    sc = 16 ;
  805.    while (n > 0) {
  806.       t |= ((long)(*(unsigned char *)s++)) << sc ;
  807.       sc -= 8 ;
  808.       if (sc < 0) {
  809.          *p++ = t ;
  810.          t = 0 ;
  811.          sc = 24 ;
  812.       }
  813.       n-- ;
  814.    }
  815.    *p++ = t ;
  816. }
  817.  
  818. int source[257] ;
  819. int unsort[257] ;
  820.  
  821. /*
  822.  *   Next we need a routine to reduce the number of distinct dimensions
  823.  *   in a TFM file. Given an array what[0]...what[oldn-1], we want to
  824.  *   group its elements into newn clusters, in such a way that the maximum
  825.  *   difference between elements of a cluster is as small as possible.
  826.  *   Furthermore, what[0]=0, and this value must remain in a cluster by
  827.  *   itself. Data such as `0 4 6 7 9' with newn=3 shows that an iterative
  828.  *   scheme in which 6 is first clustered with 7 will not work. So we
  829.  *   borrow a neat algorithm from METAFONT to find the true optimum.
  830.  *   Memory location what[oldn] is set to 0x7fffffffL for convenience.
  831.  */
  832. long nextd ; /* smallest value that will give a different mincover */
  833. int
  834. mincover(what,d) /* tells how many clusters result, given max difference d */
  835. register long d ;
  836. long *what ;
  837. {
  838.    register int m ;
  839.    register long l ;
  840.    register long *p ;
  841.  
  842.    nextd = 0x7fffffffL ;
  843.    p = what+1 ;
  844.    m = 1 ;
  845.    while (*p<0x7fffffffL) {
  846.       m++ ;
  847.       l = *p ;
  848.       while (*++p <= l+d) ;
  849.       if (*p-l < nextd) nextd = *p-l ;
  850.    }
  851.    return (m) ;
  852. }
  853.  
  854. void
  855. remap(what, oldn, newn)
  856. long *what ;
  857. int oldn, newn ;
  858. {
  859.    register int i, j ;
  860.    register long d, l ;
  861.  
  862.    what[oldn] = 0x7fffffffL ;
  863.    for (i=oldn-1; i>0; i--) {
  864.       d = what[i] ;
  865.       for (j=i; what[j+1]<d; j++) {
  866.          what[j] = what[j+1] ;
  867.          source[j] = source[j+1] ;
  868.       }
  869.       what[j] = d ;
  870.       source[j] = i ;
  871.    } /* Tom, don't let me ever catch you using bubblesort again! -- Don */
  872.  
  873.    i = mincover(what, 0L) ;
  874.    d = nextd ;
  875.    while (mincover(what,d+d)>newn) d += d ;
  876.    while (mincover(what,d)>newn) d = nextd ;
  877.  
  878.    i = 1 ;
  879.    j = 0 ;
  880.    while (i<oldn) {
  881.       j++ ;
  882.       l = what[i] ;
  883.       unsort[source[i]] = j ;
  884.       while (what[++i] <= l+d) {
  885.          unsort[source[i]] = j ;
  886.          if (i-j == oldn-newn) d = 0 ;
  887.       }
  888.       what[j] = (l+what[i-1])/2 ;
  889.    }
  890. }
  891.  
  892. long checksum() {
  893.    int i ;
  894.    long s1 = 0, s2 = 0 ;
  895.    char *p ;
  896.    struct adobeinfo *ai ;
  897.  
  898.    for (i=0; i<256; i++)
  899.       if (ai=adobeptrs[i]) {
  900.          s1 = (s1 << 1) ^ ai->width ;
  901.          for (p=ai->adobename; *p; p++)
  902.             s2 = (s2 * 3) + *p ;
  903.       }
  904.    s1 = (s1 << 1) ^ s2 ;
  905.    return s1 ;
  906. }
  907.  
  908. /*
  909.  *   The next routine simply scales something.
  910.  *   Input is in 1000ths of an em.  Output is in FIXFACTORths of 1000.
  911.  */
  912. #define FIXFACTOR (0x100000L) /* 2^{20}, the unit fixnum */
  913. long
  914. scale(what)
  915. long what ;
  916. {
  917.    return(((what / 1000) << 20) +
  918.           (((what % 1000) << 20) + 500) / 1000) ;
  919. }
  920.  
  921. long *header, *charinfo, *width, *height, *depth, *ligkern, *kern, *tparam,
  922.      *italic ;
  923. long *tfmdata ;
  924.  
  925. void
  926. buildtfm() {
  927.    register int i, j ;
  928.    register struct adobeinfo *ai ;
  929.  
  930.    if (fontspace == 0) {
  931.       if (adobeptrs[32])
  932.          fontspace = adobeptrs[32]->width ;
  933.       else
  934.          fontspace = transform(500, 0) ;
  935.    }
  936.    header = tfmdata ;
  937.    cksum = checksum() ;
  938.    header[0] = cksum ;
  939.    header[1] = 0xa00000 ; /* 10pt design size */
  940.    makebcpl(header+2, codingscheme, 39) ;
  941.    makebcpl(header+12, fontname, 19) ;
  942.    lh = 17 ;
  943.    charinfo = header + lh ;
  944.  
  945.    for (i=0; i<256 && adobeptrs[i]==NULL; i++) ;
  946.    bc = i ;
  947.    for (i=255; i>=0 && adobeptrs[i]==NULL; i--) ;
  948.    ec = i;
  949.    if (ec < bc)
  950.       error("! no Adobe characters") ;
  951.  
  952.    width = charinfo + (ec - bc + 1) ;
  953.    width[0] = 0 ;
  954.    nw++ ;
  955.    for (i=bc; i<=ec; i++)
  956.       if (ai=adobeptrs[i]) {
  957.          width[nw]=ai->width ;
  958.          for (j=1; width[j]!=ai->width; j++) ;
  959.          ai->wptr = j ;
  960.          if (j==nw)
  961.             nw++ ;
  962.       }
  963.    if (nw>256)
  964.       error("! 256 chars with different widths") ;
  965.    depth = width + nw ;
  966.    depth[0] = 0 ;
  967.    nd = 1 ;
  968.    for (i=bc; i<=ec; i++)
  969.       if (ai=adobeptrs[i]) {
  970.          depth[nd] = -ai->lly ;
  971.          for (j=0; depth[j]!=-ai->lly; j++) ;
  972.          ai->dptr = j ;
  973.          if (j==nd)
  974.             nd++ ;
  975.       }
  976.    if (nd > 16) {
  977.       remap(depth, nd, 16) ;
  978.       nd = 16 ;
  979.       for (i=bc; i<=ec; i++)
  980.          if (ai=adobeptrs[i])
  981.             ai->dptr = unsort[ai->dptr] ;
  982.    }
  983.    height = depth + nd ;
  984.    height[0] = 0 ;
  985.    nh = 1 ;
  986.    for (i=bc; i<=ec; i++)
  987.       if (ai=adobeptrs[i]) {
  988.          height[nh]=ai->ury ;
  989.          for (j=0; height[j]!=ai->ury; j++) ;
  990.          ai->hptr = j ;
  991.          if (j==nh)
  992.             nh++ ;
  993.       }
  994.    if (nh > 16) {
  995.       remap(height, nh, 16) ;
  996.       nh = 16 ;
  997.       for (i=bc; i<=ec; i++)
  998.          if (ai=adobeptrs[i])
  999.             ai->hptr = unsort[ai->hptr] ;
  1000.    }
  1001.    italic  = height + nh ;
  1002.    italic[0] = 0 ;
  1003.    ni = 1 ;
  1004.    for (i=bc; i<=ec; i++)
  1005.       if (ai=adobeptrs[i]) {
  1006.          italic[ni] = ai->urx - ai->width ;
  1007.          if (italic[ni]<0)
  1008.             italic[ni] = 0 ;
  1009.          for (j=0; italic[j]!=italic[ni]; j++) ;
  1010.          ai->iptr = j ;
  1011.          if (j==ni)
  1012.             ni++ ;
  1013.       }
  1014.    if (ni > 64) {
  1015.       remap(italic, ni, 64) ;
  1016.       ni = 64 ;
  1017.       for (i=bc; i<=ec; i++)
  1018.          if (ai=adobeptrs[i])
  1019.             ai->iptr = unsort[ai->iptr] ;
  1020.    }
  1021.  
  1022.    for (i=bc; i<=ec; i++)
  1023.       if (ai=adobeptrs[i])
  1024.          charinfo[i-bc] = ((long)(ai->wptr)<<24) +
  1025.                            ((long)(ai->hptr)<<20) +
  1026.                             ((long)(ai->dptr)<<16) +
  1027.                              ((long)(ai->iptr)<<10) ;
  1028.  
  1029.    ligkern = italic + ni ;
  1030.    nl = 0 ; /* ligatures and kerns omitted from raw Adobe font */
  1031.    kern = ligkern + nl ;
  1032.    nk = 0 ;
  1033.  
  1034.    newslant = (double)slant - efactor * tan(italicangle*(3.1415926535/180.0)) ;
  1035.    tparam = kern + nk ;
  1036.    tparam[0] = (long)(FIXFACTOR * newslant + 0.5) ;
  1037.    tparam[1] = scale((long)fontspace) ;
  1038.    tparam[2] = (fixedpitch ? 0 : scale((long)(300*efactor+0.5))) ;
  1039.    tparam[3] = (fixedpitch ? 0 : scale((long)(100*efactor+0.5))) ;
  1040.    tparam[4] = scale((long)xheight) ;
  1041.    tparam[5] = scale((long)(1000*efactor+0.5)) ;
  1042.    np = 6 ;
  1043. }
  1044.  
  1045. void
  1046. writesarr(what, len)
  1047. long *what ;
  1048. int len ;
  1049. {
  1050.    register long *p ;
  1051.    int i ;
  1052.  
  1053.    p = what ;
  1054.    i = len ;
  1055.    while (i) {
  1056.       *p = scale(*p) ;
  1057.       (void)scale(*p) ; /* need this kludge for some compilers */
  1058.       p++ ;
  1059.       i-- ;
  1060.    }
  1061.    writearr(what, len) ;
  1062. }
  1063.  
  1064. void
  1065. writetfm() {
  1066.    lf = 6 + lh + (ec - bc + 1) + nw + nh + nd + ni + nl + nk + ne + np ;
  1067.    write16(lf) ;
  1068.    write16(lh) ;
  1069.    write16(bc) ;
  1070.    write16(ec) ;
  1071.    write16(nw) ;
  1072.    write16(nh) ;
  1073.    write16(nd) ;
  1074.    write16(ni) ;
  1075.    write16(nl) ;
  1076.    write16(nk) ;
  1077.    write16(ne) ;
  1078.    write16(np) ;
  1079.    writearr(header, lh) ;
  1080.    writearr(charinfo, ec-bc+1) ;
  1081.    writesarr(width, nw) ;
  1082.    writesarr(height, nh) ;
  1083.    writesarr(depth, nd) ;
  1084.    writesarr(italic, ni) ;
  1085.    writearr(ligkern, nl) ;
  1086.    writesarr(kern, nk) ;
  1087.    writearr(tparam, np) ;
  1088. }
  1089.  
  1090. /* OK, the TFM file is done! Now for our next trick, the VPL file. */
  1091.  
  1092. /* For TeX we want to compute a character height that works properly
  1093.  * with accents. The following list of accents doesn't need to be complete. */
  1094. /*
  1095.  *   We only do this if the xheight has a reasonable value.
  1096.  *   (>50)
  1097.  */
  1098. char *accents[] = { "acute", "tilde", "caron", "dieresis", NULL} ;
  1099. int
  1100. texheight(ai)
  1101. register struct adobeinfo *ai ;
  1102. {
  1103.    register char **p;
  1104.    register struct adobeinfo *aci, *acci ;
  1105.    if (xheight <= 50 || *(ai->adobename + 1)) return (ai->ury) ;
  1106.                                            /* that was the simple case */
  1107.    for (p=accents; *p; p++)  /* otherwise we look for accented letters */
  1108.       if (aci=findadobe(*p)) {
  1109.          strcpy(buffer,ai->adobename) ;
  1110.          strcat(buffer,*p) ;
  1111.          if (acci=findadobe(buffer)) return (acci->ury - aci->ury + xheight) ;
  1112.       }
  1113.    return (ai->ury) ;
  1114. }
  1115.  
  1116. /* modified tgr to eliminate varargs problems */
  1117.  
  1118. #define vout(s)  fprintf(vplout, s)
  1119. int level ; /* the depth of parenthesis nesting in VPL file being written */
  1120. void vlevout() {
  1121.    register int l = level ;
  1122.    while (l--) vout("   ") ;
  1123. }
  1124. void vlevnlout() {
  1125.    vout("\n") ;
  1126.    vlevout() ;
  1127. }
  1128. #define voutln(str) {fprintf(vplout,"%s\n",str);vlevout();}
  1129. #define voutln2(f,s) {fprintf(vplout,f,s);vlevnlout();}
  1130. #define voutln3(f,a,b) {fprintf(vplout,f,a,b);vlevnlout();}
  1131. #define voutln4(f,a,b,c) {fprintf(vplout,f,a,b,c);vlevnlout();}
  1132. void
  1133. vleft()
  1134. {
  1135.    level++ ;
  1136.    vout("(") ;
  1137. }
  1138.  
  1139. void
  1140. vright()
  1141. {
  1142.    level-- ;
  1143.    voutln(")") ;
  1144. }
  1145.  
  1146. int forceoctal = 0 ;
  1147.  
  1148. char vcharbuf[6] ;
  1149. char *vchar(c)
  1150. int c ;
  1151. {
  1152.    if (forceoctal == 0 &&
  1153.          ((c>='0' && c<='9')||(c>='A' && c<='Z')||(c>='a' && c<='z')))
  1154.       (void) sprintf(vcharbuf,"C %c", c) ;
  1155.    else (void) sprintf(vcharbuf,"O %o", (unsigned)c) ;
  1156.    return (vcharbuf) ;
  1157. }
  1158.  
  1159. void
  1160. writevpl()
  1161. {
  1162.    register int i, j, k ;
  1163.    register struct adobeinfo *ai ;
  1164.    register struct lig *nlig ;
  1165.    register struct kern *nkern ;
  1166.    register struct pcc *npcc ;
  1167.    struct adobeinfo *asucc, *asub, *api ;
  1168.    int xoff, yoff, ht ;
  1169.    char unlabeled ;
  1170.  
  1171.    voutln2("(VTITLE Created by %s)", titlebuf) ;
  1172.    voutln("(COMMENT Please edit that VTITLE if you edit this file)") ;
  1173.    (void)sprintf(obuffer, "TeX-%s%s%s%s", outname,
  1174.       (efactor==1.0? "" : "-E"), (slant==0.0? "" : "-S"),
  1175.                  (makevpl==1? "" : "-CSC")) ;
  1176.    if (strlen(obuffer)>19) { /* too long, will retain first 9 and last 10 */
  1177.       register char *p, *q ;
  1178.       for (p = &obuffer[9], q = &obuffer[strlen(obuffer)-10] ; p<&obuffer[19];
  1179.               p++, q++) *p = *q ;
  1180.       obuffer[19] = '\0' ;
  1181.    }
  1182.    voutln2("(FAMILY %s)" , obuffer) ;
  1183.    {
  1184.       char tbuf[300] ;
  1185.  
  1186.       sprintf(tbuf, "%s + %s", outencoding->name,
  1187. #ifdef VMCMS
  1188.          ebcodingscheme) ;
  1189. #else
  1190.          codingscheme) ;
  1191. #endif
  1192.       if (strlen(tbuf) > 39) {
  1193.          error("Coding scheme too long; shortening to 39 characters.") ;
  1194.          tbuf[39] = 0 ;
  1195.       }
  1196.       voutln2("(CODINGSCHEME %s)", tbuf) ;
  1197.    }
  1198.    voutln("(DESIGNSIZE R 10.0)") ;
  1199.    voutln("(DESIGNUNITS R 1000)") ;
  1200.    voutln("(COMMENT DESIGNSIZE (1 em) IS IN POINTS)") ;
  1201.    voutln("(COMMENT OTHER DIMENSIONS ARE MULTIPLES OF DESIGNSIZE/1000)") ;
  1202.    voutln2("(CHECKSUM O %lo)",cksum ^ 0xffffffff) ;
  1203.    if (boundarychar >= 0)
  1204.       voutln2("(BOUNDARYCHAR O %lo)", (unsigned long)boundarychar) ;
  1205.    vleft() ; voutln("FONTDIMEN") ;
  1206.    if (newslant)
  1207.       voutln2("(SLANT R %f)", newslant) ;
  1208.    voutln2("(SPACE D %d)", fontspace) ;
  1209.    if (! fixedpitch) {
  1210.       voutln2("(STRETCH D %d)", transform(200,0)) ;
  1211.       voutln2("(SHRINK D %d)", transform(100,0)) ;
  1212.    }
  1213.    voutln2("(XHEIGHT D %d)", xheight) ;
  1214.    voutln2("(QUAD D %d)", transform(1000,0)) ;
  1215.    voutln2("(EXTRASPACE D %d)", fixedpitch ? fontspace : transform(111, 0)) ;
  1216.    vright() ;
  1217.    vleft() ; voutln("MAPFONT D 0");
  1218.    voutln2("(FONTNAME %s)", outname) ;
  1219.    voutln2("(FONTCHECKSUM O %lo)", (unsigned long)cksum) ;
  1220.    vright() ;
  1221.    if (makevpl>1) {
  1222.       vleft() ; voutln("MAPFONT D 1");
  1223.       voutln2("(FONTNAME %s)", outname) ;
  1224.       voutln("(FONTAT D 800)") ;
  1225.       voutln2("(FONTCHECKSUM O %lo)", (unsigned long)cksum) ;
  1226.       vright() ;
  1227.    }
  1228.  
  1229.    for (i=0; i<256 && texptrs[i]==NULL; i++) ;
  1230.    bc = i ;
  1231.    for (i=255; i>=0 && texptrs[i]==NULL; i--) ;
  1232.    ec = i;
  1233.  
  1234.    vleft() ; voutln("LIGTABLE") ;
  1235.    ai = findadobe("||") ;
  1236.    unlabeled = 1 ;
  1237.    for (nlig=ai->ligs; nlig; nlig=nlig->next)
  1238.       if (asucc=findadobe(nlig->succ))
  1239.          if (asub=findadobe(nlig->sub))
  1240.             if (asucc->texnum>=0)
  1241.                if (asub->texnum>=0) {
  1242.                   if (unlabeled) {
  1243.                      voutln("(LABEL BOUNDARYCHAR)") ;
  1244.                      unlabeled = 0 ;
  1245.                   }
  1246.                   for (j = asucc->texnum; j >= 0; j = nexttex[j]) {
  1247.                      voutln4("(%s %s O %o)", vplligops[nlig->op],
  1248.                          vchar(j), (unsigned)asub->texnum) ;
  1249.                   }
  1250.                }
  1251.    for (i=bc; i<=ec; i++)
  1252.       if ((ai=texptrs[i]) && ai->texnum == i) {
  1253.          unlabeled = 1 ;
  1254.          if (uppercase[i]==NULL) /* omit ligatures from smallcap lowercase */
  1255.             for (nlig=ai->ligs; nlig; nlig=nlig->next)
  1256.                if (asucc=findadobe(nlig->succ))
  1257.                   if (asub=findadobe(nlig->sub))
  1258.                      if (asucc->texnum>=0)
  1259.                         if (asub->texnum>=0) {
  1260.                            if (unlabeled) {
  1261.                               for (j = ai->texnum; j >= 0; j = nexttex[j])
  1262.                                  voutln2("(LABEL %s)", vchar(j)) ;
  1263.                               unlabeled = 0 ;
  1264.                            }
  1265.                            for (j = asucc->texnum; j >= 0; j = nexttex[j]) {
  1266.                               voutln4("(%s %s O %o)", vplligops[nlig->op],
  1267.                                    vchar(j), (unsigned)asub->texnum) ;
  1268.                               if (nlig->boundleft)
  1269.                                  break ;
  1270.                            }
  1271.                         }
  1272.          for (nkern = (uppercase[i] ? uppercase[i]->kerns : ai->kerns);
  1273.                     nkern; nkern=nkern->next)
  1274.             if (asucc=findadobe(nkern->succ))
  1275.                for (j = asucc->texnum; j >= 0; j = nexttex[j]) {
  1276.                   if (uppercase[j]==NULL) {
  1277.                      if (unlabeled) {
  1278.                         for (k = ai->texnum; k >= 0; k = nexttex[k])
  1279.                            voutln2("(LABEL %s)", vchar(k)) ;
  1280.                         unlabeled = 0 ;
  1281.                      }
  1282.                      if (uppercase[i]) {
  1283.                         if (lowercase[j]) {
  1284.                            for (k=lowercase[j]->texnum; k >= 0; k = nexttex[k])
  1285.                               voutln3("(KRN %s R %.1f)", vchar(k),
  1286.                                     0.8*nkern->delta) ;
  1287.                         } else voutln3("(KRN %s R %.1f)",
  1288.                                  vchar(j), 0.8*nkern->delta) ;
  1289.                      } else {
  1290.                         voutln3("(KRN %s R %d)", vchar(j),
  1291.                                 nkern->delta) ;
  1292.                         if (lowercase[j])
  1293.                            for (k=lowercase[j]->texnum; k >= 0; k = nexttex[k])
  1294.                               voutln3("(KRN %s R %.1f)", vchar(k),
  1295.                                 0.8*nkern->delta) ;
  1296.                      }
  1297.                   }
  1298.                }
  1299.          if (! unlabeled) voutln("(STOP)") ;
  1300.       }
  1301.    vright() ;
  1302.  
  1303.    for (i=bc; i<=ec; i++)
  1304.       if (ai=texptrs[i]) {
  1305.          vleft() ; fprintf(vplout, "CHARACTER %s", vchar(i)) ;
  1306.          if (*vcharbuf=='C') {
  1307.             voutln("") ;
  1308.          } else
  1309.             voutln2(" (comment %s)", ai->adobename) ;
  1310.          if (uppercase[i]) {
  1311.             ai=uppercase[i] ;
  1312.             voutln2("(CHARWD R %.1f)", 0.8 * (ai->width)) ;
  1313.             if (ht=texheight(ai)) voutln2("(CHARHT R %.1f)", 0.8 * ht) ;
  1314.             if (ai->lly) voutln2("(CHARDP R %.1f)", -0.8 * ai->lly) ;
  1315.             if (ai->urx > ai->width)
  1316.                voutln2("(CHARIC R %.1f)", 0.8 * (ai->urx - ai->width)) ;
  1317.          } else {
  1318.             voutln2("(CHARWD R %d)", ai->width) ;
  1319.             if (ht=texheight(ai)) voutln2("(CHARHT R %d)", ht) ;
  1320.             if (ai->lly) voutln2("(CHARDP R %d)", -ai->lly) ;
  1321.             if (ai->urx > ai->width)
  1322.                voutln2("(CHARIC R %d)", ai->urx - ai->width) ;
  1323.          }
  1324.          if (ai->adobenum != i || uppercase[i]) {
  1325.             vleft() ; voutln("MAP") ;
  1326.             if (uppercase[i]) voutln("(SELECTFONT D 1)") ;
  1327.             if (ai->pccs && ai->adobenum < 0) {
  1328.                xoff = 0 ; yoff = 0 ;
  1329.                for (npcc = ai->pccs; npcc; npcc=npcc->next)
  1330.                   if (api=findadobe(npcc->partname))
  1331.                      if (api->texnum>=0) {
  1332.                         if (npcc->xoffset != xoff) {
  1333.                            if (uppercase[i]) {
  1334.                               voutln2("(MOVERIGHT R %.1f)",
  1335.                                       0.8 * (npcc->xoffset - xoff)) ;
  1336.                            } else voutln2("(MOVERIGHT R %d)",
  1337.                                       npcc->xoffset - xoff) ;
  1338.                            xoff = npcc->xoffset ;
  1339.                         }
  1340.                         if (npcc->yoffset != yoff) {
  1341.                            if (uppercase[i]) {
  1342.                               voutln2("(MOVEUP R %.1f)",
  1343.                                       0.8 * (npcc->yoffset - yoff)) ;
  1344.                            } else voutln2("(MOVEUP R %d)",
  1345.                                       npcc->yoffset - yoff) ;
  1346.                            yoff = npcc->yoffset ;
  1347.                         }
  1348.                         voutln2("(SETCHAR O %o)", (unsigned)api->adobenum) ;
  1349.                         xoff += texptrs[api->texnum]->width ;
  1350.                      }
  1351.             } else voutln2("(SETCHAR O %o)", (unsigned)ai->adobenum) ;
  1352.             vright() ;
  1353.          }
  1354.          vright() ;
  1355.       }
  1356.    if (level) error("! I forgot to match the parentheses") ;
  1357. }
  1358.  
  1359. void usage(f)
  1360. FILE *f ;
  1361. {
  1362.    (void)fprintf(f, 
  1363.  "afm2tfm 7.0, Copyright 1990-92 by Radical Eye Software\n") ;
  1364.    (void)fprintf(f,
  1365.  "Usage: afm2tfm foo[.afm] [-O] [-v|-V bar[.vpl]]\n") ;
  1366.    (void)fprintf(f,
  1367.  "                 [-p|-t|-T encodingfile] [foo[.tfm]]\n") ;
  1368. }
  1369.  
  1370. void
  1371. openfiles(argc, argv)
  1372. int argc ;
  1373. char *argv[] ;
  1374. {
  1375.    register int lastext ;
  1376.    register int i ;
  1377.    int arginc ;
  1378.    extern void exit() ;
  1379.  
  1380.    tfmout = (FILE *)NULL ;
  1381.    if (argc == 1) {
  1382.       usage(stdout) ;
  1383.       exit(0) ;
  1384.    }
  1385.  
  1386. #ifdef MSDOS
  1387.    /* Make VPL file identical to that created under Unix */
  1388.    (void)sprintf(titlebuf, "afm2tfm %s", argv[1]) ;
  1389. #else
  1390.    (void)sprintf(titlebuf, "%s %s", argv[0], argv[1]) ;
  1391. #endif
  1392.    (void)strcpy(inname, argv[1]) ;
  1393.    lastext = -1 ;
  1394.    for (i=0; inname[i]; i++)
  1395.       if (inname[i] == '.')
  1396.          lastext = i ;
  1397.       else if (inname[i] == '/' || inname[i] == ':')
  1398.          lastext = -1 ;
  1399.    if (lastext == -1) (void)strcat(inname, ".afm") ;
  1400.  
  1401.    while (argc>2 && *argv[2]=='-') {
  1402.       arginc = 2 ;
  1403.       i = argv[2][1] ;
  1404.       if (i == '/')
  1405.          i = argv[2][2] - 32 ; /* /a ==> A for VMS */
  1406.       switch (i) {
  1407. case 'V': makevpl++ ;
  1408. case 'v': makevpl++ ;
  1409.          (void)strcpy(outname, argv[3]) ;
  1410.          lastext = -1 ;
  1411.          for (i=0; outname[i]; i++)
  1412.             if (outname[i] == '.')
  1413.                lastext = i ;
  1414.             else if (outname[i] == '/' || outname[i] == ':')
  1415.                lastext = -1 ;
  1416.          if (lastext == -1) (void)strcat(outname, ".vpl") ;
  1417. #ifdef VMCMS
  1418.          if ((vplout=fopen(outname, "w"))==NULL)
  1419. #else
  1420.          if ((vplout=fopen(outname, WRITEBIN))==NULL)
  1421. #endif
  1422.             error("! can't open vpl output file") ;
  1423.          break ;
  1424. case 'e': if (sscanf(argv[3], "%f", &efactor)==0 || efactor<0.01)
  1425.             error("! Bad extension factor") ;
  1426.          efactorparam = argv[3] ;
  1427.          break ;
  1428. case 's': if (sscanf(argv[3], "%f", &slant)==0)
  1429.             error("! Bad slant parameter") ;
  1430.          slantparam = argv[3] ;
  1431.          break ;
  1432. case 'P':
  1433. case 'p':
  1434.          inenname = argv[3] ;
  1435.          break ;
  1436. case 'T':
  1437.          inenname = outenname = argv[3] ;
  1438.          break ;
  1439. case 't':
  1440.          outenname = argv[3] ;
  1441.          break ;
  1442. case 'O':
  1443.          forceoctal = 1 ;
  1444.          arginc = 1 ;
  1445.          break ;
  1446. default: (void)fprintf(stderr, "Unknown option %s %s will be ignored.\n",
  1447.                          argv[2], argv[3]) ;
  1448.       }
  1449.       for (i=0; i<arginc; i++) {
  1450.          (void)sprintf(titlebuf + strlen(titlebuf), " %s", argv[2]) ;
  1451.          argv++ ;
  1452.          argc-- ;
  1453.       }
  1454.    }
  1455.  
  1456.    if ((afmin=fopen(inname, "r"))==NULL)
  1457.       error("! can't open afm input file") ;
  1458.  
  1459.    if (argc>3 || (argc==3 && *argv[2]=='-')) {
  1460.       usage(stderr) ;
  1461.       error("! incorrect usage") ;
  1462.    }
  1463.  
  1464.    if (argc == 2) (void)strcpy(outname, inname) ;
  1465.    else (void)strcpy(outname, argv[2]) ;
  1466.  
  1467.    lastext = -1 ;
  1468.    for (i=0; outname[i]; i++)
  1469.       if (outname[i] == '.')
  1470.          lastext = i ;
  1471.       else if (outname[i] == '/' || outname[i] == ':' || outname[i] == '\\')
  1472.          lastext = -1 ;
  1473.    if (argc == 2) {
  1474.       outname[lastext] = 0 ;
  1475.       lastext = -1 ;
  1476.    }
  1477.    if (lastext == -1) {
  1478.       lastext = strlen(outname) ;
  1479.       (void)strcat(outname, ".tfm") ;
  1480.    }
  1481.    if (tfmout == NULL && (tfmout=fopen(outname, WRITEBIN))==NULL)
  1482.       error("! can't open tfm output file") ;
  1483.    outname[lastext] = 0 ;
  1484. /*
  1485.  *   Now we strip off any directory information, so we only use the
  1486.  *   base name in the vf file.  We accept any of /, :, or \ as directory
  1487.  *   delimiters, so none of these are available for use inside the
  1488.  *   base name; this shouldn't be a problem.
  1489.  */
  1490.    for (i=0, lastext=0; outname[i]; i++)
  1491.       if (outname[i] == '/' || outname[i] == ':' || outname[i] == '\\')
  1492.          lastext = i + 1 ;
  1493.    if (lastext)
  1494.       strcpy(outname, outname + lastext) ;
  1495. }
  1496. /*
  1497.  *   Some routines to remove kerns that match certain patterns.
  1498.  */
  1499. struct kern *rmkernmatch(k, s)
  1500. struct kern *k ;
  1501. char *s ;
  1502. {
  1503.    struct kern *nk ;
  1504.  
  1505.    while (k && strcmp(k->succ, s)==0)
  1506.       k = k->next ;
  1507.    if (k) {
  1508.       for (nk = k; nk; nk = nk->next)
  1509.          while (nk->next && strcmp(nk->next->succ, s)==0)
  1510.             nk->next = nk->next->next ;
  1511.    }
  1512.    return k ;
  1513. }
  1514. /*
  1515.  *   Recursive to one level.
  1516.  */
  1517. void rmkern(s1, s2, ai)
  1518. char *s1, *s2 ;
  1519. struct adobeinfo *ai ;
  1520. {
  1521.    if (ai == 0) {
  1522.       if (strcmp(s1, "*") == 0) {
  1523.          for (ai=adobechars; ai; ai = ai->next)
  1524.             rmkern(s1, s2, ai) ;
  1525.          return ;
  1526.       } else {
  1527.          ai = findadobe(s1) ;
  1528.          if (ai == 0)
  1529.             return ;
  1530.       }
  1531.    }
  1532.    if (strcmp(s2, "*")==0)
  1533.       ai->kerns = 0 ; /* drop them on the floor */
  1534.    else
  1535.       ai->kerns = rmkernmatch(ai->kerns, s2) ;
  1536. }
  1537. int sawligkern ;
  1538. /*
  1539.  *   Reads a ligkern line, if this is one.  Assumes the first character
  1540.  *   passed is `%'.
  1541.  */
  1542. void checkligkern(s)
  1543. char *s ;
  1544. {
  1545.    char *oparam = param ;
  1546.    char *mlist[5] ;
  1547.    int n ;
  1548.  
  1549.    s++ ;
  1550.    while (*s && *s <= ' ')
  1551.       s++ ;
  1552.    if (strncmp(s, "LIGKERN", 7)==0) {
  1553.       sawligkern = 1 ;
  1554.       s += 7 ;
  1555.       while (*s && *s <= ' ')
  1556.          s++ ;
  1557.       param = s ;
  1558.       while (*param) {
  1559.          for (n=0; n<5;) {
  1560.             if (*param == 0)
  1561.                break ;
  1562.             mlist[n] = paramstring() ;
  1563.             if (strcmp(mlist[n], ";") == 0)
  1564.                break ;
  1565.             n++ ;
  1566.          }
  1567.          if (n > 4)
  1568.             error("! too many parameters in lig kern data") ;
  1569.          if (n < 3)
  1570.             error("! too few parameters in lig kern data") ;
  1571.          if (n == 3 && strcmp(mlist[1], "{}") == 0) { /* rmkern command */
  1572.             rmkern(mlist[0], mlist[2], (struct adobeinfo *)0) ;
  1573.          } else if (n == 3 && strcmp(mlist[0], "||") == 0 &&
  1574.                               strcmp(mlist[1], "=") == 0) { /* bc command */
  1575.             struct adobeinfo *ai = findadobe("||") ;
  1576.  
  1577.             if (boundarychar != -1)
  1578.                error("! multiple boundary character commands?") ;
  1579.             if (sscanf(mlist[2], "%d", &n) != 1)
  1580.                error("! expected number assignment for boundary char") ;
  1581.             if (n < 0 || n > 255)
  1582.                error("! boundary character number must be 0..255") ;
  1583.             boundarychar = n ;
  1584.             if (ai == 0)
  1585.                error("! internal error: boundary char") ;
  1586.             ai->texnum = n ; /* prime the pump, so to speak, for lig/kerns */
  1587.          } else if (n == 4) {
  1588.             int op = -1 ;
  1589.             struct adobeinfo *ai ;
  1590.  
  1591.             for (n=0; encligops[n]; n++)
  1592.                if (strcmp(mlist[2], encligops[n])==0) {
  1593.                   op = n ;
  1594.                   break ;
  1595.                }
  1596.             if (op < 0)
  1597.                error("! bad ligature op specified") ;
  1598.             if (ai = findadobe(mlist[0])) {
  1599.                struct lig *lig ;
  1600.  
  1601.                if (findadobe(mlist[2]))     /* remove coincident kerns */
  1602.                   rmkern(mlist[0], mlist[1], ai) ;
  1603.                if (strcmp(mlist[3], "||") == 0)
  1604.                   error("! you can't lig to the boundary character!") ;
  1605.                if (! fixedpitch) { /* fixed pitch fonts get *0* ligs */
  1606.                   for (lig=ai->ligs; lig; lig = lig->next)
  1607.                      if (strcmp(lig->succ, mlist[1]) == 0)
  1608.                         break ; /* we'll re-use this structure */
  1609.                   if (lig == 0) {
  1610.                      lig = newlig() ;
  1611.                      lig->succ = newstring(mlist[1]) ;
  1612.                      lig->next = ai->ligs ;
  1613.                      ai->ligs = lig ;
  1614.                   }
  1615.                   lig->sub = newstring(mlist[3]) ;
  1616.                   lig->op = op ;
  1617.                   if (strcmp(mlist[1], "||")==0) {
  1618.                      lig->boundleft = 1 ;
  1619.                      if (strcmp(mlist[0], "||")==0)
  1620.                         error("! you can't lig boundarychar boundarychar!") ;
  1621.                   } else
  1622.                      lig->boundleft = 0 ;
  1623.                }
  1624.             }
  1625.          } else
  1626.             error("! bad form in LIGKERN command") ;
  1627.       }
  1628.    }
  1629.    param = oparam ;
  1630. }
  1631. /*
  1632.  *   Here we get a token from the AFM file.  We parse just as much PostScript
  1633.  *   as we expect to find in an encoding file.  We allow commented lines and
  1634.  *   names like 0, .notdef, _foo_.  We do not allow //abc.
  1635.  */
  1636. char smbuffer[100] ;    /* for tokens */
  1637. char *gettoken() {
  1638.    char *p, *q ;
  1639.  
  1640.    while (1) {
  1641.       while (param == 0 || *param == 0) {
  1642.          if (getline() == 0)
  1643.             error("! premature end in encoding file") ;
  1644.          for (p=buffer; *p; p++)
  1645.             if (*p == '%') {
  1646.                if (ignoreligkern == 0)
  1647.                   checkligkern(p) ;
  1648.                *p = 0 ;
  1649.                break ;
  1650.             }
  1651.       }
  1652.       while (*param && *param <= ' ')
  1653.          param++ ;
  1654.       if (*param) {
  1655.          if (*param == '[' || *param == ']' ||
  1656.              *param == '{' || *param == '}') {
  1657.             smbuffer[0] = *param++ ;
  1658.             smbuffer[1] = 0 ;
  1659.             return smbuffer ;
  1660.          } else if (*param == '/' || *param == '-' || *param == '_' ||
  1661.                     *param == '.' ||
  1662.                     ('0' <= *param && *param <= '9') ||
  1663.                     ('a' <= *param && *param <= 'z') ||
  1664.                     ('A' <= *param && *param <= 'Z')) {
  1665.             smbuffer[0] = *param ;
  1666.             for (p=param+1, q=smbuffer+1;
  1667.                         *p == '-' || *p == '_' || *p == '.' ||
  1668.                         ('0' <= *p && *p <= '9') ||
  1669.                         ('a' <= *p && *p <= 'z') ||
  1670.                         ('A' <= *p && *p <= 'Z'); p++, q++)
  1671.                *q = *p ;
  1672.             *q = 0 ;
  1673.             param = p ;
  1674.             return smbuffer ;
  1675.          }
  1676.       }
  1677.    }
  1678. }
  1679. void getligkerndefaults() {
  1680.    int i ;
  1681.  
  1682.    for (i=0; staticligkern[i]; i++) {
  1683.       strcpy(buffer, staticligkern[i]) ;
  1684.       strcpy(obuffer, staticligkern[i]) ;
  1685.       param = buffer ;
  1686.       checkligkern(buffer) ;
  1687.    }
  1688. }
  1689. /*
  1690.  *   This routine reads in an encoding file, given the name.  It returns
  1691.  *   the final total structure.  It performs a number of consistency checks.
  1692.  */
  1693. struct encoding *readencoding(enc)
  1694. char *enc ;
  1695. {
  1696.    char *p ;
  1697.    int i ;
  1698.    struct encoding *e =
  1699.       (struct encoding *)mymalloc((unsigned long)sizeof(struct encoding)) ;
  1700.  
  1701.    sawligkern = 0 ;
  1702.    if (afmin)
  1703.       error("! oops; internal afmin error") ;
  1704.    if (enc) {
  1705.       afmin = fopen(enc, "r") ;
  1706.       param = 0 ;
  1707.       if (afmin == 0)
  1708.          error("! couldn't open that encoding file") ;
  1709.       p = gettoken() ;
  1710.       if (*p != '/' || p[1] == 0)
  1711.          error("! first token in encoding must be literal encoding name") ;
  1712.       e->name = newstring(p+1) ;
  1713.       p = gettoken() ;
  1714.       if (strcmp(p, "["))
  1715.          error("! second token in encoding must be mark ([) token") ;
  1716.       for (i=0; i<256; i++) {
  1717.          p = gettoken() ;
  1718.          if (*p != '/' || p[1] == 0)
  1719.             error("! tokens 3 to 257 in encoding must be literal names") ;
  1720.          e->vec[i] = newstring(p+1) ;
  1721.       }
  1722.       p = gettoken() ;
  1723.       if (strcmp(p, "]"))
  1724.          error("! token 258 in encoding must be make-array (])") ;
  1725.       while (getline()) {
  1726.          for (p=buffer; *p; p++)
  1727.             if (*p == '%') {
  1728.                if (ignoreligkern == 0)
  1729.                   checkligkern(p) ;
  1730.                *p = 0 ;
  1731.                break ;
  1732.             }
  1733.       }
  1734.       fclose(afmin) ;
  1735.       afmin = 0 ;
  1736.       if (ignoreligkern == 0 && sawligkern == 0)
  1737.          getligkerndefaults() ;
  1738.    } else {
  1739.       e = &staticencoding ;
  1740.       getligkerndefaults() ;
  1741.    }
  1742.    param = 0 ;
  1743.    return e ;
  1744. }
  1745. /*
  1746.  *   This routine prints out the line that needs to be added to psfonts.map.
  1747.  */
  1748. void conspsfonts() {
  1749.    (void)printf("%s %s", outname, fontname) ;
  1750.    if (slantparam || efactorparam || inenname) {
  1751.       (void)printf(" \"") ;
  1752.       if (slantparam)
  1753.          (void)printf(" %s SlantFont", slantparam) ;
  1754.       if (efactorparam)
  1755.          (void)printf(" %s ExtendFont", efactorparam) ;
  1756.       if (inenname)
  1757.          (void)printf(" %s ReEncodeFont", inencoding->name) ;
  1758.       (void)printf(" \"") ;
  1759.       if (inenname)
  1760.          (void)printf(" <%s", inenname) ;
  1761.    }
  1762.    (void)printf("\n") ;
  1763. }
  1764. #ifndef VMS
  1765. void
  1766. #endif
  1767. main(argc, argv)
  1768. int argc ;
  1769. char *argv[] ;
  1770. {
  1771.    int i ;
  1772.    extern void exit() ;
  1773.  
  1774.    for (i=0; i<256; i++)
  1775.       nexttex[i] = -1 ; /* encoding chains have length 0 */
  1776.    tfmdata = (long *)mymalloc((unsigned long)40000L) ;
  1777.    openfiles(argc, argv) ;
  1778.    readadobe() ;
  1779.    handlereencoding() ;
  1780.    buildtfm() ;
  1781.    writetfm() ;
  1782.    conspsfonts() ;
  1783.    if (makevpl) {
  1784.       assignchars() ;
  1785.       if (makevpl>1) upmap() ;
  1786.       writevpl() ;
  1787.    }
  1788.    exit(0) ;
  1789.    /*NOTREACHED*/
  1790. }
  1791.