Back to index

tetex-bin  3.0
afm2tfm.c
Go to the documentation of this file.
00001 /*
00002  *   This program converts AFM files to TeX TFM files, and optionally
00003  *   to TeX VPL files that retain all kerning and ligature information.
00004  *   Both files make the characters not normally encoded by TeX available
00005  *   by character codes greater than 127.
00006  */
00007 
00008 /*   (Modified by Don Knuth from Tom Rokicki's pre-VPL version.) */
00009 /*   VM/CMS port by J. Hafner (hafner@almaden.ibm.com), based on
00010  *   the port by Alessio Guglielmi (guglielmi@ipisnsib.bitnet)
00011  *   and Marco Prevedelli (prevedelli@ipisnsva.bitnet).
00012  *   This port is still in test state.  No guarantees.
00013  *   11/3/92: more corrections to VM/CMS port. Now it looks correct
00014  *   and will be supported by J. Hafner.
00015  *
00016  */
00017 /*
00018  *   More changes, primarily from Karl Berry, enough for a new version
00019  *   number to 8.0; 1 December 1996.  Note that this version computes
00020  *   checksums differently (more intelligently).
00021  */
00022 
00023 #ifdef KPATHSEA
00024 #include "config.h"
00025 #include <kpathsea/c-ctype.h>
00026 #include <kpathsea/progname.h>
00027 #include <math.h>
00028 #else /* ! KPATHSEA */
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <ctype.h>
00032 #if defined(SYSV) || defined(VMS) || defined(__THINK__) || defined(MSDOS) || defined(OS2) || defined(ATARIST) || defined(WIN32)
00033 #include <string.h>
00034 #else
00035 #include <strings.h>
00036 #endif
00037 #include <math.h>
00038 #ifdef ATARIST
00039 #include <float.h>
00040 #endif
00041 #endif /* KPATHSEA */
00042 
00043 /* JLH: added these to make the code easier to read and remove some
00044    ascii<->ebcdic dependencies */
00045 #define ASCII_A 65
00046 #define ASCII_Z 90
00047 #define ASCII_a 97
00048 #define ASCII_z 122
00049 #define ASCII_0 48
00050 #define ASCII_9 57
00051 
00052 #ifdef VMCMS
00053 #define interesting lookstr  /* for 8 character truncation conflicts */
00054 #include "dvipscms.h"
00055 extern FILE *cmsfopen() ;
00056 extern char ebcdic2ascii[] ;
00057 extern char ascii2ebcdic[] ;
00058 #ifdef fopen
00059 #undef fopen
00060 #endif
00061 #define fopen cmsfopen
00062 #endif
00063 
00064 #include "dvips.h"
00065 /* debug.h redefines fopen to my_real_fopen */
00066 #ifdef fopen
00067 #undef fopen
00068 #endif
00069 
00070 struct encoding {
00071    char *name ;
00072    char *vec[256] ;
00073 } ;
00074 struct encoding staticencoding = {
00075   "TeX text",
00076   {"Gamma", "Delta", "Theta", "Lambda", "Xi", "Pi", "Sigma",
00077    "Upsilon", "Phi", "Psi", "Omega", "arrowup", "arrowdown", "quotesingle",
00078    "exclamdown", "questiondown", "dotlessi", "dotlessj", "grave", "acute",
00079    "caron", "breve", "macron", "ring", "cedilla", "germandbls", "ae", "oe",
00080    "oslash", "AE", "OE", "Oslash", "space", "exclam", "quotedbl", "numbersign",
00081    "dollar", "percent", "ampersand", "quoteright", "parenleft", "parenright",
00082    "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one",
00083    "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon",
00084    "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C",
00085    "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
00086    "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash",
00087    "bracketright", "circumflex", "underscore", "quoteleft", "a", "b", "c", "d",
00088    "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
00089    "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright",
00090    "tilde", "dieresis", "", "", "", "", "", "", "", "", "", "", "", "", "",
00091     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
00092     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
00093     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
00094     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
00095     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
00096     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
00097     "", "", "", "", "", "", "" } } ;
00098 /*
00099  *   It's easier to put this in static storage and parse it as we go
00100  *   than to build the structures ourselves.
00101  */
00102 char *staticligkern[] = {
00103    "% LIGKERN space l =: lslash ; space L =: Lslash ;",
00104    "% LIGKERN question quoteleft =: questiondown ;",
00105    "% LIGKERN exclam quoteleft =: exclamdown ;",
00106    "% LIGKERN hyphen hyphen =: endash ; endash hyphen =: emdash ;",
00107    "% LIGKERN quoteleft quoteleft =: quotedblleft ;",
00108    "% LIGKERN quoteright quoteright =: quotedblright ;",
00109    "% LIGKERN space {} * ; * {} space ; zero {} * ; * {} zero ;",
00110    "% LIGKERN one {} * ; * {} one ; two {} * ; * {} two ;",
00111    "% LIGKERN three {} * ; * {} three ; four {} * ; * {} four ;",
00112    "% LIGKERN five {} * ; * {} five ; six {} * ; * {} six ;",
00113    "% LIGKERN seven {} * ; * {} seven ; eight {} * ; * {} eight ;",
00114    "% LIGKERN nine {} * ; * {} nine ;",
00115 /* Kern accented characters the same way as their base. */
00116   "% LIGKERN Aacute <> A ; aacute <> a ;",
00117   "% LIGKERN Acircumflex <> A ; acircumflex <> a ;",
00118   "% LIGKERN Adieresis <> A ; adieresis <> a ;",
00119   "% LIGKERN Agrave <> A ; agrave <> a ;",
00120   "% LIGKERN Aring <> A ; aring <> a ;",
00121   "% LIGKERN Atilde <> A ; atilde <> a ;",
00122   "% LIGKERN Ccedilla <> C ; ccedilla <> c ;",
00123   "% LIGKERN Eacute <> E ; eacute <> e ;",
00124   "% LIGKERN Ecircumflex <> E ; ecircumflex <> e ;",
00125   "% LIGKERN Edieresis <> E ; edieresis <> e ;",
00126   "% LIGKERN Egrave <> E ; egrave <> e ;",
00127   "% LIGKERN Iacute <> I ; iacute <> i ;",
00128   "% LIGKERN Icircumflex <> I ; icircumflex <> i ;",
00129   "% LIGKERN Idieresis <> I ; idieresis <> i ;",
00130   "% LIGKERN Igrave <> I ; igrave <> i ;",
00131   "% LIGKERN Ntilde <> N ; ntilde <> n ;",
00132   "% LIGKERN Oacute <> O ; oacute <> o ;",
00133   "% LIGKERN Ocircumflex <> O ; ocircumflex <> o ;",
00134   "% LIGKERN Odieresis <> O ; odieresis <> o ;",
00135   "% LIGKERN Ograve <> O ; ograve <> o ;",
00136   "% LIGKERN Oslash <> O ; oslash <> o ;",
00137   "% LIGKERN Otilde <> O ; otilde <> o ;",
00138   "% LIGKERN Scaron <> S ; scaron <> s ;",
00139   "% LIGKERN Uacute <> U ; uacute <> u ;",
00140   "% LIGKERN Ucircumflex <> U ; ucircumflex <> u ;",
00141   "% LIGKERN Udieresis <> U ; udieresis <> u ;",
00142   "% LIGKERN Ugrave <> U ; ugrave <> u ;",
00143   "% LIGKERN Yacute <> Y ; yacute <> y ;",
00144   "% LIGKERN Ydieresis <> Y ; ydieresis <> y ;",
00145   "% LIGKERN Zcaron <> Z ; zcaron <> z ;",
00146 /*
00147  *   These next are only included for deficient afm files that
00148  *   have the lig characters but not the lig commands.
00149  */
00150    "% LIGKERN f i =: fi ; f l =: fl ; f f =: ff ; ff i =: ffi ;",
00151    "% LIGKERN ff l =: ffl ;",
00152    0 } ;
00153 /*
00154  *   The above layout corresponds to TeX Typewriter Type and is compatible
00155  *   with TeX Text because the position of ligatures is immaterial.
00156  */
00157 struct encoding *outencoding = 0 ;
00158 struct encoding *inencoding = 0 ;
00159 char *outenname = NULL, 
00160   *inenname = NULL;/* the file names for input and output encodings */
00161 int boundarychar = -1 ;     /* the boundary character */
00162 int ignoreligkern ;         /* do we look at ligkern info in the encoding? */
00163 /*
00164  *   This is what we store Adobe data in.
00165  */
00166 struct adobeinfo {
00167    struct adobeinfo *next ;
00168    int adobenum, texnum, width ;
00169    char *adobename ;
00170    int llx, lly, urx, ury ;
00171    struct lig *ligs ;
00172    struct kern *kerns ;
00173    struct adobeptr *kern_equivs ;
00174    struct pcc *pccs ;
00175    int wptr, hptr, dptr, iptr ;
00176 } *adobechars, *adobeptrs[256], *texptrs[256],
00177   *uppercase[256], *lowercase[256] ;
00178 int nexttex[256] ; /* for characters encoded multiple times in output */
00179 /*
00180  *   These are the eight ligature ops, in VPL terms and in METAFONT terms.
00181  */
00182 char *vplligops[] = {
00183    "LIG", "/LIG", "/LIG>", "LIG/", "LIG/>", "/LIG/", "/LIG/>", "/LIG/>>", 0
00184 } ;
00185 char *encligops[] = {
00186    "=:", "|=:", "|=:>", "=:|", "=:|>", "|=:|", "|=:|>", "|=:|>>", 0
00187 } ;
00188 struct lig {
00189    struct lig *next ;
00190    char *succ, *sub ;
00191    short op, boundleft ;
00192 } ;
00193 struct kern {
00194    struct kern *next ;
00195    char *succ ;
00196    int delta ;
00197 } ;
00198 struct adobeptr {
00199    struct adobeptr *next;
00200    struct adobeinfo *ch;
00201 };
00202 struct pcc {
00203    struct pcc *next ;
00204    char * partname ;
00205    int xoffset, yoffset ;
00206 } ;
00207 
00208 FILE *afmin, *vplout, *tfmout ;
00209 char inname[200], outname[200] ; /* names of input and output files */
00210 char tmpstr[200] ; /* a buffer for one string */
00211 #define INBUFSIZE 1024
00212 char buffer[INBUFSIZE+10]; /* input buffer (modified while parsing) */
00213 char obuffer[INBUFSIZE+10] ; /* unmodified copy of input buffer */
00214 char *param ; /* current position in input buffer */
00215 char *fontname = "Unknown" ;
00216 char *codingscheme = "Unspecified" ;
00217 #ifdef VMCMS
00218 char *ebfontname ;
00219 char *ebcodingscheme ;
00220 #endif
00221 float italicangle = 0.0 ;
00222 char fixedpitch ;
00223 char makevpl ;
00224 char pedantic ;
00225 int xheight = 400 ;
00226 int fontspace ;
00227 int bc, ec ;
00228 long cksum ;
00229 float efactor = 1.0, slant = 0.0 ;
00230 float capheight = 0.8 ;
00231 char *efactorparam, *slantparam ;
00232 double newslant ;
00233 char titlebuf[500] ;
00234 
00235 void
00236 error P1C(register char *, s)
00237 {
00238    (void)fprintf(stderr, "%s\n", s) ;
00239    if (obuffer[0]) {
00240       (void)fprintf(stderr, "%s\n", obuffer) ;
00241       while (param > buffer) {
00242          (void)fprintf(stderr, " ") ;
00243          param-- ;
00244       }
00245       (void)fprintf(stderr, "^\n") ;
00246    }
00247    if (*s == '!')
00248       exit(1) ;
00249 }
00250 
00251 int
00252 transform P2C(register int, x, register int, y)
00253 {
00254    register double acc ;
00255    acc = efactor * x + slant *y ;
00256    return (int)(acc>=0? floor(acc+0.5) : ceil(acc-0.5) ) ;
00257 }
00258 
00259 int
00260 getline P1H(void) {
00261    register char *p ;
00262    register int c ;
00263 
00264    param = buffer ;
00265    for (p=buffer; (c=getc(afmin)) != EOF;) {
00266       if (p - buffer >= INBUFSIZE)
00267          error("! input line too long; perhaps input file is malformed?") ;
00268       *p++ = c ;
00269       if (c == '\r') {
00270          c = getc(afmin) ;
00271          if (c != EOF) {
00272             if (c == '\n') {
00273                *p++ = c ;
00274             } else {
00275                ungetc(c, afmin) ;
00276             }
00277          }
00278          break ;
00279       } else if (c == '\n') {
00280          break ;
00281       }
00282    }
00283    *p = 0 ;
00284    (void)strcpy(obuffer, buffer) ;
00285    if (p == buffer && c == EOF)
00286       return(0) ;
00287    else
00288       return(1) ;
00289 }
00290 
00291 char *interesting[] = { "FontName", "ItalicAngle", "IsFixedPitch",
00292    "XHeight", "C", "KPX", "CC", "EncodingScheme", NULL} ;
00293 #define FontName (0)
00294 #define ItalicAngle (1)
00295 #define IsFixedPitch (2)
00296 #define XHeight (3)
00297 #define C (4)
00298 #define KPX (5)
00299 #define CC (6)
00300 #define EncodingScheme (7)
00301 #define NONE (-1)
00302 int
00303 interest P1C(char *, s)
00304 {
00305    register char **p ;
00306    register int n ;
00307 
00308    for (p=interesting, n=0; *p; p++, n++)
00309       if (strcmp(s, *p)==0)
00310          return(n) ;
00311    return(NONE) ;
00312 }
00313 
00314 char *
00315 mymalloc P1C(unsigned long, len)
00316 {
00317    register char *p ;
00318    int i ;
00319 
00320 #ifdef SMALLMALLOC
00321    if (len > 65500L)
00322       error("! can't allocate more than 64K!") ;
00323 #endif
00324    p = (char *) malloc((unsigned)len) ;
00325    if (p==NULL)
00326       error("! out of memory") ;
00327    for (i=0; i<len; i++)
00328       p[i] = 0 ;
00329    return(p) ;
00330 }
00331 
00332 char *
00333 newstring P1C(char *, s)
00334 {
00335    char *q = mymalloc((unsigned long)(strlen(s) + 1)) ;
00336    (void)strcpy(q, s) ;
00337    return q ;
00338 }
00339 
00340 char *
00341 paramnewstring P1H(void) {
00342    register char *p, *q ;
00343 
00344    p = param ;
00345    while (*p > ' ')
00346       p++ ;
00347    if (*p != 0)
00348       *p++ = 0 ;
00349    q = newstring(param) ;
00350    while (*p && *p <= ' ')
00351       p++ ;
00352    param = p ;
00353    return(q) ;
00354 }
00355 
00356 char *
00357 paramstring P1H(void) {
00358    register char *p, *q ;
00359 
00360    p = param ;
00361    while (*p > ' ')
00362       p++ ;
00363    q = param ;
00364    if (*p != 0)
00365       *p++ = 0 ;
00366    while (*p && *p <= ' ')
00367       p++ ;
00368    param = p ;
00369    return(q) ;
00370 }
00371 
00372 int
00373 paramnum P1H(void) {
00374    register char *p ;
00375    int i ;
00376 
00377    p = paramstring() ;
00378    if (sscanf(p, "%d", &i) != 1)
00379       error("! integer expected") ;
00380    return(i) ;
00381 }
00382 
00383 float
00384 paramfloat P1H(void) {
00385    register char *p ;
00386    float i ;
00387 
00388    p = paramstring() ;
00389    if (sscanf(p, "%f", &i) != 1)
00390       error("! number expected") ;
00391    return(i) ;
00392 }
00393 
00394 struct adobeinfo *
00395 newchar P1H(void) {
00396    register struct adobeinfo *ai ;
00397 
00398    ai = (struct adobeinfo *)mymalloc((unsigned long)sizeof(struct adobeinfo)) ;
00399    ai->adobenum = -1 ;
00400    ai->texnum = -1 ;
00401    ai->width = -1 ;
00402    ai->adobename = NULL ;
00403    ai->llx = -1 ;
00404    ai->lly = -1 ;
00405    ai->urx = -1 ;
00406    ai->ury = -1 ;
00407    ai->ligs = NULL ;
00408    ai->kerns = NULL ;
00409    ai->kern_equivs = NULL ;
00410    ai->pccs = NULL ;
00411    ai->next = adobechars ;
00412    adobechars = ai ;
00413    return(ai) ;
00414 }
00415 
00416 struct kern *
00417 newkern P1H(void) {
00418    register struct kern *nk ;
00419 
00420    nk = (struct kern *)mymalloc((unsigned long)sizeof(struct kern)) ;
00421    nk->next = NULL ;
00422    nk->succ = NULL ;
00423    nk->delta = 0 ;
00424    return(nk) ;
00425 }
00426 
00427 struct pcc *
00428 newpcc P1H(void) {
00429    register struct pcc *np ;
00430 
00431    np = (struct pcc *)mymalloc((unsigned long)sizeof(struct pcc)) ;
00432    np->next = NULL ;
00433    np->partname = NULL ;
00434    np->xoffset = 0 ;
00435    np->yoffset = 0 ;
00436    return(np) ;
00437 }
00438 
00439 struct lig *
00440 newlig P1H(void) {
00441    register struct lig *nl ;
00442 
00443    nl = (struct lig *)mymalloc((unsigned long)sizeof(struct lig)) ;
00444    nl->next = NULL ;
00445    nl->succ = NULL ;
00446    nl->sub = NULL ;
00447    nl->op = 0 ; /* the default =: op */
00448    nl->boundleft = 0 ;
00449    return(nl) ;
00450 }
00451 
00452 void
00453 expect P1C(char *, s)
00454 {
00455    if (strcmp(paramstring(), s) != 0) {
00456       (void)fprintf(stderr, "%s expected: ", s) ;
00457       error("! syntax error") ;
00458    }
00459 }
00460 
00461 void
00462 handlechar P1H(void) { /* an input line beginning with C */
00463    register struct adobeinfo *ai ;
00464    register struct lig *nl ;
00465 
00466    ai = newchar() ;
00467    ai->adobenum = paramnum() ;
00468    expect(";") ;
00469    expect("WX") ;
00470    ai->width = transform(paramnum(),0) ;
00471    if (ai->adobenum >= 0 && ai->adobenum < 256) {
00472       adobeptrs[ai->adobenum] = ai ;
00473    }
00474    expect(";") ;
00475    expect("N") ;
00476    ai->adobename = paramnewstring() ;
00477    expect(";") ;
00478    expect("B") ;
00479    ai->llx = paramnum() ;
00480    ai->lly = paramnum() ;
00481    ai->llx = transform(ai->llx, ai->lly) ;
00482    ai->urx = paramnum() ;
00483    ai->ury = paramnum() ;
00484    ai->urx = transform(ai->urx, ai->ury) ;
00485 /* We need to avoid negative heights or depths. They break accents in
00486    math mode, among other things.  */
00487    if (ai->lly > 0)
00488       ai->lly = 0 ;
00489    if (ai->ury < 0)
00490       ai->ury = 0 ;
00491    expect(";") ;
00492 /* Now look for ligatures (which aren't present in fixedpitch fonts) */
00493    while (*param == 'L' && !fixedpitch) {
00494       expect("L") ;
00495       nl = newlig() ;
00496       nl->succ = paramnewstring() ;
00497       nl->sub = paramnewstring() ;
00498       nl->next = ai->ligs ;
00499       ai->ligs = nl ;
00500       expect(";") ;
00501    }
00502 }
00503 
00504 struct adobeinfo *
00505 findadobe P1C(char *, p)
00506 {
00507    register struct adobeinfo *ai ;
00508 
00509    for (ai=adobechars; ai; ai = ai->next)
00510       if (strcmp(p, ai->adobename)==0)
00511          return(ai) ;
00512    return(NULL) ;
00513 }
00514 
00515 
00516 /*
00517  *   The following comment no longer applies; we rely on the LIGKERN
00518  *   entries to kill space kerns.  Also, the same applies to numbers.
00519  *
00520  * We ignore kerns before and after space characters, because (1) TeX
00521  * is using the space only for Polish ligatures, and (2) TeX's
00522  * boundarychar mechanisms are not oriented to kerns (they apply
00523  * to both spaces and punctuation) so we don't want to use them.
00524  */
00525 void
00526 handlekern P1H(void) { /* an input line beginning with KPX */
00527    register struct adobeinfo *ai ;
00528    register char *p ;
00529    register struct kern *nk ;
00530 
00531    p = paramstring() ;
00532    ai = findadobe(p) ;
00533    if (ai == NULL)
00534       error("kern char not found") ;
00535    else {
00536       nk = newkern() ;
00537       nk->succ = paramnewstring() ;
00538       nk->delta = transform(paramnum(),0) ;
00539       nk->next = ai->kerns ;
00540       ai->kerns = nk ;
00541     }
00542 }
00543 
00544 void
00545 handleconstruct P1H(void) { /* an input line beginning with CC */
00546    register struct adobeinfo *ai ;
00547    register char *p ;
00548    register struct pcc *np ;
00549    register int n ;
00550    struct pcc *npp = NULL;
00551 
00552    p = paramstring() ;
00553    ai = findadobe(p) ;
00554    if (ai == NULL)
00555       error("! composite character name not found") ;
00556    n = paramnum() ;
00557    expect(";") ;
00558    while (n--) {
00559       if (strcmp(paramstring(),"PCC") != 0) return ;
00560         /* maybe I should expect("PCC") instead, but I'm playing it safe */
00561       np = newpcc() ;
00562       np->partname = paramnewstring() ;
00563       if (findadobe(np->partname)==NULL) return ;
00564       np->xoffset = paramnum() ;
00565       np->yoffset = paramnum() ;
00566       np->xoffset = transform(np->xoffset, np->yoffset) ;
00567       if (npp) npp->next = np ;
00568       else ai->pccs = np ;
00569       npp = np ;
00570       expect(";") ;
00571    }
00572 }
00573 
00574 struct encoding *readencoding P1H(char *) ;
00575 
00576 void
00577 makeaccentligs P1H(void) {
00578    register struct adobeinfo *ai, *aci ;
00579    register char *p ;
00580    register struct lig *nl ;
00581    for (ai=adobechars; ai; ai=ai->next) {
00582       p = ai->adobename ;
00583       if (strlen(p)>2)
00584          if ((aci=findadobe(p+1)) && (aci->adobenum > 127)) {
00585             nl = newlig() ;
00586             nl->succ = mymalloc((unsigned long)2) ;
00587             *(nl->succ + 1) = 0 ;
00588             *(nl->succ) = *p ;
00589             nl->sub = ai->adobename ;
00590             nl->next = aci->ligs ;
00591             aci->ligs = nl ;
00592          }
00593    }
00594 }
00595 
00596 void
00597 readadobe P1H(void) {
00598    struct adobeinfo *ai ;
00599 #ifdef VMCMS
00600     int i;
00601 #endif
00602 
00603 /*
00604  *   We allocate a placeholder boundary char.
00605  */
00606    ai = newchar() ;
00607    ai->adobenum = -1 ;
00608    ai->adobename = "||" ; /* boundary character name */
00609    while (getline()) {
00610       switch(interest(paramstring())) {
00611 case FontName:
00612          fontname = paramnewstring() ;
00613 #ifdef VMCMS
00614 /* fontname comes in as ebcdic but we need it asciified for tfm file
00615    so we save it in ebfontname and change it in fontname */
00616    ebfontname = newstring(fontname) ;
00617    i=0;
00618    while(fontname[i] != '\0') {
00619       fontname[i]=ebcdic2ascii[fontname[i]];
00620       i++;
00621    };
00622 #endif
00623          break ;
00624 case EncodingScheme:
00625          codingscheme = paramnewstring() ;
00626 #ifdef VMCMS
00627 /* for codingscheme, we do the same as we did for fontname */
00628    ebcodingscheme = newstring(codingscheme) ;
00629    i=0;
00630    while(codingscheme[i] != '\0') {
00631       codingscheme[i]=ebcdic2ascii[codingscheme[i]];
00632       i++;
00633    }
00634 #endif
00635          break ;
00636 case ItalicAngle:
00637          italicangle = paramfloat() ;
00638          break ;
00639 case IsFixedPitch:
00640          if (*param == 't' || *param == 'T')
00641             fixedpitch = 1 ;
00642          else
00643             fixedpitch = 0 ;
00644          break ;
00645 case XHeight:
00646          xheight = paramnum() ;
00647          break ;
00648 case C:
00649          handlechar() ;
00650          break ;
00651 case KPX:
00652          handlekern() ;
00653          break ;
00654 case CC:
00655          handleconstruct() ;
00656          break ;
00657 default:
00658          break ;
00659       }
00660    }
00661    fclose(afmin) ;
00662    afmin = 0 ;
00663 }
00664 /*
00665  *   Re-encode the adobe font.  Assumes that the header file will
00666  *   also contain the appropriate instructions!
00667  */
00668 void
00669 handlereencoding P1H(void) {
00670    if (inenname) {
00671       int i ;
00672       struct adobeinfo *ai ;
00673       char *p ;
00674 
00675       ignoreligkern = 1 ;
00676       inencoding = readencoding(inenname) ;
00677       for (i=0; i<256; i++)
00678          if (0 != (ai=adobeptrs[i])) {
00679             ai->adobenum = -1 ;
00680             adobeptrs[i] = NULL ;
00681          }
00682       for (i=0; i<256; i++) {
00683          p = inencoding->vec[i] ;
00684          if (p && *p && strcmp(p, ".notdef") != 0 && 0 != (ai = findadobe(p))) {
00685             ai->adobenum = i ;
00686             adobeptrs[i] = ai ;
00687          }
00688       }
00689       codingscheme = inencoding->name ;
00690    }
00691    ignoreligkern = 0 ;
00692    if (outenname) {
00693       outencoding = readencoding(outenname) ;
00694    } else {
00695       outencoding = readencoding((char *)0) ;
00696    }
00697 }
00698 
00699 /*
00700  *   This routine reverses a list.  We use it because we accumulate the
00701  *   adobeinfo list in reverse order, but when we go to map the
00702  *   characters, we would prefer to use the original ordering.  It just
00703  *   makes more sense.
00704  */
00705 struct adobeinfo *revlist P1C(struct adobeinfo *, p)
00706 {
00707    struct adobeinfo *q = 0, *t ;
00708 
00709    while (p) {
00710       t = p->next ;
00711       p->next = q ;
00712       q = p ;
00713       p = t ;
00714    }
00715    return q ;
00716 }
00717 
00718 void
00719 assignchars P1H(void) {
00720    register char **p ;
00721    register int i, j ;
00722    register struct adobeinfo *ai, *pai ;
00723    int nextfree = 128 ;
00724    struct pcc *pcp ;
00725 
00726 /*
00727  *   First, we assign all those that match perfectly.
00728  */
00729    for (i=0, p=outencoding->vec; i<256; i++, p++)
00730       if (*p && strcmp(*p, ".notdef") != 0 &&
00731           (ai=findadobe(*p)) && (ai->adobenum >= 0 || ai->pccs != NULL)) {
00732          if (ai->texnum >= 0)
00733             nexttex[i] = ai->texnum ; /* linked list */
00734          ai->texnum = i ;
00735          texptrs[i] = ai ;
00736       }
00737    if (pedantic)
00738       return ;
00739 /*
00740  *   Next, we assign all the others, retaining the adobe positions, possibly
00741  *   multiply assigning characters. Unless the output encoding was
00742  *   precisely specified.
00743  */
00744    for (ai=adobechars; ai; ai=ai->next)
00745       if (ai->adobenum >= 0 && ai->adobenum <256
00746           && ai->texnum < 0 && texptrs[ai->adobenum] == 0) {
00747          ai->texnum = ai->adobenum ;
00748          texptrs[ai->adobenum] = ai ;
00749       }
00750 /*
00751  *   Finally, we map all remaining characters into free locations beginning
00752  *   with 128, if we know how to construct those characters.  We need to
00753  *   make sure the component pieces are mapped.
00754  */
00755    adobechars = revlist(adobechars) ;
00756    for (ai=adobechars; ai; ai=ai->next)
00757       if (ai->texnum<0 && (ai->adobenum>=0 || ai->pccs != NULL)) {
00758          while (texptrs[nextfree]) {
00759             nextfree=(nextfree+1)&255 ;
00760             if (nextfree==128) goto finishup ; /* all slots full */
00761          }
00762          ai->texnum = nextfree ;
00763          texptrs[nextfree] = ai ;
00764       }
00765 finishup:
00766 /*
00767  *   We now check all of the composite characters.  If any of the
00768  *   components are not mapped, we unmap the composite character.
00769  */
00770    for (i=0; i<256; i++) {
00771       ai = texptrs[i] ;
00772       if (ai && ai->pccs != NULL && ai->texnum >= 0) {
00773          for (pcp = ai->pccs; pcp; pcp = pcp->next) {
00774             pai = findadobe(pcp->partname) ;
00775             if (pai == NULL || pai->texnum < 0) {
00776                texptrs[ai->texnum] = 0 ;
00777                ai->texnum = -1 ;
00778                break ;
00779             }
00780          }
00781       }
00782    }
00783 /*
00784  *   Now, if any of the characters are encoded multiple times, we want
00785  *   ai->texnum to be the first one assigned, since that is most likely
00786  *   to be the most important one.  So we reverse the above lists.
00787  */
00788    for (ai=adobechars; ai; ai=ai->next)
00789       if (ai->texnum >= 0 && ai->texnum < 256) {
00790          j = -1 ;
00791          while (nexttex[ai->texnum] >= 0) {
00792             i = nexttex[ai->texnum] ;
00793             nexttex[ai->texnum] = j ;
00794             j = ai->texnum ;
00795             ai->texnum = i ;
00796          }
00797          nexttex[ai->texnum] = j ;
00798       }
00799 }
00800 
00801 void
00802 upmap P1H(void) { /* Compute uppercase mapping, when making a small caps font */
00803    register struct adobeinfo *ai, *Ai ;
00804    register char *p, *q ;
00805    register struct pcc *np, *nq ;
00806    int i ;
00807    char lwr[50] ;
00808 
00809 /* JLH: changed some lines below to be ascii<->ebcdic independent
00810    any reason we don't use 'isupper'?.
00811    Looks like we should use isupper to me --karl.  */
00812    for (Ai=adobechars; Ai; Ai=Ai->next) {
00813       p = Ai->adobename ;
00814       if (isupper (*p)) {
00815          q = lwr ;
00816          for (; *p; p++)
00817             *q++ = TOLOWER (*p);
00818          *q = '\0';   /* changed this too! */
00819 
00820          if (0 != (ai=findadobe(lwr))) {
00821             for (i = ai->texnum; i >= 0; i = nexttex[i])
00822                uppercase[i] = Ai ;
00823             for (i = Ai->texnum; i >= 0; i = nexttex[i])
00824                lowercase[i] = ai ;
00825          }
00826       }
00827    }
00828 /* Note that, contrary to the normal true/false conventions,
00829  * uppercase[i] is NULL and lowercase[i] is non-NULL when i is the
00830  * ASCII code of an uppercase letter; and vice versa for lowercase letters */
00831 
00832    if (0 != (ai=findadobe("germandbls")))
00833       if (0 != (Ai=findadobe("S"))) { /* we also construct SS */
00834          for (i=ai->texnum; i >= 0; i = nexttex[i])
00835             uppercase[i] = ai ;
00836          ai->adobenum = -1 ;
00837          ai->width = Ai->width << 1 ;
00838          ai->llx = Ai->llx ;
00839          ai->lly = Ai->lly ;
00840          ai->urx = Ai->width + Ai->urx ;
00841          ai->ury = Ai->ury ;
00842          ai->kerns = Ai->kerns ;
00843          np = newpcc() ;
00844          np->partname = "S" ;
00845          nq = newpcc() ;
00846          nq->partname = "S" ;
00847          nq->xoffset = Ai->width ;
00848          np->next = nq ;
00849          ai->pccs = np ;
00850       }
00851    if ((ai=findadobe("dotlessi")))
00852       for (i=ai->texnum; i >= 0; i = nexttex[i])
00853          uppercase[i] = findadobe("I") ;
00854    if ((ai=findadobe("dotlessj")))
00855       for (i=ai->texnum; i >= 0; i = nexttex[i])
00856          uppercase[i] = findadobe("J") ;
00857 }
00858 /* The logic above seems to work well enough, but it leaves useless characters
00859  * like `fi' and `fl' in the font if they were present initially,
00860  * and it omits characters like `dotlessj' if they are absent initially */
00861 
00862 /* Now we turn to computing the TFM file */
00863 
00864 int lf, lh, nw, nh, nd, ni, nl, nk, ne, np ;
00865 
00866 void
00867 write16 P1C(register short, what)
00868 {
00869    (void)fputc(what >> 8, tfmout) ;
00870    (void)fputc(what & 255, tfmout) ;
00871 }
00872 
00873 void
00874 writearr P2C(register long *, p, register int, n)
00875 {
00876    while (n) {
00877       write16((short)(*p >> 16)) ;
00878       write16((short)(*p & 65535)) ;
00879       p++ ;
00880       n-- ;
00881    }
00882 }
00883 
00884 void
00885 makebcpl P3C(register long *, p, register char *, s, register int, n)
00886 {
00887    register long t ;
00888    register long sc ;
00889 
00890    if (strlen(s) < n)
00891       n = strlen(s) ;
00892    t = ((long)n) << 24 ;
00893    sc = 16 ;
00894    while (n > 0) {
00895       t |= ((long)(*(unsigned char *)s++)) << sc ;
00896       sc -= 8 ;
00897       if (sc < 0) {
00898          *p++ = t ;
00899          t = 0 ;
00900          sc = 24 ;
00901       }
00902       n-- ;
00903    }
00904    *p++ = t ;
00905 }
00906 
00907 int source[257] ;
00908 int unsort[257] ;
00909 
00910 /*
00911  *   Next we need a routine to reduce the number of distinct dimensions
00912  *   in a TFM file. Given an array what[0]...what[oldn-1], we want to
00913  *   group its elements into newn clusters, in such a way that the maximum
00914  *   difference between elements of a cluster is as small as possible.
00915  *   Furthermore, what[0]=0, and this value must remain in a cluster by
00916  *   itself. Data such as `0 4 6 7 9' with newn=3 shows that an iterative
00917  *   scheme in which 6 is first clustered with 7 will not work. So we
00918  *   borrow a neat algorithm from METAFONT to find the true optimum.
00919  *   Memory location what[oldn] is set to 0x7fffffffL for convenience.
00920  */
00921 long nextd ; /* smallest value that will give a different mincover */
00922 int
00923 mincover P2C(long *, what, 
00924             register long, d) /* tells how many clusters result, given max difference d */
00925 {
00926    register int m ;
00927    register long l ;
00928    register long *p ;
00929 
00930    nextd = 0x7fffffffL ;
00931    p = what+1 ;
00932    m = 1 ;
00933    while (*p<0x7fffffffL) {
00934       m++ ;
00935       l = *p ;
00936       while (*++p <= l+d) ;
00937       if (*p-l < nextd) nextd = *p-l ;
00938    }
00939    return (m) ;
00940 }
00941 
00942 void
00943 remap P3C(long *, what, int, oldn, int, newn)
00944 {
00945    register int i, j ;
00946    register long d, l ;
00947 
00948    what[oldn] = 0x7fffffffL ;
00949    for (i=oldn-1; i>0; i--) {
00950       d = what[i] ;
00951       for (j=i; what[j+1]<d; j++) {
00952          what[j] = what[j+1] ;
00953          source[j] = source[j+1] ;
00954       }
00955       what[j] = d ;
00956       source[j] = i ;
00957    } /* Tom, don't let me ever catch you using bubblesort again! -- Don */
00958 
00959    i = mincover(what, 0L) ;
00960    d = nextd ;
00961    while (mincover(what,d+d)>newn) d += d ;
00962    while (mincover(what,d)>newn) d = nextd ;
00963 
00964    i = 1 ;
00965    j = 0 ;
00966    while (i<oldn) {
00967       j++ ;
00968       l = what[i] ;
00969       unsort[source[i]] = j ;
00970       while (what[++i] <= l+d) {
00971          unsort[source[i]] = j ;
00972          if (i-j == oldn-newn) d = 0 ;
00973       }
00974       what[j] = (l+what[i-1])/2 ;
00975    }
00976 }
00977 
00978 long
00979 checksum P1H(void) {
00980    int i ;
00981    unsigned long s1 = 0, s2 = 0 ;
00982    char *p ;
00983    struct adobeinfo *ai ;
00984 
00985    for (i=0; i<256; i++)
00986       if (0 != (ai=adobeptrs[i])) {
00987          s1 = ((s1 << 1) ^ (s1>>31)) ^ ai->width ; /* cyclic left shift */
00988          s1 &= 0xffffffff; /* in case we're on a 64-bit machine */
00989          for (p=ai->adobename; *p; p++)
00990 #ifndef VMCMS
00991             s2 = (s2 * 3) + *p ;
00992 #else
00993             s2 = (s2 * 3) + ebcdic2ascii[*p] ;
00994 #endif
00995       }
00996    s1 = (s1 << 1) ^ s2 ;
00997    return s1 ;
00998 }
00999 
01000 /*
01001  *   The next routine simply scales something.
01002  *   Input is in 1000ths of an em.  Output is in FIXFACTORths of 1000.
01003  */
01004 #define FIXFACTOR (0x100000L) /* 2^{20}, the unit fixnum */
01005 long
01006 scale P1C(long, what)
01007 {
01008    return(((what / 1000) << 20) +
01009           (((what % 1000) << 20) + 500) / 1000) ;
01010 }
01011 
01012 long *header, *charinfo, *width, *height, *depth, *ligkern, *kern, *tparam,
01013      *italic ;
01014 long *tfmdata ;
01015 
01016 void
01017 buildtfm P1H(void) {
01018    register int i, j ;
01019    register struct adobeinfo *ai ;
01020 
01021    header = tfmdata ;
01022    cksum = checksum() ;
01023    header[0] = cksum ;
01024    header[1] = 0xa00000 ; /* 10pt design size */
01025    makebcpl(header+2, codingscheme, 39) ;
01026    makebcpl(header+12, fontname, 19) ;
01027    lh = 17 ;
01028    charinfo = header + lh ;
01029 
01030    for (i=0; i<256 && adobeptrs[i]==NULL; i++) ;
01031    bc = i ;
01032    for (i=255; i>=0 && adobeptrs[i]==NULL; i--) ;
01033    ec = i;
01034    if (ec < bc)
01035       error("! no Adobe characters") ;
01036 
01037    width = charinfo + (ec - bc + 1) ;
01038    width[0] = 0 ;
01039    nw++ ;
01040    for (i=bc; i<=ec; i++)
01041       if (0 != (ai=adobeptrs[i])) {
01042          width[nw]=ai->width ;
01043          for (j=1; width[j]!=ai->width; j++) ;
01044          ai->wptr = j ;
01045          if (j==nw)
01046             nw++ ;
01047       }
01048    if (nw>256)
01049       error("! 256 chars with different widths") ;
01050    depth = width + nw ;
01051    depth[0] = 0 ;
01052    nd = 1 ;
01053    for (i=bc; i<=ec; i++)
01054       if (0 != (ai=adobeptrs[i])) {
01055          depth[nd] = -ai->lly ;
01056          for (j=0; depth[j]!=-ai->lly; j++) ;
01057          ai->dptr = j ;
01058          if (j==nd)
01059             nd++ ;
01060       }
01061    if (nd > 16) {
01062       remap(depth, nd, 16) ;
01063       nd = 16 ;
01064       for (i=bc; i<=ec; i++)
01065          if (0 != (ai=adobeptrs[i]))
01066             ai->dptr = unsort[ai->dptr] ;
01067    }
01068    height = depth + nd ;
01069    height[0] = 0 ;
01070    nh = 1 ;
01071    for (i=bc; i<=ec; i++)
01072       if (0 != (ai=adobeptrs[i])) {
01073          height[nh]=ai->ury ;
01074          for (j=0; height[j]!=ai->ury; j++) ;
01075          ai->hptr = j ;
01076          if (j==nh)
01077             nh++ ;
01078       }
01079    if (nh > 16) {
01080       remap(height, nh, 16) ;
01081       nh = 16 ;
01082       for (i=bc; i<=ec; i++)
01083          if (0 != (ai=adobeptrs[i]))
01084             ai->hptr = unsort[ai->hptr] ;
01085    }
01086    italic  = height + nh ;
01087    italic[0] = 0 ;
01088    ni = 1 ;
01089    for (i=bc; i<=ec; i++)
01090       if (0 != (ai=adobeptrs[i])) {
01091          italic[ni] = ai->urx - ai->width ;
01092          if (italic[ni]<0)
01093             italic[ni] = 0 ;
01094          for (j=0; italic[j]!=italic[ni]; j++) ;
01095          ai->iptr = j ;
01096          if (j==ni)
01097             ni++ ;
01098       }
01099    if (ni > 64) {
01100       remap(italic, ni, 64) ;
01101       ni = 64 ;
01102       for (i=bc; i<=ec; i++)
01103          if (0 != (ai=adobeptrs[i]))
01104             ai->iptr = unsort[ai->iptr] ;
01105    }
01106 
01107    for (i=bc; i<=ec; i++)
01108       if (0 != (ai=adobeptrs[i]))
01109          charinfo[i-bc] = ((long)(ai->wptr)<<24) +
01110                            ((long)(ai->hptr)<<20) +
01111                             ((long)(ai->dptr)<<16) +
01112                              ((long)(ai->iptr)<<10) ;
01113 
01114    ligkern = italic + ni ;
01115    nl = 0 ; /* ligatures and kerns omitted from raw Adobe font */
01116    kern = ligkern + nl ;
01117    nk = 0 ;
01118 
01119    newslant = (double)slant - efactor * tan(italicangle*(3.1415926535/180.0)) ;
01120    tparam = kern + nk ;
01121    tparam[0] = (long)(FIXFACTOR * newslant + 0.5) ;
01122    tparam[1] = scale((long)fontspace) ;
01123    tparam[2] = (fixedpitch ? 0 : scale((long)(300*efactor+0.5))) ;
01124    tparam[3] = (fixedpitch ? 0 : scale((long)(100*efactor+0.5))) ;
01125    tparam[4] = scale((long)xheight) ;
01126    tparam[5] = scale((long)(1000*efactor+0.5)) ;
01127    np = 6 ;
01128 }
01129 
01130 void
01131 writesarr P2C(long *, what, int, len)
01132 {
01133    register long *p ;
01134    int i ;
01135 
01136    p = what ;
01137    i = len ;
01138    while (i) {
01139       *p = scale(*p) ;
01140       (void)scale(*p) ; /* need this kludge for some compilers */
01141       p++ ;
01142       i-- ;
01143    }
01144    writearr(what, len) ;
01145 }
01146 
01147 void
01148 writetfm P1H(void) {
01149    lf = 6 + lh + (ec - bc + 1) + nw + nh + nd + ni + nl + nk + ne + np ;
01150    write16(lf) ;
01151    write16(lh) ;
01152    write16(bc) ;
01153    write16(ec) ;
01154    write16(nw) ;
01155    write16(nh) ;
01156    write16(nd) ;
01157    write16(ni) ;
01158    write16(nl) ;
01159    write16(nk) ;
01160    write16(ne) ;
01161    write16(np) ;
01162    writearr(header, lh) ;
01163    writearr(charinfo, ec-bc+1) ;
01164    writesarr(width, nw) ;
01165    writesarr(height, nh) ;
01166    writesarr(depth, nd) ;
01167    writesarr(italic, ni) ;
01168    writearr(ligkern, nl) ;
01169    writesarr(kern, nk) ;
01170    writearr(tparam, np) ;
01171 }
01172 
01173 /* OK, the TFM file is done! Now for our next trick, the VPL file. */
01174 
01175 /* For TeX we want to compute a character height that works properly
01176  * with accents. The following list of accents doesn't need to be complete. */
01177 /*
01178  *   We only do this if the xheight has a reasonable value.
01179  *   (>50)
01180  */
01181 char *accents[] = { "acute", "tilde", "caron", "dieresis", NULL} ;
01182 int
01183 texheight P1C(register struct adobeinfo *, ai)
01184 {
01185    register char **p;
01186    register struct adobeinfo *aci, *acci ;
01187    if (xheight <= 50 || *(ai->adobename + 1)) return (ai->ury) ;
01188                                            /* that was the simple case */
01189    for (p=accents; *p; p++)  /* otherwise we look for accented letters */
01190       if (0 != (aci=findadobe(*p))) {
01191          strcpy(buffer,ai->adobename) ;
01192          strcat(buffer,*p) ;
01193          if (0 != (acci=findadobe(buffer)))
01194             return (acci->ury - aci->ury + xheight) ;
01195       }
01196    return (ai->ury) ;
01197 }
01198 
01199 /* modified tgr to eliminate varargs problems */
01200 
01201 #define vout(s)  fprintf(vplout, s)
01202 int level ; /* the depth of parenthesis nesting in VPL file being written */
01203 void vlevout() {
01204    register int l = level ;
01205    while (l--) vout("   ") ;
01206 }
01207 void vlevnlout() {
01208    vout("\n") ;
01209    vlevout() ;
01210 }
01211 #define voutln(str) {fprintf(vplout,"%s\n",str);vlevout();}
01212 #define voutln2(f,s) {fprintf(vplout,f,s);vlevnlout();}
01213 #define voutln3(f,a,b) {fprintf(vplout,f,a,b);vlevnlout();}
01214 #define voutln4(f,a,b,c) {fprintf(vplout,f,a,b,c);vlevnlout();}
01215 void
01216 vleft P1H(void)
01217 {
01218    level++ ;
01219    vout("(") ;
01220 }
01221 
01222 void
01223 vright P1H(void)
01224 {
01225    level-- ;
01226    voutln(")") ;
01227 }
01228 
01229 int forceoctal = 0 ;
01230 
01231 char vcharbuf[6] ;
01232 char *vchar P1C(int, c)
01233 {
01234    if (forceoctal == 0 && ISALNUM (c))
01235       (void) sprintf(vcharbuf,"C %c",
01236 #ifndef VMCMS
01237       c) ;
01238 #else
01239       ascii2ebcdic[c]) ;
01240 #endif
01241    else (void) sprintf(vcharbuf,"O %o", (unsigned)c) ;
01242    return (vcharbuf) ;
01243 }
01244 
01245 char vnamebuf[100];
01246 char *
01247 vname P1C(int, c)
01248 {
01249   if (!forceoctal && ISALNUM (c)) {
01250     vnamebuf[0] = 0;
01251   } else if (c >= 0 && c < 256) {
01252     sprintf (vnamebuf, " (comment %s)", texptrs[c]->adobename);
01253   }
01254   return vnamebuf;
01255 }
01256 
01257 void
01258 writevpl P1H(void)
01259 {
01260    register int i, j, k ;
01261    register struct adobeinfo *ai ;
01262    register struct lig *nlig ;
01263    register struct kern *nkern ;
01264    register struct pcc *npcc ;
01265    struct adobeinfo *asucc, *asub, *api ;
01266    struct adobeptr *kern_eq;
01267    int xoff, yoff, ht ;
01268    char unlabeled ;
01269 
01270    voutln2("(VTITLE Created by %s)", titlebuf) ;
01271    voutln("(COMMENT Please edit that VTITLE if you edit this file)") ;
01272    (void)sprintf(obuffer, "TeX-%s%s%s%s", outname,
01273       (efactor==1.0? "" : "-E"), (slant==0.0? "" : "-S"),
01274                  (makevpl==1? "" : "-CSC")) ;
01275    if (strlen(obuffer)>19) { /* too long, will retain first 9 and last 10 */
01276       register char *p, *q ;
01277       for (p = &obuffer[9], q = &obuffer[strlen(obuffer)-10] ; p<&obuffer[19];
01278               p++, q++) *p = *q ;
01279       obuffer[19] = '\0' ;
01280    }
01281    voutln2("(FAMILY %s)" , obuffer) ;
01282    {
01283       char tbuf[300] ;
01284       char *base_encoding = 
01285 #ifndef VMCMS
01286          codingscheme ;
01287 #else
01288          ebcodingscheme ;
01289 #endif
01290       
01291       if (strcmp (outencoding->name, base_encoding) == 0) {
01292         sprintf(tbuf, "%s", outencoding->name);
01293       } else {
01294         sprintf(tbuf, "%s + %s", base_encoding, outencoding->name);
01295       }
01296       
01297       if (strlen(tbuf) > 39) {
01298          error("Coding scheme too long; shortening to 39 characters.") ;
01299          tbuf[39] = 0 ;
01300       }
01301       voutln2("(CODINGSCHEME %s)", tbuf) ;
01302    }
01303    voutln("(DESIGNSIZE R 10.0)") ;
01304    voutln("(DESIGNUNITS R 1000)") ;
01305    voutln("(COMMENT DESIGNSIZE (1 em) IS IN POINTS)") ;
01306    voutln("(COMMENT OTHER DIMENSIONS ARE MULTIPLES OF DESIGNSIZE/1000)") ;
01307    /* Let vptovf compute the checksum. */
01308    /* voutln2("(CHECKSUM O %lo)",cksum ^ 0xffffffff) ; */
01309    if (boundarychar >= 0)
01310       voutln2("(BOUNDARYCHAR O %lo)", (unsigned long)boundarychar) ;
01311    vleft() ; voutln("FONTDIMEN") ;
01312    if (newslant)
01313       voutln2("(SLANT R %f)", newslant) ;
01314    voutln2("(SPACE D %d)", fontspace) ;
01315    if (! fixedpitch) {
01316       voutln2("(STRETCH D %d)", transform(200,0)) ;
01317       voutln2("(SHRINK D %d)", transform(100,0)) ;
01318    }
01319    voutln2("(XHEIGHT D %d)", xheight) ;
01320    voutln2("(QUAD D %d)", transform(1000,0)) ;
01321    voutln2("(EXTRASPACE D %d)", fixedpitch ? fontspace : transform(111, 0)) ;
01322    vright() ;
01323    vleft() ; voutln("MAPFONT D 0");
01324    voutln2("(FONTNAME %s)", outname) ;
01325    /* voutln2("(FONTCHECKSUM O %lo)", (unsigned long)cksum) ; */
01326    vright() ;
01327    if (makevpl>1) {
01328       vleft() ; voutln("MAPFONT D 1");
01329       voutln2("(FONTNAME %s)", outname) ;
01330       voutln2("(FONTAT D %d)", (int)(1000.0*capheight+0.5)) ;
01331       /* voutln2("(FONTCHECKSUM O %lo)", (unsigned long)cksum) ; */
01332       vright() ;
01333    }
01334 
01335    for (i=0; i<256 && texptrs[i]==NULL; i++) ;
01336    bc = i ;
01337    for (i=255; i>=0 && texptrs[i]==NULL; i--) ;
01338    ec = i;
01339 
01340    vleft() ; voutln("LIGTABLE") ;
01341    ai = findadobe("||") ;
01342    unlabeled = 1 ;
01343    for (nlig=ai->ligs; nlig; nlig=nlig->next)
01344       if (0 != (asucc=findadobe(nlig->succ))) {
01345          if (0 != (asub=findadobe(nlig->sub)))
01346             if (asucc->texnum>=0)
01347                if (asub->texnum>=0) {
01348                   if (unlabeled) {
01349                      voutln("(LABEL BOUNDARYCHAR)") ;
01350                      unlabeled = 0 ;
01351                   }
01352                   for (j = asucc->texnum; j >= 0; j = nexttex[j]) {
01353                      voutln4("(%s %s O %o)", vplligops[nlig->op],
01354                          vchar(j), (unsigned)asub->texnum) ;
01355                   }
01356                }
01357        }
01358    if (! unlabeled) voutln("(STOP)") ;
01359    for (i=bc; i<=ec; i++)
01360       if ((ai=texptrs[i]) && ai->texnum == i) {
01361          unlabeled = 1 ;
01362          if (uppercase[i]==NULL) /* omit ligatures from smallcap lowercase */
01363             for (nlig=ai->ligs; nlig; nlig=nlig->next)
01364                if (0 != (asucc=findadobe(nlig->succ)))
01365                   if (0 != (asub=findadobe(nlig->sub)))
01366                      if (asucc->texnum>=0)
01367                         if (asub->texnum>=0) {
01368                            if (unlabeled) {
01369                               for (j = ai->texnum; j >= 0; j = nexttex[j])
01370                                  voutln3("(LABEL %s)%s", vchar(j), vname(j)) ;
01371                               unlabeled = 0 ;
01372                            }
01373                            for (j = asucc->texnum; j >= 0; j = nexttex[j]) {
01374                               voutln4("(%s %s O %o)", vplligops[nlig->op],
01375                                    vchar(j), (unsigned)asub->texnum) ;
01376                               if (nlig->boundleft)
01377                                  break ;
01378                            }
01379                         }
01380          for (nkern = (uppercase[i] ? uppercase[i]->kerns : ai->kerns);
01381                     nkern; nkern=nkern->next)
01382             if (0 != (asucc=findadobe(nkern->succ)))
01383                for (j = asucc->texnum; j >= 0; j = nexttex[j]) {
01384                   if (uppercase[j]==NULL) {
01385                      if (unlabeled) {
01386                         for (k = ai->texnum; k >= 0; k = nexttex[k])
01387                            voutln3("(LABEL %s)%s", vchar(k), vname(k)) ;
01388                         unlabeled = 0 ;
01389                      }
01390                      /* If other characters have the same kerns as this
01391                         one, output the label here.  This makes the TFM
01392                         file much smaller than if we output all the
01393                         kerns again under a different label.  */
01394                      for (kern_eq = ai->kern_equivs; kern_eq;
01395                           kern_eq = kern_eq->next) {
01396                         k = kern_eq->ch->texnum;
01397                         if (k >= 0 && k < 256)
01398                           voutln3("(LABEL %s)%s", vchar(k), vname(k)) ;
01399                      }
01400                      ai->kern_equivs = 0; /* Only output those labels once. */
01401                      if (uppercase[i]) {
01402                         if (lowercase[j]) {
01403                            for (k=lowercase[j]->texnum; k >= 0; k = nexttex[k])
01404                               voutln4("(KRN %s R %.1f)%s", vchar(k),
01405                                     capheight*nkern->delta, vname(k)) ;
01406                         } else voutln4("(KRN %s R %.1f)%s",
01407                                  vchar(j), capheight*nkern->delta, vname(j)) ;
01408                      } else {
01409                         voutln4("(KRN %s R %d)%s", vchar(j),
01410                                 nkern->delta, vname(j)) ;
01411                         if (lowercase[j])
01412                            for (k=lowercase[j]->texnum; k >= 0; k = nexttex[k])
01413                               voutln4("(KRN %s R %.1f)%s", vchar(k),
01414                                 capheight*nkern->delta, vname(k)) ;
01415                      }
01416                   }
01417                }
01418          if (! unlabeled) voutln("(STOP)") ;
01419       }
01420    vright() ;
01421 
01422    for (i=bc; i<=ec; i++)
01423       if (0 != (ai=texptrs[i])) {
01424          vleft() ; fprintf(vplout, "CHARACTER %s", vchar(i)) ;
01425          if (*vcharbuf=='C') {
01426             voutln("") ;
01427          } else
01428             voutln2(" (comment %s)", ai->adobename) ;
01429          if (uppercase[i]) {
01430             ai=uppercase[i] ;
01431             voutln2("(CHARWD R %.1f)", capheight * (ai->width)) ;
01432             if (0 != (ht=texheight(ai)))
01433                voutln2("(CHARHT R %.1f)", capheight * ht) ;
01434             if (ai->lly)
01435                voutln2("(CHARDP R %.1f)", -capheight * ai->lly) ;
01436             if (ai->urx > ai->width)
01437                voutln2("(CHARIC R %.1f)", capheight * (ai->urx - ai->width)) ;
01438          } else {
01439             voutln2("(CHARWD R %d)", ai->width) ;
01440             if (0 != (ht=texheight(ai)))
01441                voutln2("(CHARHT R %d)", ht) ;
01442             if (ai->lly)
01443                voutln2("(CHARDP R %d)", -ai->lly) ;
01444             if (ai->urx > ai->width)
01445                voutln2("(CHARIC R %d)", ai->urx - ai->width) ;
01446          }
01447          if (ai->adobenum != i || uppercase[i]) {
01448             vleft() ; voutln("MAP") ;
01449             if (uppercase[i]) voutln("(SELECTFONT D 1)") ;
01450             if (ai->pccs && ai->adobenum < 0) {
01451                xoff = 0 ; yoff = 0 ;
01452                for (npcc = ai->pccs; npcc; npcc=npcc->next)
01453                   if (0 != (api=findadobe(npcc->partname)))
01454                      if (api->texnum>=0) {
01455                         if (npcc->xoffset != xoff) {
01456                            if (uppercase[i]) {
01457                               voutln2("(MOVERIGHT R %.1f)",
01458                                       capheight * (npcc->xoffset - xoff)) ;
01459                            } else voutln2("(MOVERIGHT R %d)",
01460                                       npcc->xoffset - xoff) ;
01461                            xoff = npcc->xoffset ;
01462                         }
01463                         if (npcc->yoffset != yoff) {
01464                            if (uppercase[i]) {
01465                               voutln2("(MOVEUP R %.1f)",
01466                                       capheight * (npcc->yoffset - yoff)) ;
01467                            } else voutln2("(MOVEUP R %d)",
01468                                       npcc->yoffset - yoff) ;
01469                            yoff = npcc->yoffset ;
01470                         }
01471                         voutln2("(SETCHAR O %o)", (unsigned)api->adobenum) ;
01472                         xoff += texptrs[api->texnum]->width ;
01473                      }
01474             } else voutln2("(SETCHAR O %o)", (unsigned)ai->adobenum) ;
01475             vright() ;
01476          }
01477          vright() ;
01478       }
01479    if (level) error("! I forgot to match the parentheses") ;
01480 }
01481 
01482 #ifdef KPATHSEA
01483 void version P1C(FILE *, f)
01484 {
01485   extern KPSEDLL char *kpathsea_version_string;
01486   fputs ("afm2tfm(k) (dvips(k) 5.95a) 8.1\n", f);
01487   fprintf (f, "%s\n", kpathsea_version_string);
01488   fputs ("Copyright (C) 2005 Radical Eye Software.\n\
01489 There is NO warranty.  You may redistribute this software\n\
01490 under the terms of the GNU General Public License\n\
01491 and the Dvips copyright.\n\
01492 For more information about these matters, see the files\n\
01493 named COPYING and afm2tfm.c.\n\
01494 Primary author of afm2tfm: T. Rokicki; -k maintainer: K. Berry.\n", f);
01495 }
01496 
01497 #define USAGE "\
01498   Convert an Adobe font metric file to TeX font metric format.\n\
01499 \n\
01500 -c REAL             use REAL for height of small caps made with -V [0.8]\n\
01501 -e REAL             widen (extend) characters by a factor of REAL\n\
01502 -O                  use octal for all character codes in the vpl file\n\
01503 -p ENCFILE          read/download ENCFILE for the PostScript encoding\n\
01504 -s REAL             oblique (slant) characters by REAL, generally <<1\n\
01505 -t ENCFILE          read ENCFILE for the encoding of the vpl file\n\
01506 -T ENCFILE          equivalent to -p ENCFILE -t ENCFILE\n\
01507 -u                  output only characters from encodings, nothing extra\n\
01508 -v FILE[.vpl]       make a VPL file for conversion to VF\n\
01509 -V SCFILE[.vpl]     like -v, but synthesize smallcaps as lowercase\n\
01510 --help              print this message and exit.\n\
01511 --version           print version number and exit.\n\
01512 "
01513 
01514 void usage P1C(FILE *, f)
01515 {
01516    extern KPSEDLL char *kpse_bug_address;
01517    
01518    fputs ("Usage: afm2tfm FILE[.afm] [OPTION]... [FILE[.tfm]]\n", f);
01519    fputs (USAGE, f);
01520    putc ('\n', f);
01521    fputs (kpse_bug_address, f);
01522 }
01523 #else /* ! KPATHSEA */
01524 void usage P1C(FILE *, f)
01525 {
01526    (void)fprintf(f,
01527  "afm2tfm 8.1, Copyright 1990-97 by Radical Eye Software\n") ;
01528    (void)fprintf(f,
01529  "Usage: afm2tfm foo[.afm] [-O] [-u] [-v|-V bar[.vpl]]\n") ;
01530    (void)fprintf(f,
01531  "                 [-e expansion] [-s slant] [-c capheight]\n") ;
01532    (void)fprintf(f,
01533  "                 [-p|-t|-T encodingfile] [foo[.tfm]]\n") ;
01534 }
01535 #endif
01536 
01537 #define CHECKARG3 if (argc < 4) { usage(stderr); exit(1); }
01538 
01539 void
01540 openfiles P2C(int, argc, char **, argv)
01541 {
01542 #ifndef KPATHSEA
01543    register int lastext ;
01544 #endif
01545    register int i ;
01546    char *p ;
01547    int arginc ;
01548 
01549    tfmout = (FILE *)NULL ;
01550 
01551    if (argc == 1) {
01552       usage(stdout) ;
01553       exit(0) ;
01554    }
01555 
01556 #if defined(MSDOS) || defined(OS2) || defined(ATARIST)
01557    /* Make VPL file identical to that created under Unix */
01558    (void)sprintf(titlebuf, "afm2tfm %s", argv[1]) ;
01559 #else
01560 #ifdef VMCMS
01561    /* Make VPL file identical to that created under Unix */
01562    (void)sprintf(titlebuf, "afm2tfm %s", argv[1]) ;
01563 #else
01564    (void)sprintf(titlebuf, "%s %s", argv[0], argv[1]) ;
01565 #endif
01566 #endif
01567    (void)strcpy(inname, argv[1]) ;
01568 #ifdef KPATHSEA
01569    if (find_suffix(inname) == NULL)
01570        (void)strcat(inname, ".afm") ;
01571 #else
01572    lastext = -1 ;
01573    for (i=0; inname[i]; i++)
01574       if (inname[i] == '.')
01575          lastext = i ;
01576       else if (inname[i] == '/' || inname[i] == ':')
01577          lastext = -1 ;
01578    if (lastext == -1) (void)strcat(inname, ".afm") ;
01579 #endif
01580    while (argc>2 && *argv[2]=='-') {
01581       arginc = 2 ;
01582       i = argv[2][1] ;
01583       if (i == '/')
01584          i = argv[2][2] - 32 ; /* /a ==> A for VMS */
01585       switch (i) {
01586 case 'V': makevpl++ ;
01587 case 'v': makevpl++ ;
01588          CHECKARG3
01589          (void)strcpy(outname, argv[3]) ;
01590 #ifdef KPATHSEA
01591         if (find_suffix(outname) == NULL)
01592            (void)strcat(outname, ".vpl") ;
01593 #else
01594          lastext = -1 ;
01595          for (i=0; outname[i]; i++)
01596             if (outname[i] == '.')
01597                lastext = i ;
01598             else if (outname[i] == '/' || outname[i] == ':')
01599                lastext = -1 ;
01600          if (lastext == -1) (void)strcat(outname, ".vpl") ;
01601 #endif
01602 #ifndef VMCMS
01603 #ifndef ATARIST
01604          if ((vplout=fopen(outname, WRITEBIN))==NULL)
01605 #else
01606          if ((vplout=fopen(outname, "w"))==NULL)
01607 #endif
01608 #else
01609          if ((vplout=fopen(outname, "w"))==NULL)
01610 #endif
01611             error("! can't open vpl output file") ;
01612          break ;
01613 case 'e': CHECKARG3
01614           if (sscanf(argv[3], "%f", &efactor)==0 || efactor<0.01)
01615             error("! Bad extension factor") ;
01616          efactorparam = argv[3] ;
01617          break ;
01618 case 'c':
01619          CHECKARG3
01620          if (sscanf(argv[3], "%f", &capheight)==0 || capheight<0.01)
01621             error("! Bad small caps height") ;
01622          break ;
01623 case 's':
01624          CHECKARG3
01625          if (sscanf(argv[3], "%f", &slant)==0)
01626             error("! Bad slant parameter") ;
01627          slantparam = argv[3] ;
01628          break ;
01629 case 'P':
01630 case 'p':
01631          CHECKARG3
01632          inenname = argv[3] ;
01633          break ;
01634 case 'T':
01635          CHECKARG3
01636          inenname = outenname = argv[3] ;
01637          break ;
01638 case 't':
01639          CHECKARG3
01640          outenname = argv[3] ;
01641          break ;
01642 case 'O':
01643          forceoctal = 1 ;
01644          arginc = 1 ;
01645          break ;
01646 case 'u':
01647          pedantic = 1 ;
01648          arginc = 1 ;
01649          break ;
01650 default: (void)fprintf(stderr, "Unknown option %s %s will be ignored.\n",
01651                          argv[2], argv[3]) ;
01652       }
01653       for (i=0; i<arginc; i++) {
01654          (void)sprintf(titlebuf + strlen(titlebuf), " %s", argv[2]) ;
01655          argv++ ;
01656          argc-- ;
01657       }
01658    }
01659 
01660 #ifdef KPATHSEA
01661    afmin = kpse_open_file (inname, kpse_afm_format);
01662 #else /* ! KPATHSEA */
01663    if ((afmin=fopen(inname, "r"))==NULL)
01664       error("! can't open afm input file") ;
01665 #endif /* KPATHSEA */
01666    SET_BINARY(fileno(afmin)) ;
01667 
01668    if (argc>3 || (argc==3 && *argv[2]=='-')) {
01669      error("! need at most two non-option arguments") ;
01670      usage(stderr) ;
01671    }
01672 
01673    if (argc == 2) (void)strcpy(outname, inname) ;
01674    else (void)strcpy(outname, argv[2]) ;
01675 
01676 #ifdef KPATHSEA
01677    if ((p = find_suffix(outname)) != NULL)
01678       *(p-1) = 0;
01679    (void)strcat(outname, ".tfm") ;
01680    if (tfmout == NULL && (tfmout=fopen(outname, WRITEBIN))==NULL)
01681       error("! can't open tfm output file") ;
01682 /*
01683  *   Now we strip off any directory information, so we only use the
01684  *   base name in the vf file.
01685  */
01686    if (p == NULL)
01687      p = find_suffix(outname);
01688    *(p-1) = 0;
01689 
01690    p = (char *)xbasename(outname) ;
01691    strcpy(tmpstr, p);        /* be careful, p and outname are overlapping */
01692    strcpy(outname, tmpstr);
01693 #else
01694    lastext = -1 ;
01695    for (i=0; outname[i]; i++)
01696       if (outname[i] == '.')
01697          lastext = i ;
01698       else if (outname[i] == '/' || outname[i] == ':' || outname[i] == '\\')
01699          lastext = -1 ;
01700    if (argc == 2) {
01701       outname[lastext] = 0 ;
01702       lastext = -1 ;
01703    }
01704    if (lastext == -1) {
01705       lastext = strlen(outname) ;
01706       (void)strcat(outname, ".tfm") ;
01707    }
01708    if (tfmout == NULL && (tfmout=fopen(outname, WRITEBIN))==NULL)
01709       error("! can't open tfm output file") ;
01710    outname[lastext] = 0 ;
01711 /*
01712  *   Now we strip off any directory information, so we only use the
01713  *   base name in the vf file.  We accept any of /, :, or \ as directory
01714  *   delimiters, so none of these are available for use inside the
01715  *   base name; this shouldn't be a problem.
01716  */
01717    for (i=0, lastext=0; outname[i]; i++)
01718       if (outname[i] == '/' || outname[i] == ':' || outname[i] == '\\')
01719          lastext = i + 1 ;
01720    if (lastext)
01721       strcpy(outname, outname + lastext) ;
01722 #endif
01723 }
01724 /*
01725  *   Some routines to remove kerns that match certain patterns.
01726  */
01727 struct kern *rmkernmatch P2C(struct kern *, k, char *, s)
01728 {
01729    struct kern *nkern ;
01730 
01731    while (k && strcmp(k->succ, s)==0)
01732       k = k->next ;
01733    if (k) {
01734       for (nkern = k; nkern; nkern = nkern->next)
01735          while (nkern->next && strcmp(nkern->next->succ, s)==0)
01736             nkern->next = nkern->next->next ;
01737    }
01738    return k ;
01739 }
01740 /*
01741  *   Recursive to one level.
01742  */
01743 void rmkern P3C(char *, s1, char *, s2, struct adobeinfo *, ai)
01744 {
01745    if (ai == 0) {
01746       if (strcmp(s1, "*") == 0) {
01747          for (ai=adobechars; ai; ai = ai->next)
01748             rmkern(s1, s2, ai) ;
01749          return ;
01750       } else {
01751          ai = findadobe(s1) ;
01752          if (ai == 0)
01753             return ;
01754       }
01755    }
01756    if (strcmp(s2, "*")==0)
01757       ai->kerns = 0 ; /* drop them on the floor */
01758    else
01759       ai->kerns = rmkernmatch(ai->kerns, s2) ;
01760 }
01761 
01762 /* Make the kerning for character S1 equivalent to that for S2.
01763    If either S1 or S2 do not exist, do nothing.
01764    If S1 already has kerning, do nothing.  */
01765 void
01766 addkern P2C(char *, s1, char *, s2)
01767 {
01768   struct adobeinfo *ai1 = findadobe (s1);
01769   struct adobeinfo *ai2 = findadobe (s2);
01770   if (ai1 && ai2 && !ai1->kerns) {
01771     /* Put the new one at the head of the list, since order is immaterial.  */
01772     struct adobeptr *ap 
01773       = (struct adobeptr *) mymalloc((unsigned long)sizeof(struct adobeptr));
01774     ap->next = ai2->kern_equivs;
01775     ap->ch = ai1;
01776     ai2->kern_equivs = ap;
01777   }
01778 }
01779 int sawligkern ;
01780 /*
01781  *   Reads a ligkern line, if this is one.  Assumes the first character
01782  *   passed is `%'.
01783  */
01784 void checkligkern P1C(char *, s)
01785 {
01786    char *oparam = param ;
01787    char *mlist[5] ;
01788    int n ;
01789 
01790    s++ ;
01791    while (*s && *s <= ' ')
01792       s++ ;
01793    if (strncmp(s, "LIGKERN", 7)==0) {
01794       sawligkern = 1 ;
01795       s += 7 ;
01796       while (*s && *s <= ' ')
01797          s++ ;
01798       param = s ;
01799       while (*param) {
01800          for (n=0; n<5;) {
01801             if (*param == 0)
01802                break ;
01803             mlist[n] = paramstring() ;
01804             if (strcmp(mlist[n], ";") == 0)
01805                break ;
01806             n++ ;
01807          }
01808          if (n > 4)
01809             error("! too many parameters in lig kern data") ;
01810          if (n < 3)
01811             error("! too few parameters in lig kern data") ;
01812          if (n == 3 && strcmp(mlist[1], "{}") == 0) { /* rmkern command */
01813             rmkern(mlist[0], mlist[2], (struct adobeinfo *)0) ;
01814          } else if (n == 3 && strcmp(mlist[1], "<>") == 0) { /* addkern */
01815             addkern(mlist[0], mlist[2]) ;
01816          } else if (n == 3 && strcmp(mlist[0], "||") == 0 &&
01817                               strcmp(mlist[1], "=") == 0) { /* bc command */
01818             struct adobeinfo *ai = findadobe("||") ;
01819 
01820             if (boundarychar != -1)
01821                error("! multiple boundary character commands?") ;
01822             if (sscanf(mlist[2], "%d", &n) != 1)
01823                error("! expected number assignment for boundary char") ;
01824             if (n < 0 || n > 255)
01825                error("! boundary character number must be 0..255") ;
01826             boundarychar = n ;
01827             if (ai == 0)
01828                error("! internal error: boundary char") ;
01829             ai->texnum = n ; /* prime the pump, so to speak, for lig/kerns */
01830          } else if (n == 4) {
01831             int op = -1 ;
01832             struct adobeinfo *ai ;
01833 
01834             for (n=0; encligops[n]; n++)
01835                if (strcmp(mlist[2], encligops[n])==0) {
01836                   op = n ;
01837                   break ;
01838                }
01839             if (op < 0)
01840                error("! bad ligature op specified") ;
01841             if (0 != (ai = findadobe(mlist[0]))) {
01842                struct lig *lig ;
01843 
01844                if (findadobe(mlist[2]))     /* remove coincident kerns */
01845                   rmkern(mlist[0], mlist[1], ai) ;
01846                if (strcmp(mlist[3], "||") == 0)
01847                   error("! you can't lig to the boundary character!") ;
01848                if (! fixedpitch) { /* fixed pitch fonts get *0* ligs */
01849                   for (lig=ai->ligs; lig; lig = lig->next)
01850                      if (strcmp(lig->succ, mlist[1]) == 0)
01851                         break ; /* we'll re-use this structure */
01852                   if (lig == 0) {
01853                      lig = newlig() ;
01854                      lig->succ = newstring(mlist[1]) ;
01855                      lig->next = ai->ligs ;
01856                      ai->ligs = lig ;
01857                   }
01858                   lig->sub = newstring(mlist[3]) ;
01859                   lig->op = op ;
01860                   if (strcmp(mlist[1], "||")==0) {
01861                      lig->boundleft = 1 ;
01862                      if (strcmp(mlist[0], "||")==0)
01863                         error("! you can't lig boundarychar boundarychar!") ;
01864                   } else
01865                      lig->boundleft = 0 ;
01866                }
01867             }
01868          } else
01869             error("! bad form in LIGKERN command") ;
01870       }
01871    }
01872    param = oparam ;
01873 }
01874 /*
01875  *   Here we get a token from the AFM file.  We parse just as much PostScript
01876  *   as we expect to find in an encoding file.  We allow commented lines and
01877  *   names like 0, .notdef, _foo_.  We do not allow //abc.
01878  */
01879 char smbuffer[100] ;    /* for tokens */
01880 char *gettoken() {
01881    char *p, *q ;
01882 
01883    while (1) {
01884       while (param == 0 || *param == 0) {
01885          if (getline() == 0)
01886             error("! premature end in encoding file") ;
01887          for (p=buffer; *p; p++)
01888             if (*p == '%') {
01889                if (ignoreligkern == 0)
01890                   checkligkern(p) ;
01891                *p = 0 ;
01892                break ;
01893             }
01894       }
01895       while (*param && *param <= ' ')
01896          param++ ;
01897       if (*param) {
01898          if (*param == '[' || *param == ']' ||
01899              *param == '{' || *param == '}') {
01900             smbuffer[0] = *param++ ;
01901             smbuffer[1] = 0 ;
01902             return smbuffer ;
01903          } else if (*param == '/' || *param == '-' || *param == '_' ||
01904                     *param == '.' ||
01905                     ('0' <= *param && *param <= '9') ||
01906                     ('a' <= *param && *param <= 'z') ||
01907                     ('A' <= *param && *param <= 'Z')) {
01908             smbuffer[0] = *param ;
01909             for (p=param+1, q=smbuffer+1;
01910                         *p == '-' || *p == '_' || *p == '.' ||
01911                         ('0' <= *p && *p <= '9') ||
01912                         ('a' <= *p && *p <= 'z') ||
01913                         ('A' <= *p && *p <= 'Z'); p++, q++)
01914                *q = *p ;
01915             *q = 0 ;
01916             param = p ;
01917             return smbuffer ;
01918          }
01919       }
01920    }
01921 }
01922 void getligkerndefaults() {
01923    int i ;
01924 
01925    for (i=0; staticligkern[i]; i++) {
01926       strcpy(buffer, staticligkern[i]) ;
01927       strcpy(obuffer, staticligkern[i]) ;
01928       param = buffer ;
01929       checkligkern(buffer) ;
01930    }
01931 }
01932 /*
01933  *   This routine reads in an encoding file, given the name.  It returns
01934  *   the final total structure.  It performs a number of consistency checks.
01935  */
01936 struct encoding *readencoding P1C(char *, enc)
01937 {
01938    char *p ;
01939    int i ;
01940    struct encoding *e =
01941       (struct encoding *)mymalloc((unsigned long)sizeof(struct encoding)) ;
01942 
01943    sawligkern = 0 ;
01944    if (afmin)
01945       error("! oops; internal afmin error") ;
01946    if (enc) {
01947 #ifdef KPATHSEA
01948      afmin = kpse_open_file(enc, kpse_enc_format);
01949 #else
01950       afmin = fopen(enc, "r") ;
01951 #endif
01952       SET_BINARY(fileno(afmin)) ;
01953       param = 0 ;
01954       if (afmin == 0)
01955 #ifdef KPATHSEA
01956          FATAL1 ("couldn't open encoding file `%s'", enc) ;
01957 #else
01958          error("! couldn't open that encoding file") ;
01959 #endif
01960       p = gettoken() ;
01961       if (*p != '/' || p[1] == 0)
01962          error("! first token in encoding must be literal encoding name") ;
01963       e->name = newstring(p+1) ;
01964       p = gettoken() ;
01965       if (strcmp(p, "["))
01966          error("! second token in encoding must be mark ([) token") ;
01967       for (i=0; i<256; i++) {
01968          p = gettoken() ;
01969          if (*p != '/' || p[1] == 0)
01970             error("! tokens 3 to 257 in encoding must be literal names") ;
01971          e->vec[i] = newstring(p+1) ;
01972       }
01973       p = gettoken() ;
01974       if (strcmp(p, "]"))
01975          error("! token 258 in encoding must be make-array (])") ;
01976       while (getline()) {
01977          for (p=buffer; *p; p++)
01978             if (*p == '%') {
01979                if (ignoreligkern == 0)
01980                   checkligkern(p) ;
01981                *p = 0 ;
01982                break ;
01983             }
01984       }
01985       fclose(afmin) ;
01986       afmin = 0 ;
01987       if (ignoreligkern == 0 && sawligkern == 0)
01988          getligkerndefaults() ;
01989    } else {
01990       e = &staticencoding ;
01991       getligkerndefaults() ;
01992    }
01993    param = 0 ;
01994    return e ;
01995 }
01996 /*
01997  *   This routine prints out the line that needs to be added to psfonts.map.
01998  */
01999 #ifndef VMCMS
02000 void conspsfonts() {
02001    (void)printf("%s %s", outname,
02002    fontname) ;
02003 #else /* VM/CMS: fontname is ascii, so we use ebfontname */
02004 void conspsfonts() {
02005    (void)printf("%s %s", outname,
02006    ebfontname) ;
02007 #endif
02008    if (slantparam || efactorparam || inenname) {
02009       (void)printf(" \"") ;
02010       if (slantparam)
02011          (void)printf(" %s SlantFont", slantparam) ;
02012       if (efactorparam)
02013          (void)printf(" %s ExtendFont", efactorparam) ;
02014       if (inenname)
02015          (void)printf(" %s ReEncodeFont", inencoding->name) ;
02016       (void)printf(" \"") ;
02017       if (inenname)
02018          (void)printf(" <%s", inenname) ;
02019    }
02020    (void)printf("\n") ;
02021 }
02022 #ifndef VMS
02023 int
02024 #endif
02025 main P2C(int, argc, char **, argv)
02026 {
02027    int i ;
02028 
02029 #ifdef KPATHSEA
02030    kpse_set_program_name (argv[0], "afm2tfm");
02031 
02032    if (argc == 1) {
02033       fputs ("afm2tfm: Need at least one file argument.\n", stderr);
02034       fputs ("Try `afm2tfm --help' for more information.\n", stderr);
02035       exit(1);
02036    }     
02037    if (argc == 2) {
02038       if (strcmp (argv[1], "--help") == 0) {
02039         usage (stdout);
02040         exit (0);
02041       } else if (strcmp (argv[1], "--version") == 0) {
02042         version (stdout);
02043         exit (0);
02044       }
02045    }
02046 #endif /* KPATHSEA */
02047    for (i=0; i<256; i++)
02048       nexttex[i] = -1 ; /* encoding chains have length 0 */
02049    tfmdata = (long *)mymalloc((unsigned long)40000L) ;
02050    openfiles(argc, argv) ;
02051    readadobe() ;
02052    if (fontspace == 0) {
02053       struct adobeinfo *ai ;
02054 
02055       if (0 != (ai = findadobe("space")))
02056          fontspace = ai->width ;
02057       else if (adobeptrs[32])
02058          fontspace = adobeptrs[32]->width ;
02059       else
02060          fontspace = transform(500, 0) ;
02061    }
02062    handlereencoding() ;
02063    buildtfm() ;
02064    writetfm() ;
02065    conspsfonts() ;
02066    if (makevpl) {
02067       assignchars() ;
02068       if (makevpl>1) upmap() ;
02069       writevpl() ;
02070    }
02071    return 0 ;
02072    /*NOTREACHED*/
02073 }
02074