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