/* Copyright 1990,1991,1992,1993,1994,1995,1996,1997,1998,1999,2000 Y&Y, Inc. Copyright 2007 TeX Users Group This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* program to make up TFM files from AFM files - needs encoding vector */ /* Revised 1999 June 13 to run in DLL form */ #ifdef _WINDOWS #define NOCOMM #define NOSOUND #define NODRIVERS #define STRICT #include #endif #include #include #include #include /* for tangent */ #include #include /* for _getcwd() */ #include #include #pragma warning(disable:4032) // different type when promoted #include #pragma warning(default:4032) // different type when promoted #ifdef _WINDOWS // We must define MYLIBAPI as __declspec(dllexport) before including // afmtotfm.h, then afmtotfm.h will see that we have already // defined MYLIBAPI and will not (re)define it as __declspec(dllimport) #define MYLIBAPI __declspec(dllexport) #include "afmtotfm.h" #endif #ifdef _WINDOWS #pragma message("DLL Version") #else #pragma message("EXE Version") // #pragma warning(disable:4127) // conditional expression is constant #endif FILE *errout=stdout; /* where to send error output 97/Sep/23 */ // #ifdef _WINDOWS // #define showline(str,flag) ShowLine(str,flag); // #else // #define showline(str,flag) {if(flag){fflush(stdout);fputs(str,errout);fflush(errout);}else{fputs(str,stdout);}} // #endif #define showline(str,flag) ShowLine(str,flag) /* #include */ /* for qsort ? */ #define CONTROLBREAK /* #define DEBUGGING */ /* #define USECONTRACTION */ /* #define SHOWBASES */ #define FONTNAME_MAX 100 #define CHARNAME_MAX 100 #define MAXLINE 512 #define MAXCHRS 256 /* #define MAXCHARNAME 25 */ /* #define MAXCHARNAME 26 */ /* an experiment */ #define MAXCHARNAME 32 /* #define MAXDISTINCT 256 */ /* limit before TeX 3.0 ? */ /* #define MAXDISTINCT 512 */ /* maximum number of distinct kern values */ #define MAXDISTINCT 1024 /* maximum number of distinct kern values */ #define MAXEXTEN 256 /* max extensible table */ #define ITALICFUZZ 30.0 /* default italic fuzz */ /* #define MAXLIG 256 */ /* #define MAXLIG 2048 */ /* don't know if this is safe ? 93/Nov/23 */ #define MAXLIG 10000 /* go for broke ? 93/Nov/26 */ /* #define MAXKERN 512 */ /* #define MAXKERN 900 */ /* #define MAXKERN 1024 */ /* #define MAXKERN 1200 */ /* #define MAXKERN 2048 */ /* an experiment */ /* #define MAXKERN 10000U */ /* using far memory */ #ifdef _WIN32 #define MAXKERN 16384U #else /* A solid limit for MAXKERN is 65536 / sizeof(kernpair) or approx 10922 ? */ #define MAXKERN 10900U /* using far memory */ #endif #ifdef _WIN32 #define __far #define _fmalloc malloc #define _frealloc realloc #define _ffree free #endif #ifdef _WIN32 #define INIMEMORY 8000U /* do this in stages ? realloc ? */ #define INCMEMORY 8000U /* do this in stages ? realloc ? */ #else #define INIMEMORY 4000U /* do this in stages ? realloc ? */ #define INCMEMORY 4000U /* do this in stages ? realloc ? */ #endif #define SHOWTEXBASE /* show ligature table debugging information */ /* Following hard-wired by TeX TFM file format */ #define MAXHEIGHTS 16 #define MAXDEPTHS 16 #define MAXITALICS 64 #define XEROXCODEN 10 /* number of words set aside for coding scheme */ #define XEROXFONTN 5 /* number of words set aside for font ID */ /* may be expanded, but then FaceByte is shifted */ #define NOWIDTH -8000000 /* if no width assigned yet */ #define KERNBIT 128 /* if kern step instead of lig step */ #define STOPBIT 128 /* if last step in lig_kern program */ int fontchrs = MAXCHRS; /* 256. Set to 128 if backwardflag non-zero */ FILE *input, *output; char fn_in[FILENAME_MAX], fn_out[FILENAME_MAX]; #ifdef _WINDOWS char *appname="AFMtoTFM.DLL conversion utility"; #else char *appname="AFMtoTFM (32) conversion utility"; #endif #ifdef _WIN32 char *programversion = /* "AFMtoTFM (32) conversion utility version 3.0"; */ /* 97/Dec/4 */ /* "AFMtoTFM (32) conversion utility version 3.1"; */ /* 98/Jan/26 */ /* "AFMtoTFM (32) conversion utility version 3.1.2"; */ /* 98/Jun/30 */ /* "AFMtoTFM (32) conversion utility version 3.1.3"; */ /* 98/Aug/15 */ /* "AFMtoTFM (32) conversion utility version 3.1.4"; */ /* 98/Aug/26 */ /* "AFMtoTFM (32) conversion utility version 3.1.5"; */ /* 98/Sep/20 */ /* "AFMtoTFM (32) conversion utility version 3.1.6"; */ /* 1999/Feb/19 change in em_quad */ /* "AFMtoTFM (32) conversion utility version 3.1.7"; */ /* 1999/June/11 change in showline */ /* "version 3.2"; */ /* 1999/June/11 DLL work start */ /* "version 3.2.1"; */ /* 1999/Sep/24 LetraSet modification */ /* "version 3.2.2"; */ /* em_quad fix when emdash missing 2000/May/18 */ "version 3.2.3"; /* 00/Jun/30 */ #else char *programversion = /* "AFMtoTFM conversion utility version 1.7"; */ /* "AFMtoTFM conversion utility version 1.8"; */ /* "AFMtoTFM conversion utility version 2.0"; */ /* "AFMtoTFM conversion utility version 2.1"; */ /* "AFMtoTFM conversion utility version 2.2"; */ /* 95/Jan/8 */ /* "AFMtoTFM conversion utility version 2.3"; */ /* 95/Apr/22 */ /* "AFMtoTFM conversion utility version 2.4"; */ /* 95/Jun/8 */ /* "AFMtoTFM conversion utility version 2.5"; */ /* 95/Aug/14 */ /* "AFMtoTFM conversion utility version 2.6"; */ /* 95/Oct/28 */ /* "AFMtoTFM conversion utility version 2.6.1"; */ /* 96/Oct/12 */ /* "AFMtoTFM conversion utility version 2.7"; */ /* 97/Feb/5 */ /* "AFMtoTFM conversion utility version 2.7.1"; */ /* 97/June/5 */ /* "AFMtoTFM conversion utility version 2.8"; */ /* 97/Oct/1 */ /* "AFMtoTFM conversion utility version 2.8.1"; */ /* 97/Oct/19 */ /* "AFMtoTFM conversion utility version 2.8.2"; */ /* 97/Oct/28 */ /* "AFMtoTFM conversion utility version 2.9"; */ /* 97/Dec/21 */ "AFMtoTFM conversion utility version 3.0"; /* 98/June/15 */ #endif char *compilefile = __FILE__; char *compiledate = __DATE__; char *compiletime = __TIME__; char *copyright = "\ Copyright (C) 1990--2000 Y&Y, Inc. http://www.YandY.com\ "; char *phone="(978) 371-3286"; /* #define COPYHASH 14251529 */ /* #define COPYHASH 2719644 */ /* #define COPYHASH 8124949 */ /* #define COPYHASH 14008178 */ /* #define COPYHASH 3114191 */ /* #define COPYHASH 8997420 */ /* #define COPYHASH 14880649 */ /* #define COPYHASH 95688 */ /* #define COPYHASH 5978917 */ /* #define COPYHASH 10060254 */ /* #define COPYHASH 3104287 */ /* #define COPYHASH 6557415 */ #define COPYHASH 5190533 /* WARNING: CHANGE COPYHASH if COPYRIGHT message is changed !!! */ int wantcpyrght=1; /* want copyright message in there */ /* int usecontraction=0; */ /* use Mac contracted font file names for FontID */ int usecontraction=1; /* use Mac contracted font file names for FontID */ /* default changed 98/01/26 since 5+3+3... unique */ int maxcharkern=MAXCHRS; /* max kern pairs per character */ int verboseflag=0; /* show progress */ int traceflag=0; /* only used if DEBUGGING or SHOWTEXBASE defined */ int showkernflag=0; /* debugging only */ int detailflag=0; int debugflag=0; /* DEBUGGING ONLY */ int showital=0; /* if non-zero, show italic corrections */ int optimize=1; /* if non-zero check for repeat kern programs */ int showoptimize=0; /* show ligkern program sharing */ int showovershoot=0; /* show overshoot correction */ int showreplicate=0; /* show -FG replication of kern pairs */ int replicateleftflag=0; /* add composite character kern pairs 97/Oct/19 */ int replicaterightflag=0; /* add composite character kern pairs 97/Oct/19 */ int sortonname=0; /* sort on name rather than character code 97/Oct/30 */ int letrasetflag=0; /* rename f-ligatures based on bogus LetraSet names */ int abortflag=0; /* 99/June/15 */ int errlevel=0; /* 99/June/15 */ int underscoreflag=0; /* zero => don't retain underscores in output name */ int tryunderscore=1; /* try underscore name of file on input */ int dontexten=0; /* dont add 'x' to file name if remapped */ int suppressligsini=0; /* suppress ligatures if non-zero (from command) */ int suppressligs=0; /* suppress ligatures if non-zero (per file) */ int allowligs=0; /* allow ligatures even for fixed pitch font */ int allowdotlessi=1; /* allow ligatures based on dotlessi */ int allowdottedi=1; /* allow ligatures based on dotted i */ int backwardflag=0; /* backward compatible - limit to 255 kern pairs */ int longtable=0; /* indirect address - on if (lnext + knext) > 255 */ int ringbell=1; /* ring bell on warning */ int ignorezeros=1; /* ignore zero width kerns */ /* int preferfullname=0; */ /* use FullName instead of FontName */ /* int forcexerox=1; */ /* force xerox style header lengths */ int forcexerox=0; /* force xerox style header lengths - changed 98/Aug/25*/ int hideyandy=1; /* add Y&Y, Inc. to header */ int forcelong=0; /* force use of long table (debugging) */ int fullwidth=0; /* add italic correction to widths */ int lowerdef = 1; /* lower case is not upper case ! */ int avoiddups = 0; /* second hyphen => sfthyphen etc. */ int boundaryadd = 0; /* add boundary character kern pairs */ int texligflag=0; /* -a texligatures1/2 11 TeX f-ligs & pseudo-ligs */ int pseudoligs=0; /* -f texligatures2 just 6 TeX standard pseudo ligs */ int extendligs=0; /* -d extraligatures 3 extra `ligatures << >> ,, */ int accentligs=0; /* -j accentligatures 58 accent`ligatures' */ int greekparens=0; /* use ((...)) instead of <<...>> */ int ansitexflag=1; /* allow, if Windows ANSI, add some TeX text chars */ int ansiextend=0; /* extend ANSI in 16 - 32 for TeX *for this font* */ int texturesflag=0; /* insert `codingscheme' & `fontID' TeXtures wants */ int suppressitalic=0; /* For Textures, suppress Italic bit */ int suppressbold=0; /* For Textures, suppress Bold bit */ int alignmentflag=1; /* implement alignment zone adjustments 97/Dec/21 */ int boldflag = 0; /* for face byte in case of TeXtures */ int italicflag = 0; /* for face byte in case of TeXtures */ /* int QDEncode=0; */ /* screen encoding for TeXtures metric file */ /* int PSEncode=0; */ /* printer encoding for TeXtures metric file */ int noteabsence=0; /* warn if character in AFM, not in encoding */ int presortflag=1; /* sort kern pairs before passing to main routine */ /* this now is the default ... */ int killkern=0; /* non-zero if too many kern pairs seen */ int limitatzero=1; /* limit height and depth at zero */ int vectorflag=0; /* next arg is reencoding vector */ int spaceflag=0; /* next arg is space width */ int extraflag=0; /* next arg is extra space width */ int pathflag=0; /* next arg is path for vectors */ int outputpathflag=0; /* next arg is path for output TFM file 95/Jan/2 */ int checksumflag=0; /* next arg is checksum */ int italicfuzzflag=0; /* next arg is new italicfuzz */ int maxkernflag=0; /* next arg is max kern pairs per character */ int minkernflag=0; /* next arh is min kernsize */ int boundarygapflag=0; /* next arg is boundary char kern size */ int mathitflag=0; /* non-zero => 1 fewer parameters (6 total) */ int mathsyflag=0; /* non-zero => 15 extra parameters (22 total) */ int mathexflag=0; /* non-zero => 6? extra parameters (13 total) */ int ecflag=0; /* non-zero => 9 extra parameters (16 total) */ /* can be set from command line or via comments */ int showwidthflag=0; /* show sum of lower case widths 2000 May 14th */ int rightboundary=-1; /* right boundary character, if any 97/Oct/1 */ int leftboundary=-1; /* left boundary character, if any 97/Oct/1 */ int leftprogram=-1; /* where special left boundary program lives */ int reencodeforg=0; /* need to reencode vector on way in orginal copy */ int reencodeflag=0; /* need to reencode vector on way in */ int vetonontext=1; /* do not reencode non-text fonts 98/Apr/5 98/Jun/30 */ int encodingset=0; /* if encoding set up still */ int textfontflag=0; /* if apparently text font 98/Apr/5 */ /* based on Encoding in AFM file */ int pass=0; /* incremented in each pass through file */ int spacefixed; /* if spacewidth from command line or Comment Space */ int extrafixed; /* if spacewidth from command line or Comment Extra */ int spaceseen; /* have already encountered "N space" */ int paulflag=0; /* -P use Paul A's scheme for stretch and shrink */ /* 1/2 stretch 1/6 shrink */ int alanflag=0; /* -J use Alan J's scheme for stretch and shrink */ /* 1/3 stretch 1/3 shrink */ int sebasflag=0; /* -R use Sebastian Rahtz's for stretch and shrink */ /* 0.6 stretch 0.24 shrink */ int averageflag=0; /* -N average of fixed and scaled scheme */ /* 0.6 stretch 0.3 shrink averaged with 160 and 110 */ int stripbolditalic = 0; /* hard wired now */ int missingboxes; /* non-zero if some bboxes missing */ int kernsave=0; /* steps that can be omitted */ int duplicates; /* how many repeat encoding chars found */ int kernligsize; /* current max kern and lig allowed 94/July/18 */ /* shouldn't get larger than MAXKERN */ int keepingacc; /* how many composite kerns conflicted */ int keepingbou; /* how many boundary kerns conflicted */ double italicfuzz=ITALICFUZZ; volatile int bAbort=0; /* 92/Nov/24 */ double minkernsize=0.0; /* ignore kerning pairs smaller than this */ double xscale=1.0; /* aspect ratio --- first entry in FontMatrix */ /* used for condensed and expanded fonts */ double ascender, descender; /* from AFM file - */ /* not used */ double xheight, capheight; /* from AFM file - in case no BBox */ double cap_height, asc_height, acc_cap_height, desc_depth; double max_height, max_depth, digit_width, cap_stem, baseline_skip; double alignment=25.0; /* max width of typical alignment zone 97/Dec/21 */ int chr; /* current character working on (for debug out) */ /* char *defaultencoding="textext"; */ char *defaultencoding="none"; char *vectorpath = ""; /* directory for encoding vectors */ char *outputpath = ""; /* directory for TFM file output */ /* char programpath[MAXPATHLEN] = "c:\\dvipsone"; */ char programpath[FILENAME_MAX] = "c:\\yandy\\util"; char fontname[FONTNAME_MAX]; char fullname[FONTNAME_MAX]; char familyname[FONTNAME_MAX]; char macintoshname[FONTNAME_MAX]; char line[MAXLINE]; char logline[MAXLINE]; /* 99/June/11 */ int wantsignature = -1; /* +1 checksum Y&Y_ */ /* -1 checksum vector base fourty */ unsigned long checksum = 0; /* checksum if specified */ unsigned long checkdefault = 0x59265920; /* default signature "Y&Y " */ int checksumset = 0; /* non-zero if checksum set */ double designsize; /* design size */ /* the normal 7 parameters in font - last missing in cmmi */ double italicangle=0.0; double spacewidth=0.0; double spacestretch=0.0; double spaceshrink=0.0; /* double xheight; */ double em_quad=0.0; double extraspace=0.0; int isfixedpitch=0; double boundaryspace=0.0; /* kern read from command line - 100 typical */ /* -g=100 */ char *leftboundarychar=NULL; /* From comment in AFM file 97/Oct/1 */ char *rightboundarychar=NULL; /* From comment in AFM file 97/Oct/1 */ char *boundarychar="space"; /* disable from command line -H 98/Aug/15 */ /* 15 extra mathsy parameters - from 8 to 22 */ double num1, num2, num3, denom1, denom2; double sup1, sup2, sup3, sub1, sub2, supdrop, subdrop; double delim1, delim2, axisheight; /* 6 extra mathex parameters - from 8 to 13 */ double defaultrule; double bigopspacing1, bigopspacing2, bigopspacing3, bigopspacing4, bigopspacing5; double fxll, fyll, fxur, fyur; /* from FontBBox -- never used ! */ int nchrs; /* number of characters - StartCharMetrics */ int nkern; /* how many kern pairs total */ int nkernzero; /* how many kern pairs in AFM file */ int fchrs; /* number of characters in font also in encoding ? */ int lnext, knext, ktotal; int bufferinx; /* `pointer' into buffer (byte count) */ int ligkerninx; /* `pointer' in lig/kern program (word count) */ int maxligkern; /* debugging - max of above */ int italicneeded; /* non-zero if italic correction table is needed */ int lf, lh, bc, ec, nw, nh, nd, ni, nl, nk, ne, np; /* Indeces that tell where lig kern programs start and end */ int ligbegin[MAXCHRS], ligend[MAXCHRS]; int kernbegin[MAXCHRS], kernend[MAXCHRS]; /* int ligkerndup[MAXCHRS]; */ /* indicate duplicated 92/Dec/11 */ #define NOEQUIV 255 /* mark for no equivalent kern program */ unsigned char kerneqv[MAXCHRS]; /* ptr earlier char with same ligkern prog */ /* determined in findrepeats 97/Oct/1 */ unsigned char charrem[MAXCHRS]; /* ptr to character program saved 97/Oct/1 */ /* used when kerneqv not NOEQUIV */ /* char encoding[MAXCHRS][MAXCHARNAME]; */ /* name from AFM file */ char *encoding[MAXCHRS]; /* name from AFM file or vector 94/July/18 */ /* double width[MAXCHRS]; */ /* width from AFM file */ long width[MAXCHRS]; /* width from AFM file */ /* double xll[MAXCHRS], yll[MAXCHRS], xur[MAXCHRS], yur[MAXCHRS]; */ /* float xll[MAXCHRS], yll[MAXCHRS], xur[MAXCHRS], yur[MAXCHRS]; */ long xll[MAXCHRS], yll[MAXCHRS], xur[MAXCHRS], yur[MAXCHRS]; /* double height[MAXCHRS], depth[MAXCHRS], italic[MAXCHRS]; */ /* float height[MAXCHRS], depth[MAXCHRS], italic[MAXCHRS]; */ long height[MAXCHRS], depth[MAXCHRS], italic[MAXCHRS]; /* double widthtable[MAXCHRS]; */ /* double widthtable[MAXCHRS+1]; */ /* includes initial zero width */ long widthtable[MAXCHRS+1]; /* includes initial zero width */ /* double heighttable[MAXCHRS], depthtable[MAXCHRS], italictable[MAXCHRS]; */ /*double heighttable[MAXCHRS+1], depthtable[MAXCHRS+1], italictable[MAXCHRS+1];*/ long heighttable[MAXCHRS+1], depthtable[MAXCHRS+1], italictable[MAXCHRS+1]; /* double kerntable[MAXCHRS]; */ /* was MAXKERN - big space eater */ long kerntable[MAXDISTINCT]; /* *distinct* kern sizes only */ /* to change the above to float from double, need to change `comparedouble' */ /* probably shouldn't change widths to float - loose too much accuracy */ unsigned long extentable[MAXEXTEN]; /* extensible char table */ int extenpointer[MAXCHRS]; /* pointers into above or -1 */ int ascendpointer[MAXCHRS]; /* pointers to next char in chain or -1 */ int counttable[MAXCHRS]; /* used in reduction of tables */ /* is there a (char) problem here with characters above 127 ??? */ /* int ligsucc[MAXLIG]; */ /* int ligature[MAXLIG]; */ /* int kernsucc[MAXKERN]; */ /* MAXKERN ? NO */ /* float kern[MAXKERN]; */ /* was double - big space eater */ /* char ligsucc[MAXLIG]; */ char __far *ligsucc=NULL; /* put in far space */ /* char ligature[MAXLIG]; */ char __far *ligature=NULL; /* put in far space */ /* char kernsucc[MAXKERN]; */ /* MAXKERN ? NO */ char __far *kernsucc=NULL; /* put in far space */ /* long kern[MAXKERN]; */ long __far *kern; /* put in far space ? */ /* int charstart; */ /* NOT USED */ /* int widthstart, heightstart, depthstart, italicstart; */ /* NOT USED */ /* int ligkernstart, kernstart, extenstart, paramstart; */ /* NOT USED */ #define MAXENCODING (XEROXCODEN*4) /* 40 bytes in Xerox PARC header */ char encodingvecname[MAXENCODING]=""; /* first line encoding vector file */ char encodingscheme[MAXENCODING]=""; /* from EncodingScheme (AFM) */ char charcodingscheme[MAXENCODING]=""; /* from CharacterCodingScheme (AFM) */ #define MAXFONTID 60 /* actual limit is 20 */ char fontid[MAXFONTID]; /* 20 for Xerox PARC header data */ char codingvector[MAXENCODING]; /* 20 which coding scheme in use */ char *vectorfile=""; /* full filename with path 95/Feb/19 */ int buffersize; /* presently allocated */ /* unsigned char buffer[MAXBUFFER]; */ /* place for constructing TFM */ /* unsigned char __far *buffer; */ /* place for constructing TFM */ unsigned char __far *buffer=NULL; /* place for constructing TFM */ unsigned char __far *kernbuffer=NULL; /* place for kern pairs - sort */ int nforward=0; /* how many forward pointers will be needed */ /* i.e. how many have ligkern progs */ int nextslot=0; /* next slot in forwarding array */ /* struct kernpair { int a; int b; float kern; }; */ /* struct kernpair { int a; int b; long kern; }; */ /* inefficient 8 byte version */ struct kernpair { /* structure for a kern pair - now 6 bytes */ unsigned char a; unsigned char b; long kern; }; /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */ /* Following is only used for Mac TFM's using Mac Encoding Vector */ int usemacencoding = 0; /* When using Mac encoding */ int borrowsymbol = 0; /* Apple LW borrows math chars from symbol */ /* Note that Textures printing fails to do this */ /* 20 `math' characters may be borrowed from Symbol font */ /* 161 degree 176 400 */ /* in Adobe text fonts */ /* 173 notequal 185 549 */ /* 176 infinity 165 713 */ /* 177 plusminus 177 549 */ /* in Adobe text fonts */ /* 178 lessequal 163 549 */ /* 179 greaterequal 179 549 */ /* 181 mu 77 576 */ /* in Adobe text fonts */ /* 182 partialdiff 182 494 */ /* 183 summation 229 713 */ /* 184 product 213 823 */ /* 185 pi 112 549 */ /* 186 integral 242 274 */ /* 189 Omega 87 768 */ /* 194 logicalnot 216 713 */ /* in Adobe text fonts */ /* 195 radical 214 549 */ /* 197 approxequal 187 549 */ /* 198 Delta 68 612 */ /* 214 divide 184 549 */ /* in Adobe text fonts */ /* 215 lozenge 224 494 */ /* 218 fraction 164 167 */ /* in Adobe text fonts */ /* 240 apple 240 790 */ int mathchar[] = { /* character codes in `standard roman' */ 161, 173, 176, 177, 178, 179, 181, 182, 183, 184, 185, 186, 189, 194, 195, 197, 198, 214, 215, 218, 240, 0 }; int symwidth[] = { /* char widths in `Symbol' font - fixed */ 400, 549, 713, 549, 549, 549, 576, 494, 713, 823, 549, 274, 768, 713, 549, 549, 612, 549, 494, 167, 790, 0 }; /* Many Adobe fonts nowadays do have the following six actually: */ /* degree, plusminus, mu, logicalnot, divide, and fraction */ /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */ #ifdef IGNORED /* deal with bogus glyph names in LetraSet fonts */ char *letranames[][2] = { {"asciicircum", "fi"}, {"asciitilde", "fl"}, {"logicalnot", "ff"}, {"plusminus", "ffi"}, {"mu", "ffl"}, {"fi", "asciicircum"}, {"fl", "asciitilde"}, {"ff", "logicalnot"}, {"ffi", "plusminus"}, {"ffl", "mu"}, {"", ""} }; #endif /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */ char *encodingnames[][2] = { /* `standard' encoding names */ {"TeX text", "textext"}, /* cmr*, cmb*, cmsl*, cmss* */ {"TeX text italic", "texital"}, /* for cmti* */ {"TeX text without f-ligatures", "textype"}, /* cmcsc10 & cmr5 */ {"TeX typewriter text", "typewrit"}, /* cm*tt* */ {"TeX typewriter text italic", "typeital"}, /* for cmitt* */ {"TeX extended ASCII", "texascii"}, /* cmtex* */ {"TeX math italic", "mathit"}, /* cmmi* */ {"TeX math symbols", "mathsy"}, /* cmsy* */ {"TeX math extension", "mathex"}, /* cmex10 */ {"ASCII caps and digits", "textext"}, /* cminch ??? */ {"AdobeStandardEncoding", "standard"}, {"Adobe StandardEncoding", "standard"}, {"Adobe Symbol Encoding", "symbol"}, {"Adobe Dingbats Encoding", "dingbats"}, {"MicroSoft Windows ANSI 3.0", "ansi"}, {"MicroSoft Windows ANSI 3.1", "ansinew"}, {"Ventura Publisher Encoding", "ventura"}, {"TeX 256 character Encoding", "tex256"}, {"Extended TeX Font Encoding - Latin", "tex256"}, {"Extended TeX Font Encoding - Latin", "cork"}, {"TeX text companion symbols 1---TS1", "ts1"}, /* {"Default TeX Encoding", "default"}, */ /* {"MacIntosh", "mac"}, */ {"Macintosh", "mac"}, /* {"AT&T Garamond Encoding", "atandt"}, */ /* {"ASCII caps and digits", "textext"}, */ /* cminch */ /* {"TEX TEXT IN ADOBE SETTING", "textext"} */ /* pctex style ? */ {"TEX TEXT + ADOBESTANDARDENCODING", "neonnew"}, /* 92/Dec/22 */ {"TeX typewriter and Windows ANSI", "texnansi"}, /* 94/Dec/31 */ {"TEXBASE1ENCODING", "8r"}, /* 98/Feb/12 */ {"", ""} }; /**********************************************************************/ int allowaliases=0; /* 94/August/9 use 'A' on command line */ char *charaliases[][2] = { {"sfthyphen", "hyphen"}, {"nbspace", "space"}, {"brokenbar", "bar"}, {"space", "visiblespace"}, /* 98/Jul/12 for stupid T1 encoding */ /* {"scedilla", "scommaaccent"}, */ /* ? */ /* {"tcedilla", "tcommaaccent"}, */ /* ? */ /* {"Scedilla", "Scommaaccent"}, */ /* ? */ /* {"Tcedilla", "Tcommaaccent"}, */ /* ? */ /* {"middot", "periodcentered"}, */ /* {"overscore", "macron"}, */ /* {"Ohm", "Omega"}, */ /* {"increment", "Delta"}, */ /* {"micro", "mu"}, */ {"", ""} }; /**********************************************************************/ /* ALL LIGATURES WITH THE SAME STARTING CHARACTER MUST APPEAR TOGETHER */ /* The first eleven `ligatures' are standard in Computer Modern fonts */ /* The following should be suppressed in fixed-width fonts */ char *texligatures1[][3]={ /* these are the only REAL ligatures */ {"f", "i", "fi"}, {"f", "l", "fl"}, {"f", "f", "ff"}, {"f", "j", "fj"}, /* added 95/Oct/15 */ {"f", "b", "fb"}, /* added 95/Oct/17 */ {"f", "k", "fk"}, /* added 95/Oct/17 */ {"ff", "i", "ffi"}, {"ff", "l", "ffl"}, {"ff", "j", "ffj"}, /* added 95/Oct/15 */ {"c", "t", "ct"}, /* added 95/June/8 */ {"s", "t", "st"}, /* added 95/June/8 */ {"i", "j", "ij"}, /* added 95/Oct/15 ??? */ {"I", "J", "IJ"}, /* added 97/Oct/15 ??? */ {"", "", ""}, /* terminator */ }; /* The following may be OK in fixed width fonts */ char *texligatures2[][3]={ /* these are standard TeX pseudo ligatures */ {"exclam", "quoteleft", "exclamdown"}, /* Spanish opening exclamation mark */ {"question", "quoteleft", "questiondown"}, /* Spanish opening question mark */ {"hyphen", "hyphen", "endash"}, {"hyphen", "sfthyphen", "sfthyphen"}, /* 96/Feb/24 */ {"endash", "hyphen", "emdash"}, {"quoteleft", "quoteleft", "quotedblleft"}, /* English opening quotes, German closing quotes */ {"quoteright", "quoteright", "quotedblright"}, /* English and Polish closing quotes */ {"quotereversed", "quotereversed", "quotedblreversed"}, /* 97/May/10 */ {"quotesinglbase", "quotesinglbase", "quotedblbase"}, /* 97/Oct/30 */ {"", "", ""}, /* terminator */ }; /* The next three/five/nine are useful extras adopted from Sebastian Rahtz: */ char *extraligatures[][3]={ {"less", "less", "guillemotleft"}, /* French opening quotes */ {"greater", "greater", "guillemotright"}, /* French closing quotes */ /* {"exclamdown", "exclamdown", "guillemotleft"}, */ /* {"questiondown", "questiondown", "guillemotright"}, */ {"comma", "comma", "quotedblbase"}, /* German and Polish opening quotes */ /* {"suppress", "l", "lslash"}, */ /* {"suppress", "L", "Lslash"}, */ /* {"space", "l", "lslash"}, */ /* ugh ??? */ /* {"space", "L", "Lslash"}, */ /* ugh ??? */ {"percent", "perthousand", "perthousand"}, /* 98/Jun/30 for T1 encoding */ {"", "", ""}, /* terminator */ }; char *alterligatures[][3]={ /* for Greek fonts ? */ {"parenleft", "parenleft", "guillemotleft"}, /* French opening quotes */ {"parenright", "parenright", "guillemotright"}, /* French closing quotes */ /* {"exclamdown", "exclamdown", "guillemotleft"}, */ /* {"questiondown", "questiondown", "guillemotright"}, */ {"comma", "comma", "quotedblbase"}, /* German and Polish opening quotes */ /* {"suppress", "l", "lslash"}, */ /* {"suppress", "L", "Lslash"}, */ /* {"space", "l", "lslash"}, */ /* ugh ??? */ /* {"space", "L", "Lslash"}, */ /* ugh ??? */ {"percent", "perthousand", "perthousand"}, /* 98/Jun/30 for T1 encoding */ {"", "", ""}, /* terminator */ }; char *letraligatures1[][3]={ /* using bogus names in LetraSet fonts */ {"f", "i", "asciicircum"}, {"f", "l", "asciitilde"}, {"f", "f", "logicalnot"}, {"logicalnot", "i", "plusminus"}, {"logicalnot", "l", "mu"}, {"", "", ""}, /* terminator */ }; /* The next 58 are convenient ligatures for accented characters */ /* (These do nothing if encoding is StandardEncoding or TeX text) */ /* The composite character name itself is generated automatically, */ /* and "" for the base means copy the previous base. */ /* possible weird alternatives `quotedbl A' => Adieresis ? UGH, NO */ /* possible weird alternatives `asciicircum A' => Acircumflex ? NO */ /* possible weird alternatives `asciitilde A' => Atilde ? NO */ /* changed `dotlessi' => `i' 93/March/13 */ /* maybe put in *both* `i' and `dotlessi' version ??? OK 95/April/22 */ /* maybe allow `degree' `A' => `Aring' ? */ /* But TeX uses \aa and \AA */ char *accentligatures[][3]={ {"acute", "A", ""}, /* {"acute", "A", "Aacute"}, */ {"", "E", ""}, /* {"acute", "E", "Eacute"}, */ {"", "I", ""}, /* {"acute", "I", "Iacute"}, */ {"", "O", ""}, /* {"acute", "O", "Oacute"}, */ {"", "U", ""}, /* {"acute", "U", "Uacute"}, */ {"", "Y", ""}, /* {"acute", "Y", "Yacute"}, */ {"", "a", ""}, /* {"acute", "a", "aacute"}, */ {"", "i", ""}, /* {"acute", "i", "iacute"}, */ {"", "dotlessi", ""}, /* {"acute", "dotlessi", "iacute"}, 95/Apr/22 */ {"", "e", ""}, /* {"acute", "e", "eacute"}, */ {"", "o", ""}, /* {"acute", "o", "oacute"}, */ {"", "u", ""}, /* {"acute", "u", "uacute"}, */ {"", "y", ""}, /* {"acute", "y", "yacute"}, */ {"caron", "S", ""}, /* {"caron", "S", "Scaron"}, */ {"", "Z", ""}, /* {"caron", "Z", "Zcaron"}, */ {"", "s", ""}, /* {"caron", "s", "scaron"}, */ {"", "z", ""}, /* {"caron", "z", "zcaron"}, */ {"cedilla", "C", ""}, /* {"cedilla", "C", "Ccedilla"}, */ {"", "c", ""}, /* {"cedilla", "c", "ccedilla"}, */ {"circumflex", "A", ""}, /* {"circumflex", "A", "Acircumflex"}, */ {"", "E", ""}, /* {"circumflex", "E", "Ecircumflex"}, */ {"", "I", ""}, /* {"circumflex", "I", "Icircumflex"}, */ {"", "O", ""}, /* {"circumflex", "O", "Ocircumflex"}, */ {"", "U", ""}, /* {"circumflex", "U", "Ucircumflex"}, */ {"", "a", ""}, /* {"circumflex", "a", "acircumflex"}, */ {"", "i", ""}, /* {"circumflex", "i", "icircumflex"},*/ {"", "dotlessi", ""}, /* {"circumflex", "dotlessi", "icircumflex"}, 95/Apr/22 */ {"", "e", ""}, /* {"circumflex", "e", "ecircumflex"}, */ {"", "o", ""}, /* {"circumflex", "o", "ocircumflex"}, */ {"", "u", ""}, /* {"circumflex", "u", "ucircumflex"}, */ {"dieresis", "A", ""}, /* {"dieresis", "A", "Adieresis"}, */ {"", "E", ""}, /* {"dieresis", "E", "Edieresis"}, */ {"", "I", ""}, /* {"dieresis", "I", "Idieresis"}, */ {"", "O", ""}, /* {"dieresis", "O", "Odieresis"}, */ {"", "U", ""}, /* {"dieresis", "U", "Udieresis"}, */ {"", "Y", ""}, /* {"dieresis", "Y", "Ydieresis"}, */ {"", "a", ""}, /* {"dieresis", "a", "adieresis"}, */ {"", "dotlessi", ""}, /* {"dieresis", "dotlessi", "idieresis"}, 95/Apr/22 */ {"", "i", ""}, /* {"dieresis", "i", "idieresis"}, */ {"", "e", ""}, /* {"dieresis", "e", "edieresis"}, */ {"", "o", ""}, /* {"dieresis", "o", "odieresis"}, */ {"", "u", ""}, /* {"dieresis", "u", "udieresis"}, */ {"", "y", ""}, /* {"dieresis", "y", "ydieresis"}, */ {"grave", "A", ""}, /* {"grave", "A", "Agrave"}, */ {"", "E", ""}, /* {"grave", "E", "Egrave"}, */ {"", "I", ""}, /* {"grave", "I", "Igrave"}, */ {"", "O", ""}, /* {"grave", "O", "Ograve"}, */ {"", "U", ""}, /* {"grave", "U", "Ugrave"}, */ {"", "a", ""}, /* {"grave", "a", "agrave"}, */ {"", "i", ""}, /* {"grave", "i", "igrave"}, */ {"", "dotlessi", ""}, /* {"grave", "dotlessi", "igrave"}, 95/Apr/22 */ {"", "e", ""}, /* {"grave", "e", "egrave"}, */ {"", "o", ""}, /* {"grave", "o", "ograve"}, */ {"", "u", ""}, /* {"grave", "u", "ugrave"}, */ {"ring", "A", ""}, /* {"ring", "A", "Aring"}, */ {"", "a", ""}, /* {"ring", "a", "aring"}, */ {"tilde", "A", ""}, /* {"tilde", "A", "Atilde"}, */ {"", "N", ""}, /* {"tilde", "N", "Ntilde"}, */ {"", "O", ""}, /* {"tilde", "O", "Otilde"}, */ {"", "a", ""}, /* {"tilde", "a", "atilde"}, */ {"", "n", ""}, /* {"tilde", "n", "ntilde"}, */ {"", "o", ""}, /* {"tilde", "o", "otilde"}, */ {"", "", ""}, /* terminator */ }; /* {"degree", "A", ""}, */ /* {"degree", "A", "Aring"}, UGH */ /* {"", "a", ""}, */ /* {"degree", "a", "aring"}, UGH */ /**********************************************************************/ /* Codes used for expanding kern pairs in AFM file */ /* Adding kern pairs for accented characters based on base characters */ /* code "*" start of list for new base letter */ /* code "" equivalent on left and right, both upper and lower case */ /* code "L" only equivalent on the left (i.e. use as charb in kern) */ /* code "R" only equivalent on the right (i.e. use as chara in kern) */ /* code " l" lower case only */ /* code " u" upper case only */ /* If first letter is a space, use rest as replacement */ /* otherwise construct replacement by concatenating to base char */ char *kernrep[][2] = { {"A", "*"}, { "acute", ""}, { "breve", ""}, { "circumflex", ""}, { "dieresis", ""}, { "grave", ""}, { "ogonek", ""}, { "ring", ""}, { "tilde", ""}, { "E", "Lu"}, /* AE equiv A on left only */ { "e", "Ll"}, /* ae equiv a on left only */ {"C", "*"}, { "acute", ""}, { "caron", ""}, { "cedilla", ""}, {"D", "*"}, { "caron", " u"}, /* Dcaron equiv D upper case only */ { "caron", "Ll"}, /* dcaron equiv d left only */ { "croat", ""}, { " Eth", "Ru"}, /* right and upper case only */ {"E", "*"}, { "acute", ""}, { "caron", ""}, { "circumflex", ""}, { "dieresis", ""}, { "grave", ""}, { "ogonek", ""}, { " AE", "Ru"}, /* AE right only */ { " ae", "Rl"}, /* ae right only */ { " OE", "Ru"}, /* OE right only */ { " oe", "Rl"}, /* oe right only */ {"G", "*"}, /* ? */ { "breve", ""}, {"I", "*"}, { "acute", ""}, { "circumflex", ""}, { "dieresis", ""}, { "dotaccent", " u"}, /* upper case only */ { "grave", ""}, { "J", "Lu"}, /* IJ left only */ { "j", "Ll"}, /* ij left only */ {"J", "*"}, { " IJ", "Ru"}, /* IJ right only */ { " ij", "Rl"}, /* ij right only */ {"L", "*"}, /* ? */ { "acute", ""}, {"N", "*"}, /* ? */ { "acute", ""}, { "caron", ""}, { "tilde", ""}, { " Eng", "L"}, /* Eng on left only */ {"O", "*"}, { "acute", ""}, { "circumflex", ""}, { "dieresis", ""}, { "grave", ""}, { "hungarumlaut", ""}, { "tilde", ""}, { "slash", ""}, /* Oslash */ { "E", "Lu"}, /* OE left only */ { "e", "Ll"}, /* oe left only */ {"R", "*"}, /* ? */ { "acute", ""}, { "caron", ""}, {"S", "*"}, { "acute", ""}, { "caron", ""}, { "cedilla", ""}, { "commaaccent", ""}, {"T", "*"}, { "caron", "L"}, /* lower case only */ { "cedilla", ""}, { "commaaccent", ""}, {"U", "*"}, { "acute", ""}, { "circumflex", ""}, { "dieresis", ""}, { "grave", ""}, { "hungarumlaut", ""}, { "ring", ""}, {"Y", "*"}, { "acute", ""}, { "dieresis", ""}, {"Z", "*"}, { "acute", ""}, { "caron", ""}, { "dotaccent", ""}, {"", "*"} }; /**********************************************************************/ /* Following stuff here for Mac Style FontName contraction */ char MacName[64]; /* 5 + 3 + 3 ... Mac Style Font Name */ char BaseName[32]; /* base name derived from FontName */ /* #define MAXSUFFIX 8 */ #define MAXSUFFIX 12 char SuffixString[MAXSUFFIX][24]; /* suffix strings */ unsigned int nextsuffix; /* count of suffix strings */ /* #endif */ /**********************************************************************/ void ShowLine (char *, int); #ifndef _WINDOWS void ShowLine (char *line, int errflag) { /* 99/June/11 */ if (line == NULL || *line == '\0') return; if (errflag) { fflush(stdout); fputs(line, errout); fflush(errout); } else fputs(line, stdout); } #endif /* DLL version of this comes later ... */ /**********************************************************************/ void perrormod (char *s) { //#ifdef _WINDOWS sprintf(logline, "%s: %s\n", s, strerror(errno)); showline(logline, 1); // #else // perror (s); // #endif } void pause (void) { #ifndef _WINDOWS fflush(stdout); /* ??? */ fflush(stderr); /* ??? */ (void) _getch(); /* ??? */ #endif } /**********************************************************************/ char *zstrdup (char *s) { char *new = _strdup(s); if (new != NULL) return new; sprintf(logline, "ERROR: Unable to allocate memory for %s\n", s); showline(logline, 1); #ifdef _WINDOWS abortflag++; return NULL; #else showline("Press any key to continue . . .\n", 0); pause(); exit(1); #endif } /* *** *** *** *** *** *** *** NEW APPROACH TO `ENV VARS' *** *** *** *** */ /* grab `env variable' from `dviwindo.ini' or from DOS environment 94/May/19 */ /* in DLL version just use GetPrivateProfileString instead ... 99/June/15 */ /* if (usedviwindo) setupdviwindo(); */ /* need to do this before use */ int usedviwindo = 1; /* use [Environment] section in `dviwindo.ini' */ /* reset if setup of dviwindo.ini file fails */ char *dviwindoini = "dviwindo.ini"; /* name of ini file we look for */ #ifndef _WINDOWS // when run as console application we read INI file directly int dviwindoinisetup = 0; /* turned on after setup */ char *dviwindo = ""; /* full file name for dviwindo.ini with path */ /* set up full file name for ini file and check for specified section */ /* e.g. dviwindo = setupinifile ("dviwindo.ini", "[Environment]") */ char *setupinifile (char *ininame, char *section) { char fullfilename[FILENAME_MAX]; FILE *input; char *windir; char line[MAXLINE]; int m; /* Easy to find Windows directory if Windows runs */ /* Or if user kindly set WINDIR environment variable */ /* Or if running in Windows NT */ if ((windir = getenv("windir")) != NULL || /* 94/Jan/22 */ (windir = getenv("WINDIR")) != NULL || (windir = getenv("winbootdir")) != NULL || (windir = getenv("SystemRoot")) != NULL || (windir = getenv("SYSTEMROOT")) != NULL) { /* 95/Jun/23 */ strcpy(fullfilename, windir); strcat(fullfilename, "\\"); strcat(fullfilename, ininame); } else _searchenv (ininame, "PATH", fullfilename); if (strcmp(fullfilename, "") == 0) { /* ugh, try standard place */ strcpy(fullfilename, "c:\\windows"); /* winnt ??? */ strcat(fullfilename, "\\"); strcat(fullfilename, ininame); } /* if (*fullfilename != '\0') { */ /* check whether ini file actually has required section */ if ((input = fopen(fullfilename, "r")) != NULL) { m = strlen(section); while (fgets (line, sizeof(line), input) != NULL) { if (*line == ';') continue; /* if (strncmp(line, section, m) == 0) { */ if (_strnicmp(line, section, m) == 0) { /* 95/June/23 */ fclose(input); return zstrdup(fullfilename); } } fclose(input); } /* } */ return ""; /* failed, for one reason or another */ } int setupdviwindo (void) { if (! usedviwindo) return 0; /* already tried and failed */ if (dviwindo != NULL && *dviwindo != '\0') return 1; /* already tried and succeeded */ dviwindo = setupinifile ("dviwindo.ini", "[Environment]"); if (dviwindo != NULL && *dviwindo != '\0') { dviwindoinisetup = 1; return 1; } else { usedviwindo = 0; /* failed, don't try this again */ return 0; } // return (*dviwindo != '\0'); } char *grabenvvar (char *varname, char *inifile, char *section, int useini) { FILE *input; char line[MAXLINE]; char *s; int m, n; if (! useini || *inifile == '\0') return getenv(varname); /* get from environment */ if ((input = fopen(inifile, "r")) != NULL) { m = strlen(section); /* search for [...] section */ while (fgets (line, sizeof(line), input) != NULL) { if (*line == ';') continue; /* if (strncmp(line, section, m) == 0) { */ if (_strnicmp(line, section, m) == 0) { /* 95/June/23 */ /* search for varname=... */ n = strlen(varname); while (fgets (line, sizeof(line), input) != NULL) { if (*line == ';') continue; if (*line == '[') break; /* if (*line == '\n') break; */ /* ??? */ if (*line <= ' ') continue; /* 95/June/23 */ /* if (strncmp(line, varname, n) == 0 && */ if (_strnicmp(line, varname, n) == 0 && *(line+n) == '=') { /* found it ? */ fclose (input); /* flush trailing white space */ s = line + strlen(line) - 1; while (*s <= ' ' && s > line) *s-- = '\0'; if (traceflag) { /* DEBUGGING ONLY */ sprintf(logline, "%s=%s", varname, line+n+1); showline(logline, 0); } return zstrdup(line+n+1); } } /* end of while fgets */ } /* end of search for [Environment] section */ } /* end of while fgets */ fclose (input); } /* end of if fopen */ /* useini = 0; */ /* so won't try this again ! need & then */ return getenv(varname); /* failed, so try and get from environment */ } /* this will return NULL if not found anywhere */ #endif // end of ifn _WINDOWS char *grabenv (char *varname) { /* get from [Environment] in dviwindo.ini */ #ifdef _WINDOWS (void) GetPrivateProfileString("Environment", varname, "", line, sizeof(line), dviwindoini); if (traceflag) { sprintf(logline, "%s=%s\n", varname, line); showline(logline, 0); } if (*line != '\0') return zstrdup(line); else return getenv(varname); #else if (usedviwindo && ! dviwindoinisetup) setupdviwindo(); /* 99/June/16 */ return grabenvvar (varname, dviwindo, "[Environment]", usedviwindo); #endif } #ifdef NEEDATMINI /* grab setting from `atm.ini' 94/June/15 */ /* if (useatmini) setupatmini(); */ /* need to do this before use */ int useatmini = 1; /* use [Setup] section in `atm.ini' */ /* reset if setup of atm.ini file fails */ char *atmininame = "atm.ini"; /* name of ini file we are looking for */ char *atmsection = "[Setup]"; /* ATM.INI section */ char *atmini = ""; /* full file name for atm.ini with path */ int setupatmini (void) { if (! useatmini) return 0; /* already tried and failed */ if (*atmini != '\0') return 1; /* already tried and succeeded */ /* atmini = setupinifile ("atm.ini", "[Setup]"); */ atmini = setupinifile (atmininame, atmsection); if (atmini != NULL && *atmini != '\0') { return 1; } else { useatmini = 0; /* failed, don't try this again */ return 0; } // return (*atmini != '\0'); } #endif /**********************************************************************/ int checkpause (int flag) { /* 95/Oct/28 */ /* if (grabenv ("DEBUGPAUSE") != NULL) { */ /* 97/Nov/28 */ if (grabenv ("DEBUGPAUSE") != NULL || flag) { showline("\n", 0); showline("Press any key to continue . . .\n", 0); pause(); return -1; } return 0; } void checkenter (int argc, char *argv[]) { /* 95/Oct/28 */ int m; char current[FILENAME_MAX]; if (grabenv ("DEBUGPAUSE") != NULL) { (void) _getcwd(current, sizeof(current)); sprintf(logline, "Current directory: `%s'\n", current); showline(logline, 0); for (m = 0; m < argc; m++) { // sprintf(logline, "%2d:\t`%s'\n", m, argv[m]); sprintf(logline, "%2d: `%s'\n", m, argv[m]); showline(logline, 0); } checkpause(0); } } void checkexit (int n) { /* 95/Oct/28 */ checkpause(1); #ifdef _WINDOWS abortflag++; #else exit(n); #endif } /**********************************************************************/ /* Add ability to continue line using \ before \n ? */ int getline (FILE *infile, char *buff, int nmax) { int c, k=0; char *s=buff; while ((c = getc(infile)) != '\n' && c != EOF) { *s++ = (char) c; k++; if (k >= nmax) { *s = '\0'; sprintf(logline, "Line too long: %s (> %d)\n", buff, MAXLINE); showline(logline, 1); /* exit (3); */ checkexit (3); return 0; } } if (c != EOF) { *s++ = (char) c; k++; } *s = '\0'; return k; } int getrealline (FILE *infile, char *buff, int nmax) { int k; k = getline(infile, buff, nmax); while ((*buff == '%' || *buff == '\n' || *buff == ';') && k > 0) { k = getline(infile, buff, nmax); } return k; } /* 2^20 = 1048576 */ long mapdouble (double x) { /* map to tfm scaled integer */ if (x == 0.0) return 0L; else if (x < 0.0) return -mapdouble(-x); else return (long) ((x * 1048576.0 + 499.999) / 1000.0); } double unmap (long x) { /* map back to Adobe double */ double dx; long th; if (x == 0) return 0.0; if (x < 0) return -unmap(-x); dx = (double) x / 1048.576; /* th = (long) (dx * 1000.0 + 500.0); */ /* th = (long) (dx * 500.0 + 250.0); */ th = (long) (dx * 500.0 + 0.5); /* 98/Aug/15 */ /* return ((double) x / 1048.576); */ /* return (th / 1000.0); */ return (th / 500.0); } /* modified to allow for repeated occurences */ /* 92/Nov/26 */ /* should this also check whether font has character ? */ /* that is, whether width[k] != NOWIDTH ? */ int clookup (char *character, int last) { /* 92/Nov/26 */ int k, l; char *alias; if (strlen(character) == 1) { /* speedup 94/July/18 */ k = *character; if (k > last && k < fontchrs) if (strcmp(character, encoding[k]) == 0) return k; } /* sfthyphen in ligature table => second occurence of hyphen in encoding */ if (strcmp(character, "sfthyphen") == 0) { /* special case */ /* disable this hack while reading AFM file ? */ for (k = last + 1; k < fontchrs; k++) { if (strcmp("hyphen", encoding[k]) == 0) break; } for (k = k + 1; k < fontchrs; k++) { if (strcmp("hyphen", encoding[k]) == 0) return k; } } /* main lookup loop */ for (k = last + 1; k < fontchrs; k++) { if (strcmp(character, encoding[k]) == 0) return k; } /* kludge to deal with T1 encoding when AFM has space kerns 98/Jul/12 */ if (strcmp(character, "space") == 0) { for (k = last + 1; k < fontchrs; k++) { if (strcmp("visiblespace", encoding[k]) == 0) { return k; } } } /* New 94/April/10 */ if (allowaliases && last < 0) { for (l = 0; l < 16; l++) { if (strcmp(charaliases[l][0], "") == 0) break; if (strcmp(charaliases[l][0], character) == 0) { alias = charaliases[l][1]; for (k = 0; k < fontchrs; k++) { if (strcmp(alias, encoding[k]) == 0) return k; } break; } } } if (noteabsence && last < 0) { sprintf(logline, "%s? ", character); showline(logline, 0); } return -1; } /* do not copy lig/kern stuff if flag == 0 */ void copymetrics (int i, int k, int flag) { /* spliced out 93/Dec/18 */ width[i] = width[k]; italic[i] = italic[k]; height[i] = height[k]; depth[i] = depth[k]; xll[i] = xll[k]; yll[i] = yll[k]; xur[i] = xur[k]; yur[i] = yur[k]; if (ligbegin[i] != -1 || kernbegin[i] != -1) { sprintf(logline, "ERROR: Attempt to overwrite kern/lig %d %d\n", i, k); showline(logline, 1); /* continue; */ return; } if (flag) { ligbegin[i] = ligbegin[k]; ligend[i] = ligend[k]; kernbegin[i] = kernbegin[k]; kernend[i] = kernend[k]; } /* otherwise ligbegin, ligend, kernbegin, kernend left at -1 */ } void replicate(int k) { /* see whether same character code appears in another position and copy */ /* this is for multiple encoding of same character in encoding vector */ int i; if (k < 0 || k > MAXCHRS) { /* shouldn't happen 93/Jan/5 */ sprintf(logline, "ERROR: Bad replication %d\n", k); showline(logline, 1); return; } /* for(i=k+1; k < fontchrs; k++) { */ /* changed 92/Dec/11 */ /* for(i=0; k < fontchrs; k++) { */ for(i=0; i < fontchrs; i++) { /* changed 93/Jan/5 */ if (i == k) continue; if (strcmp(encoding[i], encoding[k]) == 0) { if (width[i] != NOWIDTH) { if (width[i] != width[k]) { sprintf(logline, "ERROR: Attempt to overwrite width %d (%lg) with %d (%lg)\n", i, unmap(width[i]), k, unmap(width[k])); showline(logline, 1); continue; } else { /* attempt to check that it is OK */ #ifdef DEBUGGING char *s; sprintf(logline, "ERROR: Attempt to overwrite width %d with %d MISMATCH:\n", i, k); s = line + strlen(line); if (italic[i] != italic[k] || height[i] != height[k] || depth[i] != depth[k]) { sprintf(s, "italic %lg %lg - height %lg %lg - depth %lg %lg\n", unmap(italic[i]), unmap(italic[k]), unmap(height[i]), unmap(height[k]), unmap(depth[i]), unmap(depth[k])); s += strlen(s); } if (xll[i] != xll[k] || xur[i] != xur[k] || yll[i] != yll[k] || yur[i] != yur[k]) { sprintf(s, "bbox %ld %ld %ld %ld - %ld %ld %ld %ld\n", xll[i], yll[i], xur[i], yur[i], xll[k], yll[k], xur[k], yur[k]); s += strlen(s); } if (ligbegin[i] != ligbegin[k] || ligend[i] != ligend[k] || kernbegin[i] != kernbegin[k] || kernend[i] != kernend[k]) { sprintf(s, "lig %d - %d %d - %d - kern %d - %d %d - %d\n", ligbegin[i], ligend[i], ligbegin[k], ligend[k], kernbegin[i], kernend[i], kernbegin[k], kernend[k]); s += strlen(s); } showline(logline, 0); #endif continue; /* ??? 93/Jan/6 */ } } /* copymetrics (i, k, 0); */ /* should this be zero ? */ /* this may be a problem if the character carries a lig/kern prog ??? */ copymetrics (i, k, 1); /* ??? */ } } } void stripreturn(char *name) { int c; char *s=name; while ((c = *s) != '\0' && c != '\n' && c != '\r') s++; if (c == '\n' || c == '\r') *s = '\0'; s--; /* also get rid of trailing white space */ while ((c = *s) <= ' ') *s-- = '\0'; } void complain(void) { #ifdef _WINDOWS if (ringbell) MessageBeep(0xFFFFFFFF); abortflag++; #else if (ringbell) putc('\a', errout); /* ??? */ pause(); #endif } int alluppercase(char *s) { int c; while ((c = *s++) > 0) if ((c < 'A' || c > 'Z') && (c < '0' || c > '9')) return 0; return -1; } void lowercase(char *s, char *t) { int c; while ((c = *t++) > 0) { if (c >= 'A' && c <= 'Z') c = c - 'A' + 'a'; *s++ = (char) c; } *s = '\0'; } char *weightnames[] = { "extrablack", "ultrablack", "black", "ultra", "heavy", "extrabold", "bold", "demi", "semi", "demibold", "semibold", "medium", "plain", "regular", "standard", "roman", "normal", "book", "light", "thin", "extralight", "ultralight", "" }; int weightvalues[] = { 800, 800, 800, 800, 800, 800, 800, 600, 600, 600, 600, 400, 400, 400, 400, 400, 400, 400, 200, 200, 200, 200, 0 }; int analyzeweight(char *s, char *line) { char str[128]; int k; int weight=400; /* default */ sscanf(s, "%s", str); /* lowercase(str, str); */ /* for stupid DTF fonts 92/Oct/22 */ for (k = 0; k < 64; k++) { if (_strcmpi(weightnames[k], "") == 0) break; if (_strcmpi(weightnames[k], str) == 0) break; } if (strcmp(weightnames[k], "") != 0) weight = weightvalues[k]; else { showline("Unrecognized Weight ", 1); showline(line, 0); } if (texturesflag && verboseflag) { sprintf(logline, "Weight `%s' => %d\n", str, weight); showline(logline, 0); } return weight; } /* read up to StartCharMetrics */ /* gathering information as it goes */ /* returns non-zero if some serious problem */ int tostartchar (FILE *infile, int passes) { /* read up to StartCharMetrics */ char *s, *so; int n, last, next; unsigned int exten, top, mid, bot, rep; if (passes == 0) xscale = 1.0; /* don't reset if spacewidth set from command line */ if (spacefixed > 0) spacefixed = 0; if (extrafixed > 0) extrafixed = 0; if (passes == 0) { italicflag = 0; boldflag = 0; if (boundarychar != NULL) { /* copy default boundary char */ leftboundarychar = zstrdup(boundarychar); /* 98/Aug/15 */ rightboundarychar = zstrdup(boundarychar); /* 98/Aug/15 */ if (leftboundarychar == NULL || rightboundarychar == NULL) return -1; } else leftboundarychar = rightboundarychar = NULL; /* checksumset = 0; */ } while (getrealline(infile, line, MAXLINE) > 0) { if (strncmp(line, "StartCharMetrics", 16) == 0) break; // end of this section /* if (passes == 0) */ if (passes != 0) continue; /* following are useful items normally found in AFM file */ if (strncmp(line, "ItalicAngle", 11) == 0) { s = line + 11; while (*s > ' ') s++; s++; /* sscanf(line, "ItalicAngle %lg", &italicangle); */ if (sscanf(s, "%lg", &italicangle) < 1) showline(line, 1); if (italicangle != 0.0) italicflag = 1; else italicflag = 0; if (traceflag) showline(line, 0); if (italicangle > 0.0) { sprintf(logline, "WARNING: ItalicAngle positive %lg (%s)\n", italicangle, fn_in); showline(logline, 0); } } else if (strncmp(line, "Weight", 6) == 0) { s = line + 6; while (*s > ' ') s++; s++; /* if (analyzeweight(line + 7, line) > 400) boldflag = 1; */ if (analyzeweight(s, line) > 400) boldflag = 1; if (traceflag) showline(line, 0); } else if (strncmp(line, "XHeight", 7) == 0) { s = line + 7; while (*s > ' ') s++; s++; /* sscanf(line, "XHeight %lg", &xheight); */ if (sscanf(s, "%lg", &xheight) < 1) showline(line, 1); if (traceflag) showline(line, 0); } else if (strncmp(line, "CapHeight", 9) == 0) { s = line + 9; while (*s > ' ') s++; s++; /* sscanf(line, "CapHeight %lg", &capheight); */ if (sscanf(s, "%lg", &capheight) < 1) showline(line, 1); if (traceflag) showline(line, 0); } else if (strncmp(line, "Ascender", 7) == 0) { s = line + 7; while (*s > ' ') s++; s++; /* sscanf(line, "Ascender %lg", &ascender); */ if (sscanf(s, "%lg", &ascender) < 1) showline(line, 1); if (traceflag) showline(line, 0); } else if (strncmp(line, "Descender", 7) == 0) { s = line + 7; while (*s > ' ') s++; s++; /* sscanf(line, "Descender %lg", &descender); */ /* negative quantity */ if (sscanf(s, "%lg", &descender) < 1) showline(line, 1); if (traceflag) showline(line, 0); } /* else if (strncmp(line, "IsFixedPitch", 12) == 0 || strncmp(line, "isFixedPitch", 12) == 0) { */ else if (_strnicmp(line, "IsFixedPitch", 12) == 0) { if (traceflag) showline(line, 0); if (strstr(line, "true") != NULL) isfixedpitch = 1; else if (strstr(line, "false") != NULL) isfixedpitch = 0; else { showline("WARNING: Don't understand pitch: ", 0); showline(line, 0); } } else if (strncmp(line, "FontName", 8) == 0) { s = line + 8; while (*s > ' ') s++; s++; /* strncpy(fontname, line + 9, FONTNAME_MAX); */ /* 92/01/26 */ strncpy(fontname, s, FONTNAME_MAX); /* 97/Feb/04 */ stripreturn(fontname); /* allow for TrueType font names ? */ if (verboseflag) showline(line, 0); else if (traceflag) showline(line, 0); } else if (strncmp(line, "FullName", 8) == 0) { s = line + 8; while (*s > ' ') s++; s++; /* strncpy(fullname, line + 9, FONTNAME_MAX); */ strncpy(fullname, s, FONTNAME_MAX); stripreturn(fullname); if (traceflag) showline(line, 0); } else if (strncmp(line, "FamilyName", 10) == 0) { s = line + 10; while (*s > ' ') s++; s++; /* strncpy(familyname, line + 11, FONTNAME_MAX); */ strncpy(familyname, s, FONTNAME_MAX); stripreturn(familyname); if (traceflag) showline(line, 0); } // else if ((s = strstr(line, "MacIntoshName")) != NULL || // (s = strstr(line, "MacintoshName")) != NULL) { else if (_strnicmp(line, "Comment MacintoshName", 21) == 0) { s = line + 21; while (*s > ' ') s++; s++; /* strncpy(macintoshname, s + 14, FONTNAME_MAX); */ strncpy(macintoshname, s, FONTNAME_MAX); stripreturn(macintoshname); if (traceflag) showline(line, 0); } else if (strncmp(line, "FontBBox", 8) == 0) { s = line; while (*s > ' ') s++; s++; /* sscanf(line, "FontBBox %lg %lg %lg %lg", */ if (sscanf(s, "%lg %lg %lg %lg", &fxll, &fyll, &fxur, &fyur) < 4) showline(line, 1); if (traceflag) showline(line, 0); } else if (strncmp(line, "EncodingScheme", 14) == 0) { s = line; while (*s > ' ') s++; s++; /* sscanf(line, "EncodingScheme %s", encodingscheme); */ /* strncpy(encodingscheme, line + 15, MAXENCODING); */ strncpy(encodingscheme, s, MAXENCODING); stripreturn(encodingscheme); /* allow for long names ? */ if (traceflag) showline(line, 0); } /* following are special things from TFM files made by AFMtoTFM */ // else if ((s = strstr(line, "Condensed")) != NULL || // (s = strstr(line, "Expanded")) != NULL) { else if ((_strnicmp(line, "Comment Condensed", 17) == 0) || (_strnicmp(line, "Comment Expanded", 16) == 0)) { s = line + 16; while (*s > ' ') s++; s++; /* sscanf(s, "Condensed %lg", &xscale); */ if (sscanf(s, "%lg", &xscale) < 1) showline(line, 1); if (traceflag) showline(line, 0); } // else if ((s = strstr(line, "CheckSum ")) != NULL) { else if (_strnicmp(line, "Comment CheckSum", 16) == 0) { s = line + 16; while (*s > ' ') s++; s++; /* sscanf(s, "CheckSum %08lX", &checksum); */ /* sscanf(s, "CheckSum %lx", &checksum); */ if (sscanf(s, "%lx", &checksum) < 1) showline(line, 1); if (traceflag) showline(line, 0); checksumset = 1; } // else if ((s = strstr(line, "Quad ")) != NULL) { else if (_strnicmp(line, "Comment Quad", 12) == 0) { s = line + 12; while (*s > ' ') s++; s++; /* sscanf(s, "Quad %lg", &em_quad); */ if (sscanf(s, "%lg", &em_quad) < 1) showline(line, 1); em_quad = em_quad * xscale; /* do later ? */ if (traceflag) showline(line, 0); } // else if ((s = strstr(line, "ExtraSpace ")) != NULL && else if (_strnicmp(line, "Comment ExtraSpace", 18) == 0 && ! extraflag) { s = line + 18; while (*s > ' ') s++; s++; /* sscanf(s, "ExtraSpace %lg", &extraspace); */ if (sscanf(s, "%lg", &extraspace) < 1) showline(line, 1); extraspace = extraspace * xscale; /* do later ? */ if (extraspace != 0.0) { /* 92/Aug/18 */ mathitflag = 0; /* can't be math italic then! */ } if (traceflag) showline(line, 0); extrafixed = 1; /* avoid overriding this later */ } // else if ((s = strstr(line, "Space ")) != NULL && else if (_strnicmp(line, "Comment Space", 13) == 0 && ! spacefixed) { s = line + 13; while (*s > ' ') s++; s++; /* sscanf(s, "Space %lg %lg %lg", */ // spacewidth = spacestretch = spaceshrink = 0; if (sscanf(s, "%lg %lg %lg", &spacewidth, &spacestretch, &spaceshrink) < 1) showline(line, 1); spacewidth = spacewidth * xscale; spacestretch = spacestretch * xscale; spaceshrink = spaceshrink * xscale; if (traceflag) showline(line, 0); spacefixed = 1; /* avoid overriding this later */ } // else if ((s = strstr(line, "FontID ")) != NULL) { else if (_strnicmp(line, "Comment FontID", 14) == 0) { s = line + 14; /* avoid using BitStream Comment bitsFontID line ! */ if (strstr(line, "bits") == NULL) { while (*s > ' ') s++; s++; /* strncpy(fontid, s + 7, MAXFONTID); */ strncpy(fontid, s, MAXFONTID); stripreturn(fontid); if (traceflag) showline(line, 0); } } // else if ((s = strstr(line, "CharacterCodingScheme ")) != NULL) { else if (_strnicmp(line, "Comment CharacterCodingScheme", 29) == 0) { s = line + 29; while (*s > ' ') s++; s++; /* strncpy(charcodingscheme, s + 22, MAXENCODING); */ strncpy(charcodingscheme, s, MAXENCODING); stripreturn(charcodingscheme); if (traceflag) showline(line, 0); } // else if ((s = strstr(line, "DesignSize ")) != NULL) { else if (_strnicmp(line, "Comment DesignSize", 18) == 0) { s = line + 18; while (*s > ' ') s++; s++; /* sscanf(s, "DesignSize %lg", &designsize); */ if (sscanf(s, "%lg", &designsize) < 1) showline(line, 1); if (traceflag) showline(line, 0); } /* following is new for boundary characters */ // else if ((s = strstr(line, "LeftBoundary ")) != NULL) { else if (_strnicmp(line, "Comment LeftBoundary", 20) == 0) { char str[128]; s = line + 20; while (*s > ' ') s++; s++; if (sscanf(s, "%s", &str) < 1) showline(line, 1); leftboundarychar = zstrdup(str); if (leftboundarychar == NULL) return -1; if (traceflag) showline(line, 0); } // else if ((s = strstr(line, "RightBoundary ")) != NULL) { else if (_strnicmp(line, "Comment RightBoundary", 21) == 0) { char str[128]; s = line + 21; while (*s > ' ') s++; s++; if (sscanf(s, "%s", &str) < 1) showline(line, 1); rightboundarychar = zstrdup(str); if (rightboundarychar == NULL) return -1; if (traceflag) showline(line, 0); } /* following are extra parameters for EC */ /* Comment xxxxxx */ else if (_strnicmp(line, "Comment CapHeight", 17) == 0) { s = line + 17; while (*s > ' ') s++; s++; if (sscanf(s, "%lg", &cap_height) < 1) showline(line, 1); /* ecflag++; */ } else if (_strnicmp(line, "Comment Ascender", 16) == 0) { s = line + 16; while (*s > ' ') s++; s++; if (sscanf(s, "%lg", &asc_height) < 1) showline(line, 1); /* ecflag++; */ } else if (_strnicmp(line, "Comment AccentedCapHeight", 25) == 0) { s = line + 25; while (*s > ' ') s++; s++; if (sscanf(s, "%lg", &acc_cap_height) < 1) showline(line, 1); ecflag++; } else if (_strnicmp(line, "Comment Descender", 17) == 0) { s = line + 17; while (*s > ' ') s++; s++; if (sscanf(s, "%lg", &desc_depth) < 1) showline(line, 1); /* positive */ /* ecflag++; */ } else if (_strnicmp(line, "Comment MaxHeight", 17) == 0) { s = line + 17; while (*s > ' ') s++; s++; if (sscanf(s, "%lg", &max_height) < 1) showline(line, 1); ecflag++; } else if (_strnicmp(line+8, "Comment MaxDepth", 16) == 0) { s = line + 16; while (*s > ' ') s++; s++; if (sscanf(s, "%lg", &max_depth) < 1) showline(line, 1); /* positive */ ecflag++; } else if (_strnicmp(line, "Comment FigureWidth", 19) == 0) { s = line + 19; while (*s > ' ') s++; s++; if (sscanf(s, "%lg", &digit_width) < 1) showline(line, 1); ecflag++; } /* capital letter vertical stem width */ else if (_strnicmp(line, "Comment StemV", 13) == 0) { s = line + 13; while (*s > ' ') s++; s++; if (sscanf(s, "%lg", &cap_stem) < 1) showline(line, 1); ecflag++; } else if (_strnicmp(line, "Comment BaseLineSkip", 20) == 0) { s = line + 20; while (*s > ' ') s++; s++; if (sscanf(s, "%lg", &baseline_skip) < 1) showline(line, 1); ecflag++; } /* following are extra parameters for mathsy */ // else if ((s = strstr(line, "Num ")) != NULL) { else if (_strnicmp(line, "Comment Num", 11) == 0) { s = line + 11; while (*s > ' ') s++; s++; if (sscanf(s, "%lg %lg %lg", &num1, &num2, &num3) < 3) showline(line, 1); mathsyflag++; if (traceflag) showline(line, 0); } // else if ((s = strstr(line, "Denom ")) != NULL) { else if (_strnicmp(line, "Comment Denom", 13) == 0) { s = line + 13; while (*s > ' ') s++; s++; if (sscanf(s, "%lg %lg", &denom1, &denom2) < 2) showline(line, 1); mathsyflag++; if (traceflag) showline(line, 0); } // else if ((s = strstr(line, "Sup ")) != NULL) { else if (_strnicmp(line, "Comment Sup", 11) == 0) { s = line + 11; while (*s > ' ') s++; s++; if (sscanf(s, "%lg %lg %lg", ¹, ², ³) < 3) showline(line, 1); mathsyflag++; if (traceflag) showline(line, 0); } // else if ((s = strstr(line, "Sub ")) != NULL) { else if (_strnicmp(line, "Comment Sub", 11) == 0) { s = line + 11; while (*s > ' ') s++; s++; if (sscanf(s, "%lg %lg", &sub1, &sub2) < 2) showline(line, 1); mathsyflag++; if (traceflag) showline(line, 0); } // else if ((s = strstr(line, "Supdrop ")) != NULL) { else if (_strnicmp(line, "Comment Supdrop", 15) == 0) { s = line + 15; while (*s > ' ') s++; s++; if (sscanf(s, "%lg", &supdrop) < 1) showline(line, 1); mathsyflag++; if (traceflag) showline(line, 0); } // else if ((s = strstr(line, "Subdrop ")) != NULL) { else if (_strnicmp(line, "Comment Subdrop", 15) == 0) { s = line + 15; while (*s > ' ') s++; s++; if (sscanf(s, "%lg", &subdrop) < 1) showline(line, 1); mathsyflag++; if (traceflag) showline(line, 0); } // else if ((s = strstr(line, "Delim ")) != NULL) { else if (_strnicmp(line, "Comment Delim", 13) == 0) { s = line + 13; while (*s > ' ') s++; s++; if (sscanf(s, "%lg %lg", &delim1, &delim2) < 2) showline(line, 1); mathsyflag++; if (traceflag) showline(line, 0); } // else if ((s = strstr(line, "Axisheight ")) != NULL) { else if (_strnicmp(line, "Comment Axisheight", 18) == 0) { s = line + 18; while (*s > ' ') s++; s++; if (sscanf(s, "%lg", &axisheight) < 1) showline(line, 1); mathsyflag++; if (traceflag) showline(line, 0); } /* following are for mathex extra paramaters */ // else if ((s = strstr(line, "DefaultRuleThickness ")) != NULL) { else if (_strnicmp(line, "Comment DefaultRuleThickness", 28) == 0) { s = line + 28; while (*s > ' ') s++; s++; if (sscanf(s, "%lg", &defaultrule) < 1) showline(line, 1); mathexflag++; if (traceflag) showline(line, 0); } // else if ((s = strstr(line, "BigOpSpacing ")) != NULL) { else if (_strnicmp(line, "Comment BigOpSpacing", 20) == 0) { s = line + 20; while (*s > ' ') s++; s++; if (sscanf(s, "%lg %lg %lg %lg %lg", &bigopspacing1, &bigopspacing2, &bigopspacing3, &bigopspacing4, &bigopspacing5) < 5) showline(line, 1); mathexflag++; if (traceflag) showline(line, 0); } /* following provide extra information for cmex10 */ // else if ((s = strstr(line, "Ascending ")) != NULL) { else if (_strnicmp(line, "Comment Ascending", 17) == 0) { s = line + 17; so = s; // s = s + 9; if (sscanf(s, "%d%n,", &last, &n) < 1) showline(line, 1); s = s + n + 1; if (last < 0 || last >= fontchrs) { sprintf(logline, "ERROR: Asc char code %d invalid\n", last); showline(logline, 1); last = 0; complain(); } while (sscanf(s, "%d%n,", &next, &n) > 0) { if (next < 0 || next >= fontchrs) { sprintf(logline, "ERROR: Asc char code %d invalid\n", next); showline(logline, 1); next = 0; complain(); } if (next == 0) { /* debugging */ showline("LINE: ", 1); showline(line, 0); sprintf(logline, "so: %s, s: %s ", so, s); showline(logline, 0); sprintf(logline, "LAST %d NEXT %d ", last, next); showline(logline, 0); } ascendpointer[last] = next; last = next; s = s + n + 1; } mathexflag++; if (traceflag) showline(line, 0); } // else if ((s = strstr(line, "Extensible ")) != NULL) { else if (_strnicmp(line, "Comment Extensible", 18) == 0) { s = line + 18; /* sprintf(logline, "EXTENSIBLE %d\n", sscanf(s, "Extensible %d top %d mid %d bot %d rep %d", &exten, &top, &mid, &bot, &rep)); showline(logline, 0); pause(); */ if (sscanf(s, /* "Extensible %d top %d mid %d bot %d rep %d", */ // "Extensible %u top %u mid %u bot %u rep %u", "%u top %u mid %u bot %u rep %u", &exten, &top, &mid, &bot, &rep) == 5) { if (exten >= (unsigned int) fontchrs) { sprintf (logline, "ERROR: Extensible code %u invalid\n", exten); showline(logline, 1); exten = 0; complain(); } /* assert (exten >= 0 && exten < fontchrs); */ extenpointer[exten] = ne; assert (ne >= 0 && ne < fontchrs); extentable[ne] = (((unsigned long) top) << 24) | (((unsigned long) mid) << 16) | (bot << 8) | rep; ne++; if (ne > MAXEXTEN) { sprintf(logline, "ERROR: Too many extensible chars (> %d)\n", MAXEXTEN); showline(logline, 1); complain(); ne--; } mathexflag++; if (traceflag) showline(line, 0); } /* if sscanf == 5 */ else showline(line, 1); } /* end of Extensible case */ if (abortflag > 0) return -1; } // end of while loop reading lines of AFM file return 0; /* successful */ } void removesemi (char *name) { /* get rid of trailing semi colon - if any */ char *s; s = name + strlen(name) - 1; if (*s == ';') *s = '\0'; } /* int aspect(int x) { if (x == 0) return 0; else if (x < 0) return - (int) ((double) (- x) * xscale + 0.5); else return (int) ((double) x * xscale + 0.5); } */ int kernzeros, kernignored, kerntruncated; /* read kerning pairs */ int readkerns(FILE *infile, struct kernpair __far *rawkerns) { /* int chara, charb; */ char chara[MAXCHARNAME], charb[MAXCHARNAME]; int nchara, ncharb; double kerndist; int nkern=0; kernzeros = 0; kernignored = 0; kerntruncated = 0; while (getrealline(infile, line, MAXLINE) > 0) { /* if (strncmp(line, "EndKernPairs", 12) == 0) break; */ if (strncmp(line, "EndKern", 7) == 0) break; if (strstr(line, "KPX") == NULL) continue; if (sscanf(line, "KPX %s %s %lg", chara, charb, &kerndist) < 3) { showline("Don't understand: ", 1); showline(line, 0); continue; } if (xscale != 1.0) kerndist = kerndist * xscale; if (ignorezeros && kerndist == 0.0) { kernzeros++; continue; /* ignore zero kern */ } if (kerndist < minkernsize && kerndist > - minkernsize) { kernignored++; continue; /* ignore small kern */ } if (killkern) { kerntruncated++; continue; /* or break; ? */ } /* sprintf(logline, "KPX %s %s %lg\n", chara, charb, kerndist); */ /* modified to use `visiblespace' if `space' not in encoding 98/Jun/30 */ nchara = clookup(chara, -1); /* width[nchara] != NOWIDTH ??? */ // if (nchara < 0) if (nchara < 0 || width[nchara] == NOWIDTH) // 2000/May/18 { if (strcmp(chara, "space") == 0) { nchara = clookup("visiblespace", -1); /* sprintf(logline, "%s => %d %s", chara, nchara, line); */ // if (nchara < 0) if (nchara < 0 || width[nchara] == NOWIDTH) // 2000/May/18 continue; } else continue; /* not in encoding */ } ncharb = clookup(charb, -1); // if (ncharb < 0) if (ncharb < 0 || width[ncharb] == NOWIDTH) // 2000/May/18 { if (strcmp(charb, "space") == 0) { ncharb = clookup("visiblespace", -1); /* sprintf(logline, "%s => %d %s", charb, ncharb, line); */ // if (ncharb < 0) if (ncharb < 0 || width[ncharb] == NOWIDTH) // 2000/May/18 continue; } else continue; /* not in encoding */ } /* rawkerns[nkern].a = nchara; */ /* rawkerns[nkern].b = ncharb; */ rawkerns[nkern].a = (unsigned char) nchara; rawkerns[nkern].b = (unsigned char) ncharb; /* rawkerns[nkern].kern = (float) kerndist; */ rawkerns[nkern].kern = mapdouble(kerndist); nkern++; if (nkern > kernligsize-1) { sprintf(logline, "Too many kern pairs (> %d)\n", kernligsize-1); showline(logline, 1); killkern++; } if (abortflag > 0) return 0; } // end of while loop reading kerns return nkern; } /* Check whether this kern already in raw kern table */ /* returns index into rawkerns if a pair already exists */ int kernindex (int nchara, int ncharb) { int k; struct kernpair __far *rawkerns = (struct kernpair __far *) kernbuffer; for (k = 0 ; k < nkern; k++) { if (rawkerns[k].a == nchara && rawkerns[k].b == ncharb) return k; } return -1; } /* Stuff for replicating kern pairs for accented characters 97/Oct/19 */ int matchreplicate (char *name) { int k; /* if (traceflag) sprintf(logline, "Find match for %s\n", name); */ for (k = 0; k < 128; k++) { if (*(kernrep[k][0]) == '\0') break; /* end of list */ if (*(kernrep[k][1]) != '*') continue; /* not start of char list */ if (_stricmp(kernrep[k][0], name) == 0) return k; /* match */ } return -1; } /* Replicate left character base => accented */ /* This adds little to size of TFM file if optimize turned on */ int replicateleft(int nkern, struct kernpair __far *rawkerns) { int nchara, ncharb; int k, kbase, m, caseflag, nk; int nkerninx=nkern; long kpx; /* int exitflag=0; */ char *s; if (showreplicate) { sprintf(logline, "REPLICATELEFTKERN %d\n", nkern); showline(logline, 0); } /* for (k = 0; k < nkern; k++) { */ for (k = 0; k < nkernzero; k++) { nchara = rawkerns[k].a; ncharb = rawkerns[k].b; kpx = rawkerns[k].kern; if (showreplicate) { sprintf(logline, "MASTER: KPX, %s %s %lg\n", encoding[nchara], encoding[ncharb], unmap(kpx)); showline(logline, 0); } /* deal with pairs where this is the first character */ s = encoding[nchara]; if (*s >= 'A' && *s <= 'Z') caseflag = 1; else caseflag = 0; kbase = matchreplicate(s); if (kbase >= 0) { for (m = kbase+1; m < 128; m++) { if (*(kernrep[m][1]) == '*') break; /* next base letter */ if (*(kernrep[m][0]) == '\0') break; /* end of table */ if (*(kernrep[m][1]) == 'L') continue; /* not on left */ /* sprintf(logline, "%s\t%c %c\n", kernrep[m][1], *(kernrep[m][1]), *(kernrep[m][1]+1)); */ if (*(kernrep[m][1]) != '\0') { if ((*(kernrep[m][1]+1) == 'l' && caseflag) || (*(kernrep[m][1]+1) == 'u' && ! caseflag)) continue; /* wrong case */ } if (*(kernrep[m][0]) != ' ') { *line = *(kernrep[kbase][0]); /* base letter */ strcpy(line+1, kernrep[m][0]); } else strcpy(line, kernrep[m][0]+1); /* don't use base */ if (! caseflag && (*line >= 'A' && *line <= 'Z')) *line = (char) (*line + 'a' - 'A'); else if (caseflag != 0 && (*line >= 'a' && *line <= 'z')) *line = (char) (*line + 'A' - 'a'); nchara = clookup(line, -1); if (nchara >= 0 && width[nchara] == NOWIDTH) { if (traceflag) { showline(line, 1); showline(" not in font\n", 1); } nchara = -1; /* pretend not in encoding */ } if (nchara >= 0) { nk = kernindex(nchara, ncharb); if (nk >= 0) { if (traceflag) { sprintf(logline, "Keeping: KPX %s %s %lg\n", encoding[nchara], encoding[ncharb], unmap(rawkerns[nk].kern)); showline(logline, 0); } keepingacc++; continue; /* don't override KPX from AFM ? */ } /* new special casing for accented chars based on "i" and "I" 98/Jun/30 */ if (_stricmp(kernrep[kbase][0], "i") == 0) { if (kpx < 0) { if (traceflag) { sprintf(logline, "Not adding: %s %s %lg\n", encoding[nchara], encoding[ncharb], unmap(kpx)); showline(logline, 0); } continue; } else { if (traceflag) { sprintf(logline, "Modifying KPX %s %s %lg\n", encoding[nchara], encoding[ncharb], unmap(kpx)); showline(logline, 0); } kpx += mapdouble(30); /* arbitrary additional kerning */ } } if (showreplicate) { sprintf(logline, "Adding: %s %s %lg\n", encoding[nchara], encoding[ncharb], unmap(kpx)); showline(logline, 0); } if (nkerninx >= kernligsize) { sprintf(logline, "ERROR: Too many added kern pairs %d\n", nkerninx); showline(logline, 1); return nkerninx; /* 98/Apr/4 */ } rawkerns[nkerninx].a = (unsigned char) nchara; /* new */ rawkerns[nkerninx].b = (unsigned char) ncharb; rawkerns[nkerninx].kern = kpx; nkerninx++; kpx = rawkerns[k].kern; /* restore in case changed */ } /* if (exitflag) break; */ } } /* nchara = rawkerns[k].a; */ /* restore ? */ } if (verboseflag) { if (nkerninx-nkern > 0) { sprintf(logline, "Added %d kern pairs (%s) (%d + %d = %d)\n", nkerninx-nkern, "left", nkern, nkerninx-nkern, nkerninx); showline(logline, 0); } } return nkerninx; } /* Replicate right character base => accented */ /* This can add a lot to size of TFM file */ int replicateright(int nkern, struct kernpair __far *rawkerns) { int nchara, ncharb; int k, kbase, m, caseflag, nk; int nkerninx=nkern; long kpx; /* int exitflag=0; */ char *s; if (showreplicate) { sprintf(logline, "REPLICATERIGHTKERN %d\n", nkern); showline(logline, 0); } /* for (k = 0; k < nkern; k++) { */ for (k = 0; k < nkernzero; k++) { nchara = rawkerns[k].a; ncharb = rawkerns[k].b; kpx = rawkerns[k].kern; if (showreplicate) { sprintf(logline, "MASTER: KPX, %s %s %lg\n", encoding[nchara], encoding[ncharb], unmap(kpx)); showline(logline, 0); } /* deal with pairs where this is the second character */ s = encoding[ncharb]; if (*s >= 'A' && *s <= 'Z') caseflag = 1; else caseflag = 0; kbase = matchreplicate(s); if (kbase >= 0) { for (m = kbase+1; m < 128; m++) { if (*(kernrep[m][1]) == '*') break; /* next base letter */ if (*(kernrep[m][0]) == '\0') break; /* end of table */ if (*(kernrep[m][1]) == 'R') continue; /* not on right */ /* sprintf(logline, "%s\t%c %c\n", kernrep[m][1], *(kernrep[m][1]), *(kernrep[m][1]+1)); */ if (*(kernrep[m][1]) != '\0') { if ((*(kernrep[m][1]+1) == 'l' && caseflag) || (*(kernrep[m][1]+1) == 'u' && ! caseflag)) continue; /* wrong case */ } if (*(kernrep[m][0]) != ' ') { *line = *(kernrep[kbase][0]); /* base letter */ strcpy(line+1, kernrep[m][0]); } else strcpy(line, kernrep[m][0]+1); /* don't use base */ if (! caseflag && (*line >= 'A' && *line <= 'Z')) *line = (char) (*line + 'a' - 'A'); else if (caseflag != 0 && (*line >= 'a' && *line <= 'z')) *line = (char) (*line + 'A' - 'a'); ncharb = clookup(line, -1); if (ncharb >= 0 && width[ncharb] == NOWIDTH) { if (traceflag) { showline(line, 1); showline(" not in font\n", 1); } ncharb = -1; /* pretend not in encoding */ } if (ncharb >= 0) { nk = kernindex(nchara, ncharb); if (nk >= 0) { if (traceflag) { sprintf(logline, "Keeping: KPX %s %s %lg\n", encoding[nchara], encoding[ncharb], unmap(rawkerns[nk].kern)); showline(logline, 0); } keepingacc++; continue; /* don't override KPX from AFM ? */ } /* new special casing for accented chars based on "i" and "I" 98/Jun/30 */ if (_stricmp(kernrep[kbase][0], "i") == 0) { if (kpx < 0) { if (traceflag) { sprintf(logline, "Not adding: %s %s %lg\n", encoding[nchara], encoding[ncharb], unmap(kpx)); showline(logline, 0); } continue; } else { if (traceflag) { sprintf(logline, "Modifying KPX %s %s %lg\n", encoding[nchara], encoding[ncharb], unmap(kpx)); showline(logline, 0); } kpx += mapdouble(30); /* arbitrary additional kerning */ } } if (showreplicate) { sprintf(logline, "Adding: %s %s %lg\n", encoding[nchara], encoding[ncharb], unmap(kpx)); showline(logline, 0); } if (nkerninx >= kernligsize) { sprintf(logline, "ERROR: Too many added kern pairs %d\n", nkerninx); showline(logline, 1); return nkerninx; /* 98/Apr/4 */ } rawkerns[nkerninx].a = (unsigned char) nchara; rawkerns[nkerninx].b = (unsigned char) ncharb; /* new */ rawkerns[nkerninx].kern = kpx; nkerninx++; kpx = rawkerns[k].kern; /* restore in case changed */ } /* if (exitflag) break; */ } } /* ncharb = rawkerns[k].b; */ /* restore ? */ } if (verboseflag) { if (nkerninx-nkern > 0) { sprintf(logline, "Added %d kern pairs (%s) (%d + %d = %d)\n", nkerninx-nkern, "right", nkern, nkerninx-nkern, nkerninx); showline(logline, 0); } } return nkerninx; } /* our own heap sort routine that deals with far addresses */ /* not a stable sort - does not preserve order of equals ... */ /* we could really use a stable sort in case of stupid AFMs */ int swapcount; /* debugging */ void swap(char __far *v, int nsize, int i , int j) { int c; char __far *vi; char __far *vj; int k; if (i == j) return; swapcount++; vi = v + i * nsize; vj = v + j * nsize; for (k = 0; k < nsize; k++) { c = *vi; *vi = *vj; *vj = (char) c; vi++; vj++; } } void fqsortsub(void __far *v, int nsize, int left, int right, int (*compare) (const void __far *, int, int, int)) { /* 92/Nov/24 */ int i, last; if (left >= right) return; swap(v, nsize, left, (left + right) /2 ); last = left; for (i = left+1; i <= right; i++) { /* if ((*compare)((void __far *) ((char __far *) v + i * nsize), (void __far *) ((char __far *) v + left * nsize)) < 0) swap(v, nsize, ++last, i); */ if ((*compare)(v, nsize, i, left) < 0) swap(v, nsize, ++last, i); } swap(v, nsize, left, last); fqsortsub(v, nsize, left, last-1, compare); fqsortsub(v, nsize, last+1, right, compare); } void fqsort(void __far *v, int nitems, int nsize, int (*compare) (const void __far *, int, int, int)) { swapcount=0; fqsortsub(v, nsize, 0, nitems-1, compare); if (traceflag) { /* debugging */ sprintf(logline, "Did %d swaps in presort of kern pairs\n", swapcount); showline(logline, 0); } } int comparekernpair(const void __far *arr, int nsize, int i, int j) { const struct kernpair __far *kern1; const struct kernpair __far *kern2; kern1 = (const struct kernpair __far *) ((char __far *) arr + i * nsize); kern2 = (const struct kernpair __far *) ((char __far *) arr + j * nsize); if (sortonname) { /* sort on character name */ /* 97/Oct/30 */ int ret; ret = strcmp(encoding[kern1->a], encoding[kern2->a]); if (ret != 0) return ret; else return strcmp(encoding[kern1->b], encoding[kern2->b]); } else { /* sort on character code */ if (kern1->a < kern2->a) return -1; else if (kern1->a > kern2->a) return 1; if (kern1->b < kern2->b) return -1; else if (kern1->b > kern2->b) return 1; /* sprintf(logline, "ERROR: Repeated kern pair %s %s (%d %d) %lg %lg\n", encoding[kern1->a], encoding[kern1->b], kern1->a, kern1->b, unmap(kern1->kern), unmap(kern2->kern)); */ return 0; /* same kern pair */ } } #ifdef DEBUGKERNS void dumpkernpairs (struct kernpair __far *arr, int n) { /* debugging */ int k; sprintf(logline, "StartKernPairs %d\n", n); showline(logline, 0); for (k = 0; k < n; k++) { sprintf(logline, "KPX %s %s %lg\n", encoding[arr[k].a], encoding[arr[k].b], unmap(arr[k].kern)); showline(logline, 0); } showline("EndKernPairs\n", 0); } #endif /* remove duplications from kern table */ int removeduplicates(struct kernpair __far *arr, int n) { int k, m=0; int repeated=0; while (m < n-1) { if ((arr[m].a != arr[m+1].a) || (arr[m].b != arr[m+1].b)) { m++; continue; } sprintf(logline, "WARNING: Repeated kern pair %s (%d) %s (%d) %lg %lg\n", encoding[arr[m].a], arr[m].a, encoding[arr[m].b], arr[m].b, unmap(arr[m].kern), unmap(arr[m+1].kern)); showline(logline, 0); repeated++; /* which one should we keep ? first or last ? */ /* for (k=m; k < n-1; k++) arr[k] = arr[k+1]; */ /* keep first */ for (k=m+1; k < n-1; k++) arr[k] = arr[k+1]; /* keep last */ n--; if (abortflag > 0) return 0; } if (repeated > 0) { if (verboseflag) { sprintf(logline,"%d repeated kern pair%s\n", repeated, (repeated == 1) ? "" : "s"); showline(logline, 0); } } return n; } /* compare kern programs for k < m */ /* returns zero if no match, returns number of matching steps if match */ int compareprogs (struct kernpair __far *arr, int k, int m, int n) { int i=k, j=m; if (debugflag) { sprintf(logline, "Comparing progs for %s (%d) and %s (%d)\n", encoding[arr[k].a], arr[k].a, encoding[arr[m].a], arr[m].a); showline(logline, 0); } while (i < n && j < n) { if (arr[i].a != arr[k].a) { /* stepped into next program */ if (arr[j].a != arr[m].a) return (j - m); /* check other */ else return 0; /* mismatch in length */ } if (arr[j].a != arr[m].a) { /* stepped into next program */ if (arr[i].a != arr[k].a) return (j - m); /* impossible */ else return 0; /* mismatch in length */ } if (arr[i].b != arr[j].b) return 0; /* mismatch in charb */ if (arr[i].kern != arr[j].kern) return 0; /* mismatch in amount */ i++, j++; } if (traceflag) showline("Dropped through\n", 0); /* debugging only */ if (i == n && j < n) { /* impossible */ if (arr[j].a != arr[m].a) return (j - m); else return 0; /* mismatch in length */ } else if (j == n && i < n) { if (arr[i].a != arr[k].a) return (j - m); else return 0; /* mismatch in length */ } showline("IMPOSSIBLE\n", 1); return 0; /* should never get here */ } /* Help remove redundant stuff from rawkerns */ /* search for earlier kern program equal to the one starting at m */ /* we only those for characters that don't also have lig programs */ /* compare against all, find the one with lowest char code */ /* not very efficient as a result */ /* could be done better by searching backward and building */ /* chain of equivalences ... */ int searchrepeats(struct kernpair __far *arr, int m, int n) { int k=0, nlen; int aold=-1; int klow=-1; int chrlow; int nlenlow=0; if (debugflag) { sprintf(logline, "Searching for repeats for %s (%d) at %d\n", encoding[arr[m].a], arr[m].a, m); showline(logline, 0); } /* don't bother if character has a ligature program ? */ /* if ((ligbegin[arr[m].a] != ligend[arr[m].a]) return 0; */ klow = m; chrlow = arr[m].a; while (k < n) { if (arr[k].a != aold) { /* start of new program ? */ if (k == m) { /* don't compare with self */ aold = arr[k].a; k++; continue; } nlen = compareprogs(arr, k, m, n); if (nlen > 0) { if (arr[k].a < chrlow) { klow = k; chrlow = arr[k].a; nlenlow = nlen; } } aold = arr[k].a; } k++; } if (chrlow == arr[m].a) return 0; /* if (traceflag || replicateleftflag || replicaterightflag) */ if (traceflag || showoptimize) { sprintf(logline, "Kern program for %s (%d) same as for %s (%d)\n", encoding[arr[m].a], arr[m].a, encoding[arr[klow].a], arr[klow].a); showline(logline, 0); } /* don't bother if equivalent character has a ligature program ? */ /* if ((ligbegin[arr[klow].a] != ligend[arr[klow].a]) return 0; */ kerneqv[arr[m].a] = arr[klow].a; /* chrlow indicate equivalence */ if (ligbegin[arr[m].a] != ligend[arr[m].a]) { if (ligbegin[arr[klow].a] != ligend[arr[klow].a]) { /* kerneqv[arr[m].a] = -1; */ /* saves checking later ? */ return 0; } } return nlenlow; } /* find equal kern programs */ int findrepeats(struct kernpair __far *arr, int n) { int m=0, len, total=0; int aold=-1; while (m < n) { if (arr[m].a != aold) { /* start of new program ? */ if (aold >= 0) { len = searchrepeats(arr, m, n); /* should not count those with ligature programs ... */ total += len; } aold = arr[m].a; } m++; } if (total > 0){ if (verboseflag) { sprintf(logline, "Saving %d ligkern steps by sharing (%d - %d = %d)\n", total, n, total, n-total); showline(logline, 0); } } return total; } void sortkernpairs(struct kernpair __far *rawkerns, int n) { if (n == 0) return; /* 98/Apr/5 */ if (verboseflag) { sprintf(logline, "Sorting %d kern pairs\n", n); showline(logline, 0); } fqsort(rawkerns, n, sizeof(struct kernpair), comparekernpair); } /* ligaturing on the left char in pair happens before kerning */ /* ligaturing on the right char in pair happens after kerning */ /* hence space quotedblleft/right not normally invoked */ /* instead space quoteleft/right do the job */ /* this is also why we need space comma (space quotedblbase not invoked) */ /* this also means you can't have different kerns for space ` and space `` ! */ char *boundarykern[][2] = { {"space", "quoteleft"}, /* used also for space `` */ {"space", "quoteright"}, /* used also for space '' */ {"space", "quotesinglbase"}, {"space", "quotereversed"}, /* rarely in encoding */ {"space", "comma"}, /* used for space ,, */ {"space", "quotedblleft"}, /* not normally invoked, instead space ` */ {"space", "quotedblright"}, /* not normally invoked, instead space ' */ {"space", "quotedblbase"}, /* not normally invoked, instead space , */ {"space", "quotedblreversed"}, /* rarely in encoding */ {"quotedblright", "space"}, {"quotedblleft", "space"}, {"quoteright", "space"}, /* used only for ' space, not '' space */ {"quoteleft", "space"}, /* used only for ` space, not `` space */ {"", ""} }; /* add kerns between space (boundary char) and quotes */ /* avoid repeated kerns which are a problem with nonstable sort */ int addboundarykerns (void) { int count = 0; int k, nk, nchara, ncharb; struct kernpair __far *rawkerns = (struct kernpair __far *) kernbuffer; if (! textfontflag) { showline("WARNING: Not adding boundary kerns to non-text font\n", 0); return nkern; /* 98/Apr/5 ??? */ } if (verboseflag) showline("Adding boundary kerns\n", 0); for (k = 0; k < 32; k++) { if (*(boundarykern[k][0]) == '\0') { /* boundaryspace = boundaryspace / 2; if (flag++) break; continue; */ break; /* end of list */ } nchara = clookup(boundarykern[k][0], -1); if (nchara >= 0 && width[nchara] == NOWIDTH) { if (traceflag) { sprintf(logline, "%s not in font\n", boundarykern[k][0]); showline(logline, 0); } nchara = -1; /* pretend not in encoding */ } if (nchara < 0) continue; ncharb = clookup(boundarykern[k][1], -1); if (ncharb >= 0 && width[ncharb] == NOWIDTH) { if (traceflag) { sprintf(logline, "%s not in font\n", boundarykern[k][1]); showline(logline, 0); } ncharb = -1; /* pretend not in encoding */ } if (ncharb < 0) continue; nk = kernindex(nchara, ncharb); if (nk >= 0) { /* don't overwrite */ if (traceflag) { sprintf(logline, "Keeping: KPX %s %s %lg\n", encoding[nchara], encoding[ncharb], unmap(rawkerns[nk].kern)); showline(logline, 0); } /* rawkerns[nk].kern = mapdouble(boundaryspace); */ /* overwrite */ keepingbou++; } else { /* add a new kern pair */ rawkerns[nkern].a = (unsigned char) nchara; rawkerns[nkern].b = (unsigned char) ncharb; rawkerns[nkern].kern = mapdouble(boundaryspace); nkern++; if (nkern > kernligsize-1) { sprintf(logline, "ERROR: Too many kern pairs (> %d)\n", kernligsize-1); showline(logline, 1); break; } count++; } if (traceflag) { sprintf(logline, "Adding: KPX %s %s %lg\n", encoding[nchara], encoding[ncharb], boundaryspace); showline(logline, 0); } } if (verboseflag) { sprintf(logline, "Added %d boundary kerns\n", count); /* debugging */ showline(logline, 0); } return nkern; } int checkborrow(int); /* c:\c\afmtotfm.c(3228) : fatal error C1001: internal compiler error */ /* (compiler file 'msc2.cpp', line 1011) */ void freeencoding (void) { int k; /* if (! encodingset) return; */ /* already freed ? */ for (k = 0; k < MAXCHRS; k++) { if (strcmp(encoding[k], "") == 0) continue; if (debugflag) { sprintf(logline, "free %d %s ", k, encoding[k]); showline(logline, 0); } free(encoding[k]); encoding[k] = ""; } encodingset = 0; } void spaceguess (char *s) { if (traceflag) showline(line, 0); if (sscanf(s, " WX %lg", &spacewidth) < 1) { showline("Don't understand: ", 1); showline(line, 1); } if (xscale != 1.0) spacewidth = spacewidth * xscale; /* if (verboseflag) { sprintf(logline, "\nSpace (from space char) %lg\n", spacewidth); showline(logline, 0); } */ // if (verboseflag) { // sprintf(logline, "p %d a %d s %d a %d\n", paulflag, alanflag, sebasflag, averageflag); // showline(logline, 0); // } if (paulflag) { spacestretch = spacewidth/2; /* 0.5 */ spaceshrink = spacewidth/6; /* 0.1666 */ /* extraspace = 500 - spacewidth; */ /* em/2 ??? */ } else if (alanflag) { spacestretch = spacewidth/3; /* 0.3333 */ spaceshrink = spacewidth/3; /* 0.3333 */ /* extraspace = 500 - spacewidth; */ /* em/2 ??? */ } else if (sebasflag) { spacestretch = spacewidth * 3 / 5; /* 0.6 */ spaceshrink = spacewidth * 6 / 25; /* 0.24 */ /* extraspace = 500 - spacewidth; */ /* em/2 ??? */ } else if (averageflag) { /* 95/August/3 */ spacestretch = (spacewidth * 6 / 10 + 160) / 2; spaceshrink = (spacewidth * 3 / 10 + 110) / 2; if (spacewidth < 500) extraspace = ((500 - spacewidth) + 110) / 2; else extraspace = 110; /* lower limit */ } /* prevent spacewidth - spaceshrink from becoming too small */ if (spacewidth - spaceshrink < 140) { /* 95/Oct/28 */ spacestretch = spacestretch + (140 - (spacewidth - spaceshrink)); spaceshrink = spacewidth - 140; if (spaceshrink < 0) spaceshrink = 0; } /* prevent spacewidth + spacestretch from becoming too large */ if (spacewidth + spacestretch > 500) { spacestretch = 500 - spacewidth; if (spacestretch < 0) spacestretch = 0; } // if (verboseflag) { // sprintf(logline, "Space %lg %lg %lg\n", // spacewidth, spacestretch, spaceshrink); // showline(logline, 0); // } spaceseen++; } #ifdef IGNORED int letrarename(char *s, int passes) { // 99/Sep/24 int i; for (i = 0; i < 16; i++) { if (strcmp(letranames[i][0], "") == 0) return 0; if (strcmp(s, letranames[i][0]) == 0) { strcpy(s, letranames[i][1]); if (verboseflag && passes == 0) printf("Replacing %s with %s\n", letranames[i][0], letranames[i][1]); return -1; } } return 0; } #endif /* returns non zero if some serious problem */ int readafmfile(FILE *infile, int passes) { int k, n, mat; /* char chara[MAXCHARNAME], charb[MAXCHARNAME]; */ char ligsuccess[MAXCHARNAME], ligcombine[MAXCHARNAME]; int nchara, ncharb, nlast; int ochrs; int charkerns=0; /* to keep compiler happy */ /* double kerndist, italiccorrect; */ double italiccorrect; long kerndist; double twidth, txll, tyll, txur, tyur; char tencoding[CHARNAME_MAX]; /* for safety sake */ char *s; int last; struct kernpair __far *rawkerns; int kfirst; long newwidth; /* check on conflict */ int bad, flag; int skipchar; int keqv; /* 97/Oct/1 */ rawkerns = (struct kernpair __far *) kernbuffer; if (traceflag) { sprintf(logline, "Reading AFM file pass %d\n", passes); showline(logline, 0); } lnext = 0; knext = 0; ktotal = 0; bc = fontchrs; ec = 0; missingboxes = 0; fchrs = 0; duplicates=0; spaceseen = 0; if (passes == 0) { /* reset a bunch of flags the first time around */ mathitflag=0; /* non-zero => 1 fewer parameters */ mathsyflag=0; /* non-zero => 15 extra parameters */ mathexflag=0; /* non-zero => 6? extra parameters */ textfontflag=0; /* reset 98/Jun/30 */ suppressligs = suppressligsini; /* reset in case changed */ fxll=0.0, fyll=0.0, fxur=1000.0, fyur=1000.0; nchrs=0, nkern=0; ne = 0; if (! reencodeflag) /* free since will read from AFM */ freeencoding(); /* just in case left over */ if (traceflag) { sprintf(logline, "Resetting tables for %d chars\n", fontchrs); showline(logline, 0); } for (k = 0; k < fontchrs; k++) { width[k] = NOWIDTH; /* mark unused position */ ligbegin[k] = -1; ligend[k] = -1; kernbegin[k] = -1; kernend[k] = -1; /* ligkerndup[k] = 0; */ /* 92/Dec/11 */ kerneqv[k] = NOEQUIV; /* reset 97/Oct/1 */ } } if (passes == 0) { italicangle = 0.0; isfixedpitch = 0; } #ifdef DEBUGGING if (traceflag) showline("Starting to read afm file\n", 0); #endif /* StartFontMetrics */ if (tostartchar(infile, passes) != 0) /* get to StartCharMetrics */ return -1; /* some serious error */ if (passes == 0) { if (_stricmp(encodingscheme, "AdobeStandardEncoding") == 0 || _stricmp(encodingscheme, "StandardEncoding") == 0 || _stricmp(encodingscheme, "MicroSoft Windows ANSI 3.1") == 0 || _stricmp(encodingscheme, "MS Windows ANSI") == 0) textfontflag = 1; else { /* 98/Apr/5 */ if (vetonontext) { if (reencodeflag) { showline("WARNING: turning off reencoding for this non-text font\n", 0); sprintf(logline, " EncodingScheme %s\n", encodingscheme); showline(logline, 0); } reencodeflag=0; /* temporary for this AFM */ freeencoding(); textfontflag = 0; } else { if (reencodeflag) { showline("WARNING: treating as text font\n", 0); sprintf(logline, " EncodingScheme %s\n", encodingscheme); showline(logline, 0); } textfontflag = 1; /* ??? */ } } if (xscale != 1.0) { sprintf(logline, "NOTE: Imposing horizontal scaling by %lg\n", xscale); showline(logline, 0); } } ochrs = 0; if (sscanf(line, "StartCharMetrics %d", &ochrs) < 1) { /* no longer a problem since we don't rely on it */ /* sprintf(logline, "WARNING: Missing number: %s", line); */ } if (passes == 0) nchrs = 0; /* can't trust the above anyway 92/Oct/8 */ flag = 0; /* Now do all characters in CharMetrics Section */ while (getrealline(infile, line, MAXLINE) > 0) { if (strncmp(line, "Comment", 7) == 0) continue; /* 92/Oct/8 */ /* if (strstr(line, "EndCharMetrics") != NULL) break; */ /* if (strncmp(line, "EndCharMetrics", 14) == 0) break; */ if (strncmp(line, "EndChar", 7) == 0) break; if (sscanf(line, "C %d ;%n", &k, &n) < 1) { showline("Don't understand: ", 1); showline(line, 1); continue; } if (passes == 0) nchrs++; s = line + n; last = -1; /* 92/Nov/26 */ if (passes == 0) { /* if (strstr(line, "N space") != NULL) */ /* fixed 94/Oct/13 */ if (strstr(line, "N space ") != NULL) { /* pick up space width */ if (! spacefixed) { /* 92/March/17 */ if (! spaceseen) { /* sprintf(logline, "At byte %ld\n", ftell(infile)); */ spaceguess(s); /* separated 95/Oct/28 */ } } /* end of spacefixed == 0 */ } /* end of N space found */ } /* end of passes == 0 */ /* only care about encoded chars unless font is reencoded */ if ((k >= 0 && k < fontchrs) || reencodeflag) { mat = sscanf(s, " WX %lg ; N %s ; B %lg %lg %lg %lg ;%n", &twidth, tencoding, &txll, &tyll, &txur, &tyur, &n); if (mat < 6) { if (mat < 2 || mat > 2) { sprintf(logline, "Don't understand: %s\n", s); showline(logline, 1); continue; } else { if (passes == 0) { if (strcmp(tencoding, ";") == 0) { showline("WARNING: Missing Character Name: ", 0); showline(line, 1); sprintf(tencoding, "a%d", k); } else { showline("WARNING: Missing BoundingBox: ", 0); showline(line, 1); } /* sprintf(logline, "tencoding %s\n", tencoding); */ } missingboxes++; txll = 0.0; txur = twidth; /* tyll = descender; tyur = ascender; */ tyll = 0.0; if (k >= 'a' && k <= 'z') tyur = xheight; else tyur = capheight; } } /* Maybe only do this for A-Z a-z ? */ if (alignmentflag) { /* overshoot correction 97/Dec/21 */ double tyllold=tyll, tyurold=tyur; if (tyll < 0.0) { if (tyll > 0.0 - alignment) tyll = 0.0; if (tyll < descender) { if (tyll > descender - alignment) tyll = descender; } } if (tyur > xheight) { if (tyur < xheight + alignment) tyur = xheight; else if (tyur > capheight) { if (tyur < capheight + alignment) tyur = capheight; else if (tyur > ascender) { if (tyur < ascender + alignment) tyur = ascender; } } } if (traceflag && showovershoot) { sprintf(logline, "%s\t(%lg %lg) --> (%lg %lg)\n", tencoding, tyllold, tyurold, tyll, tyur); showline(logline, 0); } } /* Absorb italic correction into total widths */ /* Preserves character widths, but keep superscript and subscript aligned */ if (fullwidth) { if (txur + italicfuzz > twidth) twidth = txur + italicfuzz; } if (xscale != 1.0) { twidth = twidth * xscale; txll = txll * xscale; txur = txur * xscale; } removesemi(tencoding); s = s + n; if (sscanf (s, " I %lg", &italiccorrect) == 1) /* txur = twidth + italiccorrect; /* ??? */ txur = twidth + italiccorrect - italicfuzz; /* 93/Nov/9 */ kfirst = -1; /* 93/Jan/5 */ for (;;) { /* 92/Nov/26 */ if (last == MAXCHRS) break; if (reencodeflag) { /* if ((k = clookup(tencoding, k)) < 0) */ /* if ((k = clookup(tencoding, last)) < 0) { */ k = clookup(tencoding, last); /* also check width[k] != NOWIDTH) ? */ if (k < 0) { k = MAXCHRS; /* indicate failure */ break; /* pop out of this search loop */ } /* avoid aliases for hyphen here ... 97/May/29 */ /* but allow aliases for space here ... 98/Jul/12 */ if (strcmp(encoding[k], tencoding) != 0 && strcmp(tencoding, "space") != 0) { k = MAXCHRS; /* indicate failure */ break; /* pop out of this search loop */ } } if (kfirst < 0) kfirst = k; /* remember the first one */ if (k > ec) ec = k; if (k < bc) bc = k; assert(k >= 0 && k < fontchrs); if (! reencodeflag) { /* 94/July/18 */ if (strcmp(encoding[k], "") != 0) { /* 95/Feb/20 */ /* if (debugflag) sprintf(logline, "free %d %s ", k, encoding[k]);*/ free(encoding[k]); encoding[k] = ""; /* ? */ } encoding[k] = zstrdup(tencoding); if (encoding[k] == NULL) return -1; /* OUT OF MEMORY */ } if (twidth < 0.0 && passes == 0) { sprintf(logline, "\nWidth %lg in char %d?\n", twidth, k); showline(logline, 0); } /* assert(twidth >= 0.0); */ if (passes == 0 && width[k] != NOWIDTH) { /* 92/Sep/24 */ newwidth = mapdouble(twidth); bad = 0; /* It is bad if the widths don't match ! */ if (newwidth != width[k]) bad = 1; /* Serious problems if ligkern program on character with repeat encoding */ if ((k >= 'A' && k <= 'Z') || (k >= 'a' && k <= 'z')) bad = 1; if (bad) { sprintf(logline, "\n%s: Duplicate entry for char %d (%s) ", "ERROR", k, tencoding); showline(logline, 1); } else { // sprintf(logline, "%s (%d) # ", tencoding, k); sprintf(logline, "%s (%d) ", tencoding, k); showline(logline, 0); flag++; /* if ((flag % 6) == 0) showline("\n", 0); */ } if (newwidth != width[k]) { sprintf(logline, "\nERROR: character width mismatch %ld <> %ld ", twidth, unmap(width[k])); showline(logline, 1); } duplicates++; } /* width[k] = twidth; */ width[k] = mapdouble(twidth); /* xll[k] = (float) txll; yll[k] = (float) tyll; */ /* xur[k] = (float) txur; yur[k] = (float) tyur; */ xll[k] = mapdouble(txll); yll[k] = mapdouble(tyll); xur[k] = mapdouble(txur); yur[k] = mapdouble(tyur); last = k; if (! reencodeflag) break; /* no repetition */ } /* 92/Nov/26 */ /* if reencodeflag == 0 then kfirst will equal k above at this point */ k = kfirst; /* 93/Jan/5 */ /* if (verboseflag) */ /* moved here 93/Jan/5 */ if (traceflag) { /* moved here 93/Jan/5 */ char *s; if (k < 0) s = "-"; else if (k >= fontchrs) s = ":"; else s= "*"; showline(s, 0); } if (k < 0 || k == MAXCHRS) continue; /* ??? */ if (traceflag) { sprintf(logline, "%d ", k); /* debugging */ showline(logline, 0); } fchrs++; /* count if in encoding */ if (passes > 0) { /* only do after first pass */ /* s = s + n; */ if (ligbegin[k] >= 0 && ligbegin[k] != lnext) { sprintf(logline, "ERROR: Split lig program for char %s (%d)\n", encoding[k], k); /* unlikely ! */ showline(logline, 1); complain (); } /* assert(ligbegin[k] < 0 || ligbegin[k] == lnext); */ ligbegin[k] = lnext; /* ignore ligatures in AFM file if suppressligs is non-zero */ if (! suppressligs) { while (sscanf(s, " L %s %s ;%n", ligsuccess, ligcombine, &n) == 2) { removesemi(ligcombine); /* sprintf(logline, "Noted ligature %s for %d ", s, k); */ #ifdef DEBUGGING if (traceflag) { sprintf(logline, "Noted ligature %s for %d ", s, k); showline(logline, 0); } #endif s = s + n; nchara = clookup(ligsuccess, -1); /* sprintf(logline, "LIGSUCCESS %s %d ", ligsuccess, nchara); */ if (nchara < 0) continue; /* second char not found */ /* Should we complain here or just quietly ignore it ? */ if (width[nchara] == NOWIDTH) { sprintf(logline, "LIG %s NCHARA %s (%d) NO WIDTH\n", tencoding, ligsuccess, nchara); showline(logline, 0); continue; } ncharb = clookup(ligcombine, -1); /* sprintf(logline, "LIGCOMBINE %s %d ", ligcombine, ncharb); */ if (ncharb < 0) continue; /* ligature not found */ /* Should we complain here or just quietly ignore it ? */ if (width[ncharb] == NOWIDTH) { sprintf(logline, "LIG %s NCHARB %s (%d) NO WIDTH\n", tencoding, ligcombine, ncharb); showline(logline, 0); continue; } ligsucc[lnext] = (char) nchara; /* far space */ ligature[lnext] = (char) ncharb; /* far space */ #ifdef DEBUGGING if (traceflag) { sprintf(logline, "LIG: %s %s %s\n", tencoding, ligsuccess, ligcombine); showline(logline, 0); } #endif /* if (verboseflag) sprintf(logline, "Remainder %s\n", s); */ // printf("%s + %s => %s\n", tencoding, ligsuccess, ligcombine); // debugging lnext++; if (lnext >= MAXLIG) { /* 255 - MAXLIG ? NO */ sprintf(logline, "ERROR: Too many ligatures (> %d)\n", MAXLIG); showline(logline, 1); complain(); /* lnext = 254; break; */ /* exit(7); */ /* very unlikely ! */ checkexit(7); /* very unlikely ! */ return -1; } if (abortflag > 0) return -1; } /* end of while scanf ... */ } /* end of if suppreslig == 0 */ ligend[k] = lnext; /* possible problem with mismatch ? */ replicate(k); /* see if another character position */ /* is this now redundant ??? */ } /* end of if passes > 0 */ } /* end of if k >= 0 ... */ if (abortflag > 0) return -1; } /* end of while (getrealline(infile, line, MAXLINE) > 0) */ if (verboseflag) showline("\n", 0); if (flag > 0) { flag = flag / 2; showline("\n", 0); sprintf(logline, "WARNING: above %d char%s appear more than once\n", flag, (flag == 1) ? "" : "s"); showline(logline, 0); } /* '*' in encoding, '-' unencoded, '.' not in encoding, ':' above 127 */ /* if (verboseflag) showline("\n", 0); */ if (bc > ec) { if (passes > 0) { showline("ERROR: No chars in AFM are in specified encoding!\n", 1); complain(); return -1; } bc = ec; } /* if (ansiextend && bc > 18) bc = 18; */ /* 93/Dec/19 ??? */ if (ansiextend && bc > 16) bc = 16; /* 93/Dec/29 ??? */ /* if (ochrs != 0 && nchrs != ochrs) */ /* 92/Oct/8 */ if (pass == 0 && ochrs != 0 && nchrs != ochrs) { /* 92/Oct/8 */ sprintf(logline, "WARNING: Saw %d characters, expected %d (%s)\n", nchrs, ochrs, fn_in); showline(logline, 0); if (duplicates > 0) { sprintf(logline, "(There were %d repeat encodings)\n", duplicates/2); showline(logline, 0); } } /* now for kerning information ... */ /* sort first ? */ /* if (verboseflag) sprintf(logline, "Ended on: %s", line); */ /* forget the following, in case the fool forgot StartKernData ! */ /* while (getrealline(infile, line, MAXLINE) > 0) { if (strstr(line, "StartKernData") != NULL) break; } */ /* ditched 93/July/10 */ /* if (verboseflag) sprintf(logline, "Found: %s", line); */ while (getrealline(infile, line, MAXLINE) > 0) { if (strstr(line, "StartKernPairs") != NULL) break; } /* if (verboseflag) sprintf(logline, "Found: %s", line); */ nkernzero = 0; /* may not be any kern info */ if (strstr(line, "StartKernPairs") != NULL) { if (sscanf(line, "StartKernPairs %d", &nkernzero) < 1) { showline("Don't understand: ", 1); showline(line, 1); } } /* if (nkernzero >= (255 - lnext) && passes > 0) { sprintf(logline, "There may be too many kern pairs for old TFM format (%d >= %d)\n", nkernzero, 255-lnext); } */ if (traceflag) { sprintf(logline, "textfontflag %d\n", textfontflag); showline(logline, 0); } if (passes > 0) { nkern = readkerns(infile, rawkerns); /* 92/Oct/12 */ keepingacc=0; keepingbou=0; /* dumpkernpairs(rawkerns, nkern); */ nkernzero = nkern; /* override 97/Oct/1 */ /* add boundary char ligatures with 'space' character and quotes */ if (boundaryadd && textfontflag && ! isfixedpitch) { if (rightboundary < 0 && leftboundary < 0) { leftboundarychar = zstrdup("space"); rightboundarychar = zstrdup("space"); if (leftboundarychar == NULL || rightboundarychar == NULL) return -1; leftboundary = clookup(leftboundarychar, -1); rightboundary = clookup(rightboundarychar, -1); } if (rightboundary >= 0 || leftboundary >= 0) addboundarykerns() ; /* right place to do this ??? */ /* ??? 98/Jun/30 */ if (leftboundary < 0) { if (leftboundarychar != NULL) { free(leftboundarychar); leftboundarychar = NULL; } } if (rightboundary < 0) { if (rightboundarychar != NULL) { free(rightboundarychar); rightboundarychar = NULL; } } } nkernzero = nkern; /* remember how many real kern pairs */ /* Avoid producing accented versions of duplicate characters */ if (replicateleftflag || replicaterightflag) { /* 98/Apr/5 */ sortkernpairs(rawkerns, nkern); /* 92/Oct/12 */ nkern = removeduplicates(rawkerns, nkern); /* 97/Oct/1 */ } nkernzero = nkern; /* override 97/Oct/1 */ /* Now replicated kerns for accented characters based on base character */ if (replicateleftflag && textfontflag) nkern = replicateleft(nkern, rawkerns); /* 97/Oct/19 */ if (replicaterightflag && textfontflag) nkern = replicateright(nkern, rawkerns); /* 97/Oct/19 */ if (keepingacc) { sprintf(logline, "WARNING: AFM file already contains %d kern pair%s for %s characters\n", keepingacc, (keepingacc == 1) ? "" : "s", "accented"); showline(logline, 0); } if (keepingbou) { sprintf(logline, "WARNING: AFM file already contains %d kern pair%s for %s characters\n", keepingbou, (keepingbou == 1) ? "" : "s", "boundary"); showline(logline, 0); } nkernzero = nkern; /* override 97/Oct/1 */ if (presortflag) { sortkernpairs(rawkerns, nkern); /* 92/Oct/12 */ #ifdef DEBUGKERNS dumpkernpairs(rawkerns, nkern); #endif nkern = removeduplicates(rawkerns, nkern); /* 97/Oct/1 */ #ifdef DEBUGKERNS dumpkernpairs(rawkerns, nkern); #endif if (optimize) kernsave = findrepeats(rawkerns, nkern); /* 97/Oct/1 */ else kernsave=0; } /* nkernzero = nkern; */ /* ??? */ } killkern = 0; /* reset in case */ /* nkern here is the wrong number to base decision on ... */ /* if (nkern >= (255 - lnext) && passes > 0) { */ if (nkern-kernsave >= (255 - lnext) && passes > 0) { if (traceflag) { sprintf(logline, "WARNING: Too many kern pairs for old TFM format (%d >= 255 - %d ligatures)\n", /* nkern, 255-lnext); */ /* nkern, lnext); */ nkern-kernsave, lnext); showline(logline, 0); } } /* now process raw kerning data */ /* assuming grouped by first character */ nlast = -1; /* previous character code */ skipchar=0; charkerns=0; for (k = 0; k < nkern; k++) { if (passes == 0) continue; /* skip this stuff first time around */ nchara = rawkerns[k].a; ncharb = rawkerns[k].b; kerndist = rawkerns[k].kern; if (nchara != nlast) { /* start on new first letter */ skipchar = 0; /* NOTE: kern pairs MUST be grouped by first letter */ /* assert(kernbegin[nchara] < 0 || kernbegin[nchara] == knext); */ if (kernbegin[nchara] >= 0 && kernbegin[nchara] != knext) { sprintf(logline, "ERROR: Split kern program for char %s (%d)\n", encoding[nchara], nchara); showline(logline, 1); showline("ERROR: Kern pairs must be sorted on first char\n", 1); complain(); } kernbegin[nchara] = knext; kernend[nchara] = knext; /* in case it doesn't get filled in */ /* if (nlast >= 0) kernend[nlast] = knext; */ nlast = nchara; charkerns = 0; /* Is kern program the same as one earlier ? */ if ((keqv = kerneqv[nchara]) != NOEQUIV) { /* only do this is if neither character has lig program */ if (ligend[nchara] == ligbegin[nchara]){ if (ligend[keqv] == ligbegin[keqv]) { skipchar=1; /* continue; */ } /* if kern programs the same, but has a ligature program also 97/Oct/15 */ /* else if (verboseflag) */ else if (traceflag) { sprintf(logline, "SPECIAL LIG CASE %s (%d) %s (%d)\n", encoding[nchara], nchara, encoding[keqv], keqv); /* debugging */ showline(logline, 0); } } } } if (skipchar) continue; /* 97/Oct/1 */ charkerns++; if (charkerns < maxcharkern && ! killkern) { kernsucc[knext] = (char) ncharb; /* far space */ /* kern[knext] = (float) kerndist; */ /* float */ kern[knext] = kerndist; knext++; kernend[nchara] = knext; if (showkernflag) { sprintf(logline, "knext %d KPX %s %s %lg \n", knext, encoding[nchara], encoding[ncharb], unmap(kerndist)); showline(logline, 0); } /* if (knext >= MAXKERN) */ /* MAXKERN */ if (knext >= kernligsize) { sprintf(logline, "WARNING: Truncating all kern pairs after char %d\n", nchara); showline(logline, 0); /* sprintf(logline, "(ERROR: More than %d kern pairs)\n", MAXKERN); */ sprintf(logline, "(ERROR: More than %d kern pairs)\n", kernligsize); showline(logline, 1); complain(); kernend[nchara] = knext; /* needed ? */ killkern++; /* should not happen ! */ } if (backwardflag && knext >= 255 - lnext) { /* MAXKERN */ sprintf(logline, "WARNING: Truncating all kern pairs after char %d\n", nchara); showline(logline, 0); showline( "(old style TFM can contain only 256 ligs & kerns)\n", 1); complain(); kernend[nchara] = knext; /* needed ? */ killkern++; /* should not happen */ } } else if (charkerns == maxcharkern && ! killkern) { sprintf(logline, "Truncating kern pairs for char %d\n", nchara); showline(logline, 0); kernend[nchara] = knext; /* needed ? */ kerntruncated++; } else kerntruncated++; } /* have now read all kerning information - print out statistics */ if (verboseflag && passes > 0 && nkern > 0) { if (kernsave > 0) { sprintf(logline, "Used %d + %d = %d kerns - ", knext, kernsave, knext + kernsave); showline(logline, 0); } else { sprintf(logline, "Used %d kerns - ", knext); showline(logline, 0); } if (kernzeros > 0) { sprintf(logline, "ignored %d zero size kerns - ", kernzeros); showline(logline, 0); } if (kernignored > 0) { sprintf(logline, "ignored %d tiny kerns - ", kernignored); showline(logline, 0); } if (kerntruncated > 0) { sprintf(logline, "truncated %d extra kerns - ", kerntruncated); showline(logline, 0); } /* sprintf(logline, "(seen %d kerns)\n", nkern); */ /* sprintf(logline, "(out of %d kerns)\n", nkernzero); */ /* sprintf(logline, "(out of %d)\n", nkernzero); */ sprintf(logline, "(out of %d)\n", nkernzero+kernzeros+kernignored+kerntruncated); showline(logline, 0); } nkern = knext; /* if (nlast >= 0) kernend[nlast] = knext; */ /* we don't really need to read the rest of the AFM file */ #ifdef IGNORED while (getrealline(infile, line, MAXLINE) > 0) { if (strstr(line, "EndKernData") != NULL) break; } /* Now read up to composite characters */ while (getrealline(infile, line, MAXLINE) > 0) { if (strstr(line, "StartComposites") != NULL) break; } /* now read over composite characters */ while (getrealline(infile, line, MAXLINE) > 0) { if (strstr(line, "EndComposites") != NULL) break; } /* read to end of file */ while (getrealline(infile, line, MAXLINE) > 0) { if (strstr(line, "EndFontMetrics") != NULL) break; } #endif if (traceflag) { sprintf(logline, "XSCALE is %lg\n", xscale); /* DEBUGGING ONLY */ showline(logline, 0); } if (missingboxes) { showline( "WARNING: Missing BoundingBoxes => inaccurate height & depth\n", 0); } return 0; /* succesfully read */ } void listmissing (void) { int k, flag=0, ncol=0; for (k = 0; k < fontchrs; k++) { if (width[k] == NOWIDTH) { if (strcmp(encoding[k], "") != 0) flag++; } } if (flag == 0) return; /* none missing */ showline("\n", 0); flag = 0; for (k = 0; k < fontchrs; k++) { if (width[k] == NOWIDTH) { if (strcmp(encoding[k], "") != 0) { sprintf(logline, "%s ? ", encoding[k]); ncol += strlen(logline); if (ncol >= 78) { showline("\n", 0); ncol = strlen(logline); } showline(logline, 0); flag++; /* if ((flag % 6) == 0) showline("\n", 0); */ } } } showline("\n", 0); sprintf(logline, "WARNING: above %d char%s in encoding vector, but not in AFM file\n", flag, (flag == 1) ? "" : "s"); showline(logline, 0); showline("(or possibly repeated entries in encoding vector)\n", 0); } /* Try and add TeX standard `ligatures' */ int addligatures(char *ligatures[][3], int accented, int nligtype) { int count=0; /* debugging */ int k, m, nchara, ncharb; int kbase=-1; /* 95/Jan/22 */ int kold=-1; /* index of entry with base name */ char *ligbase="", *ligsuccess="", *ligcombine=""; char *oldbase=""; /* not accessed - debug only */ char composite[MAXCHARNAME]; /* for constructing composite */ /* if (suppressligs && ! allowligs) return; */ /* 93/May/29 */ /* no, if user explicitly asks for it, then do it ! */ /* for(m = tstart; m < tend; m++) { */ for(m = 0; m < 256; m++) { // printf("Considering %s + %s => %s\n", // ligatures[m][0], ligatures[m][1], ligatures[m][2]); if (strcmp(ligatures[m][0], "") == 0) { /* keep old ligbase ? */ if (strcmp(ligatures[m][1], "") == 0) break; /* termination */ if (kbase < 0) continue; /* base does not exist ! 95/Jan/22 */ if (kold < 0) { /* not an error, just means base was not found ? */ /* sprintf(logline, "Bad ligature table %d\n", m); */ } k = kold; } else { ligbase = ligatures[m][0]; /* base character */ /* if (strcmp(ligbase, "") == 0) break; */ /* termination */ k = clookup(ligbase, -1); // also check width != NOWIDTH ? kbase = k; /* rem whether base exist ! 95/Jan/22 */ /* kold = k; */ /* ??? */ } if (k < 0 || width[k] == NOWIDTH) { /* ? */ #ifdef SHOWTEXBASE if (traceflag) { sprintf(logline, "LIGBASE %s not in encoding\n", ligbase); showline(logline, 0); } #endif kbase = -1; /* if not already ! 95/Jan/22 */ // printf("LIGBASE %s not in encoding\n", ligbase); // debugging continue; /* ligbase not in encoding */ } /* is this a new base character ? */ if (k != kold) { if (kold != -1) { /* if so finish last one */ #ifdef SHOWTEXBASE if (traceflag) { sprintf(logline, "LIGBASE %s ends at %d\n", oldbase, lnext); showline(logline, 0); } #endif ligend[kold] = lnext; /* possible problem with mismatch ? */ /* DEBUGGING TAKE OUT TEST */ replicate(kold); /* see if another character position */ } /* if (ligbegin[k] != ligend[k] && ligend[k] != lnext) { */ if (ligbegin[k] != ligend[k]) { #ifdef SHOWTEXBASE if (traceflag) { sprintf(logline, "LIGBASE %s, LIGBEGIN %d, LIGEND %d LNEXT %d\n", ligbase, ligbegin[k], ligend[k], lnext); showline(logline, 0); } #endif continue; /* avoid split ligature prog */ } #ifdef SHOWTEXBASE if (traceflag) { sprintf(logline, "LIGBASE %s begins at %d\n", ligbase, lnext); showline(logline, 0); } #endif assert(ligbegin[k] == ligend[k]); ligbegin[k] = lnext; /* start program for char k */ ligend[k] = lnext; /* dummy end program for now */ kold = k; /* remember character code working on now */ oldbase = ligbase; } ligsuccess = ligatures[m][1]; nchara = clookup(ligsuccess, -1); if ((! allowdotlessi && strcmp(ligsuccess, "dotlessi") == 0) || // (allowdottedi && strcmp(ligsuccess, "i") == 0)) (! allowdottedi && strcmp(ligsuccess, "i") == 0)) { // fix 99/Oct/1 if (traceflag) { sprintf(logline, "Ignoring %s %s\n", ligbase, ligsuccess); showline(logline, 0); } continue; } if (nchara < 0 || width[nchara] == NOWIDTH) { #ifdef SHOWTEXBASE if (traceflag) { sprintf(logline, "LIGBASE %s SUCCESS %s not found\n", ligbase, ligsuccess); showline(logline, 0); } #endif continue; /* second char not found */ } ligcombine = ligatures[m][2]; if (accented) { /* special for accented characters */ strcpy(composite, ligsuccess); /* following needed if pseudo ligatures based on `dotlessi' instead of `i' */ if (strcmp(composite, "dotlessi") == 0) strcpy(composite, "i"); /* following needed if pseudo ligatures based on `degree' instead of `ring' */ /* if (strcmp(ligbase, "degree") == 0) strcpy(ligbase, "ring"); */ strcat(composite, ligbase); ligcombine = composite; } ncharb = clookup(ligcombine, -1); if (ncharb < 0 || width[ncharb] == NOWIDTH) { #ifdef SHOWTEXBASE if (traceflag) { sprintf(logline, "LIGBASE %s LIGAT %s not found\n", ligbase, ligcombine); showline(logline, 0); } #endif continue; /* ligature not found */ } #ifdef SHOWTEXBASE if (traceflag) { sprintf(logline, "LIGBASE %s SUCCESS %s LIGATURE %s LNEXT %d\n", ligbase, ligsuccess, ligcombine, lnext); showline(logline, 0); } #endif ligsucc[lnext] = (char) nchara; /* far space */ ligature[lnext] = (char) ncharb; /* far space */ // printf("Using %s + %s => %s\n", // ligbase, ligsuccess, ligcombine); // debugging lnext++; if (lnext >= MAXLIG) { /* 255 ? MAXLIG ? NO */ sprintf(logline, "ERROR: Too many ligatures (> %d)\n", MAXLIG); showline(logline, 1); complain(); /* exit(7); */ /* very unlikely ! */ checkexit(7); /* very unlikely ! */ return -1; } count++; /* debugging */ } /* is this the last ligature for this base character ? */ if (kold != -1) { #ifdef SHOWTEXBASE if (traceflag) { sprintf(logline, "LIGBASE %s ends at %d\n", oldbase, lnext); showline(logline, 0); } #endif ligend[kold] = lnext; /* possible problem with mismatch ? */ /* DEBUGGING TAKE OUT TEST */ replicate(kold); /* see if another character position */ } /* following is debugging stuff */ if (traceflag) { char *ligtype; switch (nligtype) { case 1: ligtype = "f"; break; case 2: ligtype = "dash and quote"; break; case 3: ligtype = "guillemet"; break; case 4: ligtype = "accent"; break; case 5: ligtype = "accent"; break; default: ligtype = "unknown"; break; } if (accented) { sprintf(logline, "%d accent pseudo ligatures added\n", count); showline(logline, 0); } else { sprintf(logline, "%d %s ligatures added\n", count, ligtype); showline(logline, 0); } } return 0; } int expandbuffer (void) { /* expand TFM file output buffer */ unsigned char __far *newbuffer; unsigned int newsize; newsize = buffersize + INCMEMORY; newbuffer = (unsigned char __far *) _frealloc (buffer, newsize); if (newbuffer == NULL) { sprintf(logline, "ERROR: Unable to allocate memory for %s\n", "TFM file"); showline(logline, 1); checkexit(1); return -1; } else { buffer = newbuffer; buffersize = newsize; if (traceflag) { /* debugging */ sprintf(logline, "Expanded TFM file buffer to %u\n", newsize); showline(logline, 0); } return newsize; } } /* *** *** *** goodies for writing into the output TFM buffer *** *** *** */ int writeint(int word) { /* write 16-bit count into buffer */ int ret; if (bufferinx + 1 >= buffersize) { ret = expandbuffer(); if (ret < 0) return -1; } buffer[bufferinx++] = (unsigned char) ((word >> 8) & 255); buffer[bufferinx++] = (unsigned char) (word & 255); /* if (bufferinx >= MAXBUFFER) overflow(); */ return 0; } int writelong(long word) { /* write 32-bit number into buffer */ int ret; if (bufferinx + 3 >= buffersize) { ret = expandbuffer(); if (ret < 0) return -1; } buffer[bufferinx++] = (unsigned char) ((word >> 24) & 255); buffer[bufferinx++] = (unsigned char) ((word >> 16) & 255); buffer[bufferinx++] = (unsigned char) ((word >> 8) & 255); buffer[bufferinx++] = (unsigned char) (word & 255); /* if (bufferinx >= MAXBUFFER) overflow(); */ return 0; } /* writefour(skipbyte, nextchar, opbyte, remainder); */ int writefour(int a, int b, int c, int d) { int ret; if (bufferinx + 3 >= buffersize) { ret = expandbuffer(); if (ret < 0) return -1; } buffer[bufferinx++] = (unsigned char) a; buffer[bufferinx++] = (unsigned char) b; buffer[bufferinx++] = (unsigned char) c; buffer[bufferinx++] = (unsigned char) d; /* if (bufferinx >= MAXBUFFER) overflow(); */ return 0; } /* special lig_kern program step that points to start of actual program */ int writepointer(int place, int ligkerin) { int ret; if (place + 3 >= buffersize) { ret = expandbuffer(); /* should not ! */ if (ret < 0) return -1; } buffer[place++] = 128 + 64; /* > 128 */ /* skip byte */ buffer[place++] = 0; /* next byte */ buffer[place++] = (char) ((ligkerin >> 8) & 255); /* op byte */ buffer[place++] = (char) (ligkerin & 255); /* remainder */ if (ligkerin > maxligkern) maxligkern = ligkerin; /* debugging */ /* if (verboseflag) sprintf(logline, "ligkerin %d ", ligkerin); */ return 0; } void markend(void) { /* mark end of lig/kern program */ if (bufferinx > 3) buffer[bufferinx - 4] = (unsigned char) (buffer[bufferinx - 4] | STOPBIT); /* 92/Nov/24 */ } /* write pascal style string */ /* starts with byte count - pad with zeros */ /* null delimited string, how many bytes, how many bytes total (not count) */ int writepascal(char *s, int n, int m) { int k; int ret; if (bufferinx + m + 1 >= buffersize) { ret = expandbuffer(); /* 98/Aug/26 */ if (ret < 0) return -1; } if (n > m) n = m; /* sanity check */ buffer[bufferinx++] = (unsigned char) n; /* byte count */ for (k=0; k < n; k++) buffer[bufferinx++] = (unsigned char) *s++; for (k=n; k < m; k++) buffer[bufferinx++] = '\0'; return 0; } int longalign(void) { /* buffer must be multiple of four long */ int ret; if (bufferinx + 3 >= buffersize) { ret = expandbuffer(); /* should not ! */ if (ret < 0) return -1; } if ((bufferinx % 4) != 0) { sprintf(logline, "Header not word aligned %d\n", bufferinx); showline(logline, 0); } while ((bufferinx % 4) != 0) bufferinx++; return 0; } int writetfm(FILE *outfile) { int k; /* unsigned char *bufptr = buffer; */ /* unsigned char __far *bufptr = buffer; */ unsigned char __far *bufptr = buffer; #ifdef DEBUGGING int a, b, c, d; unsigned int e, f; long g; double h; #endif #ifdef DEBUGGING for (k = 0; k < lf; k++) { a = *bufptr++; b = *bufptr++; c = *bufptr++; d = *bufptr++; if (traceflag) { pause(); e = (a << 8) | b ; f = (c << 8) | d; g = ((long) e) << 16 | (long) f; h = 1000.0 * ((double) g) / 1048576.0; sprintf(logline, "%d\t%d\t%d\t%d => \t%u\t%u => \t%ld \t(%lg)\n", a, b, c, d, e, f, g, h); showline(logline, 0); } putc(a, outfile); putc(b, outfile); putc(c, outfile); putc(d, outfile); } #else /* fwrite(bufptr, 4, lf, outfile); */ /* bufptr is _far ... */ for (k = 0; k < lf * 4; k++) putc(*bufptr++, outfile); #endif return 0; } /* *** *** *** goodies for writing into the output TFM buffer *** *** *** */ /* make up packed char_info_word */ /* k only needed for debug output */ unsigned long packcharinfo(int width, int height, int depth, int italic, int tag, int remainder, int k) { unsigned long res; assert (width >= 0); assert (height >= 0); assert (depth >= 0); assert (italic >= 0); assert (width < 256); assert (height < 16); assert (depth < 16); assert (italic < 64); if (remainder < 0 || remainder > 255) { sprintf(logline, "ERROR: Remainder %d out of range in char %d\n", remainder, k); showline(logline, 1); /* sprintf(logline, "Width %d Height %d Depth %d Italic %d Tag %d\n", width, height, depth, italic, tag); */ /* debugging */ /* sprintf(logline, "ligkerninx %d nextslot %d\n", ligkerninx, nextslot);*/ complain(); remainder = remainder & 255; /* just to be safe */ } res = ((long) width << 24) | ((long) height << 20) | ((long) depth << 16) | ((long) italic << 10) | (tag << 8) | remainder; #ifdef DEBUGGING if (traceflag) { sprintf(logline, "%d %d %d %d %d %d => %lo\n", width, height, depth, italic, tag, remainder, res); showline(logline, 0); pause(); } #endif return res; } /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */ #ifdef DEBUGGING /* void showtable(double table[], int n) { */ void showtable(long table[], int n) { int k; if (n == 0) return; showline("\n", 0); #ifdef DEBUGGING pause(); #endif for (k = 0; k < n; k++) { if ((k % 6) == 0) showline("\n", 0); /* sprintf(logline, "%d w: %lg ", k, table[k]); */ sprintf(logline, "%d w: %lg ", k, unmap(table[k])); showline(logline, 0); } } void showwidths(void) { showtable(widthtable, nw); } void showheights(void) { showtable(heighttable, nh); } void showdepths(void) { showtable(depthtable, nd); } void showitalics(void) { showtable(italictable, ni); } void showkerns(void) { showtable(kerntable, nk); } #endif /* int comparedouble(const void *dbla, const void *dblb) { const double *a, *b; a = (const double *) dbla; b = (const double *) dblb; if (*a < *b) return -1; else if (*a > *b) return 1; else return 0; } */ int comparelong(const void *dbla, const void *dblb) { const long *a, *b; a = (const long *) dbla; b = (const long *) dblb; if (*a < *b) return -1; else if (*a > *b) return 1; else return 0; } /* for width and kern can expect exact match - since tables big enough */ /* int mapwidth(double charwidth) { */ /* get width index from width */ int mapwidth(long charwidth) { /* get width index from width */ int k; /* double *ptr; */ long *ptr; /* assert(charwidth >= 0.0 && charwidth < 4096.0); */ /* assert(charwidth >= -4096.0 && charwidth < 4096.0); */ /* if (charwidth == 0.0) return 0; */ /* ptr = bsearch(&charwidth, widthtable, (unsigned int) nw, sizeof(double), comparedouble); */ ptr = bsearch(&charwidth, widthtable + 1, (unsigned int) (nw - 1), /* sizeof(double), comparedouble); */ sizeof(long), comparelong); if (ptr == NULL) { sprintf(logline, "ERROR: Can't find %s %lg in table\n", "width", charwidth); showline(logline, 1); #ifdef DEBUGGING if (verboseflag) showwidths(); /* may want this ? */ #endif /* checkexit(7); */ ptr = widthtable; } k = (int) (ptr - widthtable); #ifdef DEBUGGING /* if (charwidth == 0.0 && verboseflag) { */ if (charwidth == 0 && verboseflag) {