/* vpltovpl.c. version 1. december 1990 version 2. january 1992 version 3. may 1992 version 4. dec 1992 version 5. dec 28 1992 version 6. may 20 1993. removed progress indicators. put back with -DDEBUG version 7. may 25 1993. cleaned up and re-used generation of extra file for dotlessj only (activated by -DSPECIAL) version 8. july 12 1993. redo some of virtual font code; and generate the dotlessj missing char with vpl rather than using a tiny PS font version 9. july 14 1993. add in code to check if we are an artificial small caps font, and do things right for that by Sebastian Rahtz spqr@minster.york.ac.uk (thanks also to Alexander Samarin for suggestions; and Michael Doob and Craig Platt for ideas on how to do dotlessj) Take an existing .vpl file, create extra characters for new composite characters for extended TeX layout, and add them to the end of the file [ where necessary write a tiny new font metric file for extra characters; abandoned in version 8 ] Parameters: 1) name of vpl file (which is going to be overwritten) 2) name of original AFM file a quite dreadfully written C program converted from an Icon program: -------------------------------------------------------- # vplovx.icn version 1 # # Sebastian Rahtz October 1990 # -------------------------------------------------------- bits pinched from other people. notably the `findchar' and `newchar' functions, with associated material, taken from afm2tfm almost verbatim */ #include "vpltovpl.h" char vplname[LINELENGTH], afmname[LINELENGTH]; char command[LINELENGTH], plname[LINELENGTH]; char basefont[100]; float uppergap,lowergap = -1.0 ; FILE *vplfile, *afmfile, *plfile; char entry[MAXENTRY]; int SCFont = 0; float fontat=.8; struct character { struct character *next; char *name; float width,height,depth,charic; } *chars,*vchars[MAXCHARS] ; /*---------------------------*/ struct character * findchar(p) char *p ; { register struct character *ai ; for (ai=chars; ai; ai = ai->next) { if (strcmp(p, ai->name)==0) return(ai) ; } return(NULL) ; } /*--------------------------*/ float width(key) char *key; { register struct character *ai; ai = findchar(key); if (ai == NULL) { #ifdef DEBUG fprintf(stderr,"No width for %s\n",key); #endif return (0); } else return (ai->width); } /*--------------------------*/ float height(key) char *key; { register struct character *ai; ai = findchar(key); if (ai == NULL) { #ifdef DEBUG fprintf(stderr,"No height for %s\n",key); #endif return (0); } else return (ai->height); } /*--------------------------*/ float depth(key) char *key; { register struct character *ai; ai = findchar(key); if (ai == NULL) { #ifdef DEBUG fprintf(stderr,"No depth for %s\n",key); #endif return (0); } else return (ai->depth); } /*--------------------------*/ float charic(key) char *key; { register struct character *ai; ai = findchar(key); if (ai == NULL) { #ifdef DEBUG fprintf(stderr,"No charic for %s\n",key); #endif return (0); } else return (ai->charic); } /*--------------------------*/ void error(s) register char *s ; { extern void exit() ; (void)fprintf(stderr, "%s\n", s) ; if (*s == '!') exit(1) ; } /*--------------------------*/ char * mymalloc(len) unsigned long len ; { register char *p ; int i ; #ifdef SMALLMALLOC if (len > 65500L) error("! can't allocate more than 64K!") ; #endif p = malloc((unsigned)len) ; if (p==NULL) error("! out of memory") ; for (i=0; iwidth = 0 ; ai->name = NULL ; ai->height = 0 ; ai->depth = 0 ; ai->charic = 0 ; ai->next = chars ; chars = ai ; return(ai) ; } /*--------------------------*/ int count(line) char *line; { /* count the parentheses in a line, add +1 for a '(', -1 for a ')' */ char *p; int cnt = 0; for (p=line; *p; p++) { if (*p=='(') cnt += 1; if (*p==')') cnt -= 1; } return(cnt); } #ifndef MSDOS /*--------------------------*/ float max(float a, float b) { if (a > b ) return (a) ; else return (b) ; } #endif /*--------------------------*/ void vchar(charnum,charname,charwd,charht,chardp, charic,oldchar,accent,moveright,moveup,WhichFont) int charnum; /* number of new character*/ char *charname; /* name of new character*/ float charwd; /* width of character*/ float charht; /* height of character*/ float chardp; /* depth of character*/ float charic; /* italic correction of character*/ char *oldchar; /* number of old character*/ char *accent; /* string of accent number*/ float moveright; /* (can be negative)*/ float moveup; /* (can be negative)*/ int WhichFont ; /* for small caps. 0 or 1 */ { #ifdef DEBUG fprintf(stderr,"generate character %s from %s and %s: %f %f\n", charname,oldchar,accent,moveup,moveright); #endif fprintf(vplfile,"(CHARACTER O %d (comment %s: %.2f %.2f)\n",charnum,charname,moveright,moveup); if (charwd != 0 ) fprintf(vplfile," (CHARWD R %.2f)\n",charwd); if (charht != 0 ) fprintf(vplfile," (CHARHT R %.2f)\n",charht); if (chardp != 0 ) fprintf(vplfile," (CHARDP R %.2f)\n",chardp); if (charic != 0 ) fprintf(vplfile," (CHARIC R %.2f)\n",charic); /* WhichFont will be 0 normally, but 1 if we are a small caps font */ fprintf(vplfile," (MAP (SELECTFONT D %d)\n",WhichFont); fprintf(vplfile," (SETCHAR %s)\n",oldchar); if (moveright != 0.0) fprintf(vplfile," (MOVERIGHT R %.2f)\n",-moveright); if (moveup != 0.0 ) fprintf(vplfile," (MOVEUP R %.2f)\n",moveup); fprintf(vplfile," (SETCHAR %s)\n",accent); fprintf(vplfile," )\n"); fprintf(vplfile," )\n"); } /*----------------------*/ void upperacc(number,c,accent,name) int number; char *c,*accent,*name; { float xdepth,xheight,xmoveup; #ifdef DEBUG fprintf(vplfile,"(COMMENT UPPERACC with %d: %s, %s, %s )\n",number,c,accent,name); #endif xdepth=depth(accent); if (xdepth > 0.0) /* # its an underneath accent # no need to move up */ { xheight=height(c); xmoveup=0.0; } else { xdepth=depth(c); xheight=height(accent); xmoveup=uppergap; } vchar(number, name, width(c), xheight+xmoveup, xdepth, charic(c), c, accent, (float) ( ( width(c) / 2.0 ) + ( width(accent) / 2.0 ) ), xmoveup,0); } /*--------------------------*/ void loweracc(number,c,accent,name,movedown) int number; float movedown; char *c,*accent,*name; { float moveup,adepth,xheight,xdepth,xmoveup; float CDepth,CHeight,CWidth,ADepth,AHeight,AWidth,CIc; char CharName[5]; char LastChar; strcpy(CharName,c); /* if we are in small caps, uppercase the character name */ if (SCFont == 1 ) { LastChar=CharName[strlen(CharName)-1]; CharName[strlen(CharName)-1]=toupper(LastChar); /* for a small caps font, we need to reduce the dimensions to the size of the small caps font; we have derived this from the vpl file earlier as `fontat' */ ADepth=depth(accent) * fontat; AWidth=width(accent) * fontat ; AHeight=height(accent) * fontat + SC_ACCENT_RAISE ; CWidth=width(CharName) * fontat ; CHeight=height(CharName) * fontat ; CDepth=depth(CharName) * fontat ; CIc=charic(CharName) * fontat ; } else { ADepth=depth(accent); AWidth=width(accent) ; AHeight=height(accent) ; CWidth=width(CharName) ; CHeight=height(CharName) ; CDepth=depth(CharName) ; CIc=charic(CharName) ; } #ifdef DEBUG fprintf(vplfile,"(COMMENT LOWERACC with %d: %s, %s, %s %f)\n",number,CharName,accent,name,movedown); #endif xdepth=ADepth; if (xdepth > 0.0 ) { xheight=CHeight; xmoveup=0.0; } else { xdepth=CDepth; xheight=AHeight; xmoveup=lowergap; } if (movedown != 0.0 ) xmoveup= xmoveup+movedown; vchar(number, name, CWidth, xheight+xmoveup, xdepth, CIc, CharName, accent, (float) ( ( CWidth / 2.0 ) + ( AWidth / 2.0 ) ), xmoveup, SCFont ); } /*--------------------------*/ generatenormal() { char *c,*ctwo; upperacc(200,"C A",BREVE,"Abreve"); /* upperacc(201,"C A",OGONEK,"Agonek"); NOW DONE AS SPECIAL LATER*/ upperacc(202,"C C",ACUTE,"Cacute"); upperacc(203,"C C",CARON,"Ccaron"); upperacc(204,"C D",CARON,"Dcaron"); upperacc(205,"C E",CARON,"Ecaron"); upperacc(206,"C E",OGONEK,"Eogonek"); upperacc(207,"C G",BREVE,"Gbreve"); upperacc(210,"C L",ACUTE,"Lacute"); upperacc(213,"C N",ACUTE,"Nacute"); upperacc(214,"C N",CARON,"Ncaron"); upperacc(216,"C O",HUNGARUMLAUT,"Ohungarumlaut"); upperacc(217,"C R",ACUTE,"Racute"); upperacc(220,"C R",CARON,"Rcaron"); upperacc(221,"C S",ACUTE,"Sacute"); upperacc(223,"C S",CEDILLA,"Scedilla"); upperacc(224,"C T",CARON,"Tcaron"); upperacc(225,"C T",CEDILLA,"Tcedilla"); upperacc(226,"C U",HUNGARUMLAUT,"Uhungarumlaut"); upperacc(227,"C U",RING,"Uring "); upperacc(231,"C Z",ACUTE,"Zacute"); upperacc(233,"C Z",DOTACCENT,"Zdotaccent"); upperacc(235,"C I",DOTACCENT,"Idotaccent"); if (SCFont == 1) { /* small caps capital D bar hack. */ c = "O 137" ; ctwo = "C D"; fprintf(vplfile,"(CHARACTER O 236 \n"); fprintf(vplfile," (CHARWD R %.2f)\n",width(ctwo)*fontat); fprintf(vplfile," (CHARHT R %.2f)\n",max(height(c),height(ctwo))*fontat); fprintf(vplfile," (CHARIC R %.2f)\n",max(charic(c),charic(ctwo))*fontat); fprintf(vplfile," (CHARDP R %.2f)\n",max(depth(c),depth(ctwo))*fontat); fprintf(vplfile," (MAP"); fprintf(vplfile," (SELECTFONT D 1)\n"); fprintf(vplfile," (PUSH)\n"); fprintf(vplfile," (MOVERIGHT R -100)\n"); fprintf(vplfile," (MOVEDOWN R -75)\n"); fprintf(vplfile," (SETCHAR O 25)\n"); fprintf(vplfile," (POP)\n"); fprintf(vplfile," (SETCHAR C D)\n"); fprintf(vplfile," )\n"); fprintf(vplfile," )\n"); } else loweracc(236,"C d",BAR,"dbar",325.0); loweracc(240,"C a",BREVE,"abreve",0.0); if (SCFont == 1) { char *c,*ctwo; c="C A"; ctwo=OGONEK; vchar(241,"aogonek",width(c)*fontat,height(c)*fontat,depth(ctwo)*fontat,charic(c)*fontat, c,ctwo,width(c)*fontat * .25,0.0,1); } else loweracc(241,"C a",OGONEK,"aogonek",0.0); loweracc(242,"C c",ACUTE,"cacute",0.0); loweracc(243,"C c",CARON,"ccaron",0.0); loweracc(245,"C e",CARON,"ecaron",0.0); loweracc(246,"C e",OGONEK,"eogonek",0.0); loweracc(247,"C g",BREVE,"gbreve",0.0); if (SCFont == 1) loweracc(250,"C l",ACUTE,"lacute",100.0); else loweracc(250,"C l",ACUTE,"lacute",200.0); loweracc(253,"C n",ACUTE,"nacute",0.0); loweracc(254,"C n",CARON,"ncaron",0.0); loweracc(256,"C o",HUNGARUMLAUT,"ohungarumlaut",0.0); loweracc(257,"C r",ACUTE,"racute",0.0); loweracc(260,"C r",CARON,"rcaron",0.0); loweracc(261,"C s",ACUTE,"sacute",0.0); loweracc(263,"C s",CEDILLA,"scedilla",0.0); loweracc(265,"C t",CEDILLA,"tcedilla",0.0); loweracc(266,"C u",HUNGARUMLAUT,"uhungarumlaut",0.0); loweracc(267,"C u",RING,"uring ",0.0); loweracc(271,"C z",ACUTE,"zacute",0.0); loweracc(273,"C z",DOTACCENT,"zdotaccent",0.0); } /*--------------------------*/ generatespecial() { register struct character *ai ; char *c,*ctwo; c="C A"; ctwo=OGONEK; vchar(201,"Aogonek",width(c),height(c),depth(ctwo),charic(c), c,ctwo,width(c) *0.35,0.0,0); c="C I"; ctwo="C J"; vchar(234,"IJ",(width(c)+width(ctwo)), max(height(c),height(ctwo)),max(depth(c),depth(ctwo)), max(charic(c),charic(ctwo)),c,ctwo,0.0,0.0,0); if (SCFont == 1 ) { c="C I"; ctwo="C J" ; vchar(274,"ij",(width(c)+width(ctwo)*fontat)-100.0, max(height(c),height(ctwo))*fontat,max(depth(c),depth(ctwo))*fontat, max(charic(c),charic(ctwo))*fontat,c,ctwo,50.0,0.0,SCFont); c="C r"; ai = findchar("O 32"); if (ai == NULL) ctwo="C j"; else ctwo="O 32"; vchar(215,"Eng",(width(c)+width(ctwo))-100.0 , max(height(c),height(ctwo)),max(depth(c),depth(ctwo)), max(charic(c),charic(ctwo)),c,ctwo,100.0,-50.0,0); } else { c="C i"; ctwo="C j" ; vchar(274,"ij",(width(c)+width(ctwo))-100.0, max(height(c),height(ctwo)),max(depth(c),depth(ctwo)), max(charic(c),charic(ctwo)),c,ctwo,50.0,0.0,SCFont); ai = findchar("O 32"); if (ai == NULL) ctwo="C j"; else ctwo="O 32"; c="C r"; vchar(215,"Eng",(width(c)+width(ctwo))-100.0 , max(height(c),height(ctwo)),max(depth(c),depth(ctwo)), max(charic(c),charic(ctwo)),c,ctwo,100.0,-50.0,0); } c="C r"; ai = findchar("O 32"); if (ai == NULL) ctwo="C j"; else ctwo="O 32"; vchar(255,"eng",(width(c)+width(ctwo))-100.0, max(height(c),height(ctwo)),max(depth(c),depth(ctwo)), max(charic(c),charic(ctwo)),c,ctwo,100.0,-50.0,0); c="C S"; vchar(337,"Germandbls",width(c)*2,height(c),depth(c),charic(c),c,c,0.0,0.0,0); c="C L"; ctwo=QUOTE; vchar(211,"Lquote",width(c),height(c),depth(c),charic(c),c,ctwo,200.0,-50.0,0); if (SCFont == 1 ) loweracc(244,"C D",CARON,"dquote",0.0); else { c="C d"; ctwo=QUOTE; vchar(244,"dquote",width(c),height(c),depth(c),charic(c),c,ctwo, 100.0,0.0,SCFont); } if (SCFont == 1 ) loweracc(264,"C T",CARON,"tquote",0.0); else { c="C t"; ctwo=QUOTE; vchar(264,"tquote",width(c),height(c),depth(c),charic(c),c,ctwo, 100.0,0.0,SCFont); } if (SCFont == 1 ) c="C L"; else c="C l"; ctwo=QUOTE; vchar(251,"lquote",width(c),height(c),depth(c),charic(c),c,ctwo,100.0,0.0,SCFont); fprintf(vplfile,"(CHARACTER O 027 (comment cwm)\n"); fprintf(vplfile," (CHARWD R 0)\n"); fprintf(vplfile," (CHARHT R 0)\n"); fprintf(vplfile," (CHARDP R 0)\n"); fprintf(vplfile," (MAP"); fprintf(vplfile," (MOVERIGHT R 0)\n"); fprintf(vplfile," )\n"); fprintf(vplfile," )\n"); /* the visible space character; must be same width as numbers; constructed from 3 rules. */ c="C 0"; fprintf(vplfile,"(CHARACTER O 040 (comment visiblespace)\n"); fprintf(vplfile," (CHARWD R %.2f)\n",width(c)); fprintf(vplfile," (CHARHT R 500)\n"); fprintf(vplfile," (CHARDP R 0)\n"); fprintf(vplfile," (MAP"); fprintf(vplfile," (MOVERIGHT R 100)\n"); fprintf(vplfile," (SETRULE R 400 R 35)\n"); fprintf(vplfile," (SETRULE R 35 R 400)\n"); fprintf(vplfile," (SETRULE R 400 R 35)\n"); fprintf(vplfile," (MOVERIGHT R 70)\n"); fprintf(vplfile," )\n"); fprintf(vplfile," )\n"); /* now a set of characters that are found in some fonts, but need to be generated if they are not found in the AFM file */ ai = findchar("O 375"); if (ai == NULL) loweracc(375,"C y",ACUTE,"yacute",0.0); ai = findchar("O 335"); if (ai == NULL) upperacc(335,"C Y",ACUTE,"Yacute"); ai = findchar("O 320"); if (ai == NULL) { /* Eth hack. */ c = "O 137" ; ctwo = "C D"; fprintf(vplfile,"(CHARACTER O 320 (comment Eth)\n"); fprintf(vplfile," (CHARWD R %.2f)\n",width(ctwo)); fprintf(vplfile," (CHARHT R %.2f)\n",max(height(c),height(ctwo))); fprintf(vplfile," (CHARIC R %.2f)\n",max(charic(c),charic(ctwo))); fprintf(vplfile," (CHARDP R %.2f)\n",max(depth(c),depth(ctwo))); fprintf(vplfile," (MAP"); fprintf(vplfile," (PUSH)\n"); fprintf(vplfile," (MOVERIGHT R -100)\n"); fprintf(vplfile," (MOVEDOWN R -75)\n"); fprintf(vplfile," (SETCHAR O 25)\n"); fprintf(vplfile," (POP)\n"); fprintf(vplfile," (SETCHAR C D)\n"); fprintf(vplfile," )\n"); fprintf(vplfile," )\n"); } ai = findchar("O 336"); if (ai == NULL) { c="C 0"; fprintf(vplfile,"(CHARACTER O 336 (comment Thorn )\n"); fprintf(vplfile," (CHARWD R %.2f)\n",width(c)); fprintf(vplfile," (CHARHT R 700)\n"); fprintf(vplfile," (CHARDP R 0)\n"); fprintf(vplfile," (MAP"); fprintf(vplfile," (SETRULE R 500 R %.2f)\n",width(c)); fprintf(vplfile," )\n"); fprintf(vplfile," )\n"); /* Thorn junk it c = "C l" ; ctwo = "C b"; fprintf(vplfile,"(CHARACTER O 336 (comment Thorn)\n"); fprintf(vplfile," (CHARWD R %.2f)\n",width(ctwo)); fprintf(vplfile," (CHARHT R %.2f)\n",max(height(c),height(ctwo))); fprintf(vplfile," (CHARIC R %.2f)\n",max(charic(c),charic(ctwo))); fprintf(vplfile," (CHARDP R %.2f)\n",max(depth(c),depth(ctwo))); fprintf(vplfile," (MAP"); fprintf(vplfile," (MOVEDOWN R 400)\n"); fprintf(vplfile," (SETCHAR C l)\n"); fprintf(vplfile," (MOVEDOWN R -400)\n"); fprintf(vplfile," (MOVERIGHT R -%.2f)\n",width(c)); fprintf(vplfile," (SETCHAR C b)\n"); fprintf(vplfile," )\n"); fprintf(vplfile," )\n"); */ } ai = findchar("O 360"); if (ai == NULL) { if (SCFont == 1) { /* small caps capital D bar hack. */ c = "O 137" ; ctwo = "C D"; fprintf(vplfile,"(CHARACTER O 360 \n"); fprintf(vplfile," (CHARWD R %.2f)\n",width(ctwo)*fontat); fprintf(vplfile," (CHARHT R %.2f)\n",max(height(c),height(ctwo))*fontat); fprintf(vplfile," (CHARIC R %.2f)\n",max(charic(c),charic(ctwo))*fontat); fprintf(vplfile," (CHARDP R %.2f)\n",max(depth(c),depth(ctwo))*fontat); fprintf(vplfile," (MAP"); fprintf(vplfile," (SELECTFONT D 1)\n"); fprintf(vplfile," (PUSH)\n"); fprintf(vplfile," (MOVERIGHT R -100)\n"); fprintf(vplfile," (MOVEDOWN R -75)\n"); fprintf(vplfile," (SETCHAR O 25)\n"); fprintf(vplfile," (POP)\n"); fprintf(vplfile," (SETCHAR C D)\n"); fprintf(vplfile," )\n"); fprintf(vplfile," )\n"); } else { c="C 0"; fprintf(vplfile,"(CHARACTER O 360 (comment eth)\n"); fprintf(vplfile," (CHARWD R %.2f)\n",width(c)); fprintf(vplfile," (CHARHT R 700)\n"); fprintf(vplfile," (CHARDP R 0)\n"); fprintf(vplfile," (MAP"); fprintf(vplfile," (SETRULE R 500 R %.2f)\n",width(c)); fprintf(vplfile," )\n"); fprintf(vplfile," )\n"); } /* eth junked c = "C x" ; ctwo = "C o"; fprintf(vplfile,"(CHARACTER O 360 (comment eth)\n"); fprintf(vplfile," (CHARWD R %.2f)\n",width(c)); fprintf(vplfile," (CHARHT R %.2f)\n",max(height(c),height(ctwo))); fprintf(vplfile," (CHARIC R %.2f)\n",max(charic(c),charic(ctwo))); fprintf(vplfile," (CHARDP R %.2f)\n",max(depth(c),depth(ctwo))); fprintf(vplfile," (MAP"); fprintf(vplfile," (MOVEDOWN R -400)\n"); fprintf(vplfile," (SETCHAR C x)\n"); fprintf(vplfile," (MOVEDOWN R 400)\n"); fprintf(vplfile," (MOVERIGHT R -850)\n"); fprintf(vplfile," (SETCHAR C o)\n"); fprintf(vplfile," )\n"); fprintf(vplfile," )\n"); */ } ai = findchar("O 376"); if (ai == NULL) { c="C 0"; fprintf(vplfile,"(CHARACTER O 376 (comment thorn)\n"); fprintf(vplfile," (CHARWD R %.2f)\n",width(c)); fprintf(vplfile," (CHARHT R 700)\n"); fprintf(vplfile," (CHARDP R 0)\n"); fprintf(vplfile," (MAP"); fprintf(vplfile," (SETRULE R 500 R %.2f)\n",width(c)); fprintf(vplfile," )\n"); fprintf(vplfile," )\n"); /* thorn; junked c = "C l" ; ctwo = "C b"; fprintf(vplfile,"(CHARACTER O 376 (comment thorn)\n"); fprintf(vplfile," (CHARWD R %.2f)\n",width(c)); fprintf(vplfile," (CHARHT R %.2f)\n",max(height(c),height(ctwo))); fprintf(vplfile," (CHARIC R %.2f)\n",max(charic(c),charic(ctwo))); fprintf(vplfile," (CHARDP R %.2f)\n",max(depth(c),depth(ctwo))); fprintf(vplfile," (MAP"); fprintf(vplfile," (PUSH)"); fprintf(vplfile," (MOVEDOWN R 300)\n"); fprintf(vplfile," (SETCHAR C l)\n",c); fprintf(vplfile," (MOVEDOWN R -300)\n"); fprintf(vplfile," (POP)"); fprintf(vplfile," (SETCHAR C b)\n",ctwo); fprintf(vplfile," )\n"); fprintf(vplfile," )\n"); */ } /* ff, ffi, ffl ligatures are not faked if they are not in the font; why should we make up for sloppiness of font designers? so long as the ligature table doesnt mention them, no problem (since no-one puts them in by hand, i hope) */ ai = findchar("O 32"); if (ai == NULL) { /* dotless j. tricky, as it is driver-dependent, using SPECIALs */ if (SCFont==1) { c="C J"; fprintf(vplfile,"(CHARACTER O 32 (comment dotlessj)\n"); fprintf(vplfile," (CHARWD R %.2f)\n",width(c)*fontat); fprintf(vplfile," (CHARHT R %.2f)\n",height(ctwo)*fontat); fprintf(vplfile," (CHARDP R %.2f)\n",depth(c)*fontat); fprintf(vplfile," (CHARIC R %.2f)\n",charic(c)*fontat); fprintf(vplfile," (MAP (SELECTFONT D 1)\n" ); fprintf(vplfile," (SETCHAR C J)\n"); fprintf(vplfile," )\n"); fprintf(vplfile," )\n"); } else { c="C j"; ctwo="O 31"; fprintf(vplfile,"(CHARACTER O 32 (comment dotlessj)\n"); fprintf(vplfile," (CHARWD R %.2f)\n",width(c)); fprintf(vplfile," (CHARHT R %.2f)\n",height(ctwo)); fprintf(vplfile," (CHARDP R %.2f)\n",depth(c)); fprintf(vplfile," (CHARIC R %.2f)\n",charic(c)); fprintf(vplfile," (MAP (SELECTFONT D 0)\n" ); /* first attempt was to pass a \special to dvips which draws a white circle over the dot of a j. From Doob and Platt in Proceedings of Tug93 these are absolute PostScript instructions, remember, and this has to work at any size. Doob and Platt do a 1.5pt circle which is fine for 10pt type, but what about 100pt? We will try to cope with it by doing a solid white rule above and to the right of where we are; it extends the width of the j, and the height is the difference between the height of a dotless i and a dotless j there is a problem with this; if we are already using some gray or colour command, we don't want to set the tone back to black regardless, do we... sigh. we have to have made a note earlier fprintf(vplfile," (SPECIAL ps: currentgray /DotlessJGray exch def)\n"); fprintf(vplfile," (SPECIAL ps: 1 setgray)\n"); fprintf(vplfile," (MOVEUP R %.2f)\n",height(ctwo)*1.02); fprintf(vplfile," (PUSH)\n"); fprintf(vplfile," (SETCHAR C j)\n"); fprintf(vplfile," (POP)\n"); fprintf(vplfile," (SETRULE R %.2f R %.2f)\n",height(c)-height(ctwo),width(c)); fprintf(vplfile," (SPECIAL ps: DotlessJGray setgray)\n"); but the problem with all that is that the white blob covers any accent on the dotlessj! */ /* instead we set up a clipping path which covers all of the \dotless i's height + depth of the j, ie all the j except its dot (with luck....) */ fprintf(vplfile," (SPECIAL ps: gsave newpath 0 0 moveto (\\31) true charpath flattenpath pathbbox /IHeight exch def pop pop pop grestore gsave newpath 0 0 moveto (\\152) true charpath flattenpath pathbbox pop exch /JDepth exch def /JRight exch def /JLeft exch def grestore gsave newpath)\n"); fprintf(vplfile," (PUSH)\n"); fprintf(vplfile," (MOVEDOWN R %.2f)\n",depth(c)); fprintf(vplfile," (SPECIAL ps: JLeft JDepth rmoveto JLeft neg JRight add 0 rlineto 0 JDepth neg IHeight add rlineto JLeft neg JRight add neg 0 rlineto 0 JDepth neg IHeight add neg rlineto closepath clip)\n"); fprintf(vplfile," (POP)\n"); fprintf(vplfile," (SPECIAL ps: (\\152) show grestore)\n"); fprintf(vplfile," )\n"); fprintf(vplfile," )\n"); } } } /*--------------------------*/ int getentry() /* read characters until we have a lump with a matching number of opening and closing brackets. this must be a VPL entity */ { register int c,seen,count ; char *cs; seen = count = 0 ; cs=entry; while( (c=getc(vplfile)) != EOF) { if ( c != '\n') *cs++ = c ; if (c=='(') { seen=1 ; count++;} else if (c==')') count--; if ( (seen != 0) && (count==0)) { *cs='\0'; return (0); } } return (1); } /*--------------------------*/ void process() /* get each VP entry one by one and store away the metric entries for each character */ { int x,i,charno; char *p; char *q; char name1[2]; char name2[4]; char namevalue[6]; float value; struct character *ac; while ( (x=getentry()) != 1) { if (strncmp(entry,"(CHARACTER",10) == 0) { ac = anewchar(); #ifdef DEBUG fprintf(stderr,"."); #endif sscanf(entry,"(CHARACTER %s %s",name1,name2); strcpy(namevalue,strcat(strcat(name1," "),name2)); ac->name=namespace(); strcpy(ac->name,namevalue); if (( p=strstr(entry,"CHARWD")) != NULL) sscanf(p,"CHARWD R %f",&ac->width); if ((p=strstr(entry,"CHARIC")) != NULL) sscanf(p,"CHARIC R %f",&ac->charic); if ((p=strstr(entry,"CHARHT")) != NULL) sscanf(p,"CHARHT R %f",&ac->height); if ((p=strstr(entry,"CHARDP")) != NULL) sscanf(p,"CHARDP R %f",&ac->depth); } else if (strncmp(entry,"(FAMILY ",8) == 0) { /* its a small caps font maybe; look for things like (FAMILY TeX-ptmr0-CSC) */ if ( strncmp(entry+strlen(entry)-4,"CSC)",4) == 0 ) SCFont=1; } else if (strncmp(entry,"(MAPFONT D 1",12) == 0) { /* in our small caps font, this tells us the size of the smallcaps */ if ((p=strstr(entry,"FONTAT")) != NULL) sscanf(p,"FONTAT D %d",&i); fontat = (float) i / 1000 ; lowergap= lowergap + SC_ACCENT_RAISE; } #ifdef DEBUG fprintf(stderr,"\n"); #endif } } /*--------------------------*/ void generateligs() { fprintf(vplfile,"(LIGTABLE\n"); fprintf(vplfile," (LABEL O 136 ) (COMMENT circumflex)\n"); fprintf(vplfile," (LIG C A O 302)\n"); fprintf(vplfile," (LIG C E O 312)\n"); fprintf(vplfile," (LIG C I O 316)\n"); fprintf(vplfile," (LIG C O O 324)\n"); fprintf(vplfile," (LIG C U O 333)\n"); fprintf(vplfile," (LIG C a O 342)\n"); fprintf(vplfile," (LIG C e O 352)\n"); fprintf(vplfile," (LIG C i O 356)\n"); fprintf(vplfile," (LIG C o O 364)\n"); fprintf(vplfile," (LIG C u O 373)\n"); fprintf(vplfile," (STOP)\n"); fprintf(vplfile," (LABEL O 176 ) (COMMENT tilde) \n"); fprintf(vplfile," (LIG C A O 303 )\n"); fprintf(vplfile," (LIG C N O 321 )\n"); fprintf(vplfile," (LIG C O O 325 )\n"); fprintf(vplfile," (LIG C n O 361 )\n"); fprintf(vplfile," (LIG C o O 365 )\n"); fprintf(vplfile," (LIG C a O 343 )\n"); fprintf(vplfile," (STOP)\n"); fprintf(vplfile," (LABEL O 42 ) (COMMENT dieresis)\n"); fprintf(vplfile," (LIG C Y O 230)\n"); fprintf(vplfile," (LIG C y O 270)\n"); fprintf(vplfile," (LIG C A O 304)\n"); fprintf(vplfile," (LIG C E O 313)\n"); fprintf(vplfile," (LIG C I O 317)\n"); fprintf(vplfile," (LIG C O O 326)\n"); fprintf(vplfile," (LIG C U O 334)\n"); fprintf(vplfile," (LIG C a O 344)\n"); fprintf(vplfile," (LIG C i O 357)\n"); fprintf(vplfile," (LIG C o O 366)\n"); fprintf(vplfile," (LIG C u O 374)\n"); fprintf(vplfile," (STOP)\n"); fprintf(vplfile," )\n"); return; } /*--------------------------*/ main(argc,argv) int argc; char *argv[]; { struct character *ai; int x,b1,b2,b3,b4,b5,lastext,i; char *fcopy; char line[LINELENGTH], cname1[30],cname2[30],cname3[30], *p; if (argc!=3) { fprintf(stderr,"Usage: %s vplfilename afmfilename\n",argv[0]); exit(1); } #ifdef DEBUG fprintf(stderr,"This is VPLtoVPL C version 9, July 1993\n"); #endif /* check for existence of vpl file */ (void)strcpy(vplname,argv[1]); fcopy=vplname; if ( (p=SEARCH(vplname,'.')) == (char *)NULL) strcat(vplname,".vpl"); else strcpy(p,".vpl"); if ( (vplfile = fopen(vplname,"r")) == (FILE *)NULL) { fprintf(stderr,"Can't open %s\n",vplname); exit(1); } /* open .afm file */ (void)strcat(afmname,argv[2]); if ( (afmfile = fopen(afmname,"r")) == (FILE *)NULL) { fprintf(stderr,"Can't open %s\n",afmname); exit(1); } /* get the base name of the font */ strcpy(basefont, fcopy) ; lastext = -1 ; for (i=0; basefont[i]; i++) if (basefont[i] == '.') lastext = i ; else if (basefont[i] == '/' || basefont[i] == ':') lastext = -1 ; if (lastext != -1) basefont[lastext]='\0'; /* remove the last character */ *(basefont+strlen(basefont)-1)='\0'; /* read AFM file to find correct raising of accents over uppercase and lowercase letters */ while ( fgets(line,LINELENGTH,afmfile) != (char *)NULL ) { if (lowergap > 0.0 && uppergap > 0.0) break; if (strncmp(line,"CC ",3) == 0) { /* look for lines like this: CC Aacute 2 ; PCC A 0 0 ; PCC acute 195 214 ; */ sscanf(line,"CC %s %d ; PCC %s %d %d ; PCC %s %d %d", cname1,&b1,cname2,&b2,&b3,cname3,&b4,&b5); if (strcmp(cname1,"Ucircumflex")==0) uppergap = (float)b5; else if (strcmp(cname1,"ucircumflex")==0) lowergap = (float)b5; } } #ifdef DEBUG fprintf(stderr,"read AFM file to find %f & %f, proceeding to main work\n",uppergap,lowergap); #endif process(); fclose(vplfile); #ifdef DEBUG for (ai=chars; ai; ai = ai->next) { fprintf(vplfile,"(COMMENT %s: wd %.2f ht %.2f dp %.2f ci %.2f)\n",ai->name, ai->width, ai->height, ai->depth, ai->charic ); } #endif if ( (vplfile = fopen(vplname,"a")) == (FILE *)NULL) { fprintf(stderr,"Can't open %s for update\n",vplname); exit(1); } #ifdef DEBUG fprintf(stderr,"proceeding to normal characters\n"); #endif generatenormal(); #ifdef DEBUG fprintf(stderr,"proceeding to special work\n"); #endif generatespecial(); /* i think this is getting a bit much; these do things like make "A do \"A generateligs(); */ fclose(afmfile); }