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